LCOV - code coverage report
Current view: top level - acceptance - GerritServer.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 284 295 96.3 %
Date: 2022-11-19 15:00:39 Functions: 41 44 93.2 %

          Line data    Source code
       1             : // Copyright (C) 2013 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.acceptance;
      16             : 
      17             : import static com.google.common.base.Preconditions.checkArgument;
      18             : import static com.google.common.base.Preconditions.checkState;
      19             : import static java.lang.annotation.RetentionPolicy.RUNTIME;
      20             : import static java.util.Objects.requireNonNull;
      21             : 
      22             : import com.google.auto.value.AutoValue;
      23             : import com.google.common.base.MoreObjects;
      24             : import com.google.common.base.Strings;
      25             : import com.google.common.base.Ticker;
      26             : import com.google.common.collect.ImmutableList;
      27             : import com.google.gerrit.acceptance.AbstractDaemonTest.TestTicker;
      28             : import com.google.gerrit.acceptance.FakeGroupAuditService.FakeGroupAuditServiceModule;
      29             : import com.google.gerrit.acceptance.ReindexGroupsAtStartup.ReindexGroupsAtStartupModule;
      30             : import com.google.gerrit.acceptance.ReindexProjectsAtStartup.ReindexProjectsAtStartupModule;
      31             : import com.google.gerrit.acceptance.config.ConfigAnnotationParser;
      32             : import com.google.gerrit.acceptance.config.GerritConfig;
      33             : import com.google.gerrit.acceptance.config.GerritConfigs;
      34             : import com.google.gerrit.acceptance.config.GlobalPluginConfig;
      35             : import com.google.gerrit.acceptance.config.GlobalPluginConfigs;
      36             : import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
      37             : import com.google.gerrit.acceptance.testsuite.account.AccountOperationsImpl;
      38             : import com.google.gerrit.acceptance.testsuite.change.ChangeOperations;
      39             : import com.google.gerrit.acceptance.testsuite.change.ChangeOperationsImpl;
      40             : import com.google.gerrit.acceptance.testsuite.change.PerCommentOperationsImpl;
      41             : import com.google.gerrit.acceptance.testsuite.change.PerDraftCommentOperationsImpl;
      42             : import com.google.gerrit.acceptance.testsuite.change.PerPatchsetOperationsImpl;
      43             : import com.google.gerrit.acceptance.testsuite.change.PerRobotCommentOperationsImpl;
      44             : import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
      45             : import com.google.gerrit.acceptance.testsuite.group.GroupOperationsImpl;
      46             : import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
      47             : import com.google.gerrit.acceptance.testsuite.project.ProjectOperationsImpl;
      48             : import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
      49             : import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperationsImpl;
      50             : import com.google.gerrit.common.Nullable;
      51             : import com.google.gerrit.extensions.annotations.Exports;
      52             : import com.google.gerrit.extensions.config.FactoryModule;
      53             : import com.google.gerrit.index.IndexType;
      54             : import com.google.gerrit.index.testing.FakeIndexModule;
      55             : import com.google.gerrit.lucene.LuceneIndexModule;
      56             : import com.google.gerrit.pgm.Daemon;
      57             : import com.google.gerrit.pgm.Init;
      58             : import com.google.gerrit.server.config.GerritRuntime;
      59             : import com.google.gerrit.server.config.GerritServerConfig;
      60             : import com.google.gerrit.server.config.SitePath;
      61             : import com.google.gerrit.server.experiments.ConfigExperimentFeatures.ConfigExperimentFeaturesModule;
      62             : import com.google.gerrit.server.git.receive.AsyncReceiveCommits.AsyncReceiveCommitsModule;
      63             : import com.google.gerrit.server.git.validators.CommitValidationListener;
      64             : import com.google.gerrit.server.index.options.AutoFlush;
      65             : import com.google.gerrit.server.schema.JdbcAccountPatchReviewStore;
      66             : import com.google.gerrit.server.ssh.NoSshModule;
      67             : import com.google.gerrit.server.util.ReplicaUtil;
      68             : import com.google.gerrit.server.util.SocketUtil;
      69             : import com.google.gerrit.server.util.SystemLog;
      70             : import com.google.gerrit.testing.FakeEmailSender.FakeEmailSenderModule;
      71             : import com.google.gerrit.testing.InMemoryRepositoryManager;
      72             : import com.google.gerrit.testing.SshMode;
      73             : import com.google.gerrit.testing.TestLoggingActivator;
      74             : import com.google.inject.AbstractModule;
      75             : import com.google.inject.BindingAnnotation;
      76             : import com.google.inject.Injector;
      77             : import com.google.inject.Key;
      78             : import com.google.inject.Module;
      79             : import com.google.inject.Provides;
      80             : import com.google.inject.Singleton;
      81             : import com.google.inject.multibindings.OptionalBinder;
      82             : import java.lang.annotation.Annotation;
      83             : import java.lang.annotation.Retention;
      84             : import java.lang.reflect.Field;
      85             : import java.net.InetAddress;
      86             : import java.net.InetSocketAddress;
      87             : import java.net.URI;
      88             : import java.nio.file.Path;
      89             : import java.util.Arrays;
      90             : import java.util.HashMap;
      91             : import java.util.Locale;
      92             : import java.util.Map;
      93             : import java.util.concurrent.BrokenBarrierException;
      94             : import java.util.concurrent.CyclicBarrier;
      95             : import java.util.concurrent.ExecutorService;
      96             : import java.util.concurrent.Executors;
      97             : import java.util.concurrent.Future;
      98             : import java.util.concurrent.TimeUnit;
      99             : import java.util.stream.Stream;
     100             : import org.eclipse.jgit.lib.Config;
     101             : import org.eclipse.jgit.lib.RepositoryCache;
     102             : import org.eclipse.jgit.util.FS;
     103             : import org.junit.rules.TemporaryFolder;
     104             : 
     105             : public class GerritServer implements AutoCloseable {
     106             :   public static class StartupException extends Exception {
     107             :     private static final long serialVersionUID = 1L;
     108             : 
     109             :     StartupException(String msg, Throwable cause) {
     110           1 :       super(msg, cause);
     111           1 :     }
     112             :   }
     113             : 
     114             :   /** Marker on {@link InetSocketAddress} for test SSH server. */
     115             :   @Retention(RUNTIME)
     116             :   @BindingAnnotation
     117             :   public @interface TestSshServerAddress {}
     118             : 
     119             :   @AutoValue
     120         138 :   public abstract static class Description {
     121             :     public static Description forTestClass(
     122             :         org.junit.runner.Description testDesc, String configName) {
     123         132 :       VerifyNoPiiInChangeNotes verifyNoPiiInChangeNotes =
     124         132 :           get(VerifyNoPiiInChangeNotes.class, testDesc.getTestClass());
     125         132 :       return new AutoValue_GerritServer_Description(
     126             :           testDesc,
     127             :           configName,
     128         132 :           !has(UseLocalDisk.class, testDesc.getTestClass()) && !forceLocalDisk(),
     129         132 :           !has(NoHttpd.class, testDesc.getTestClass()),
     130         132 :           has(Sandboxed.class, testDesc.getTestClass()),
     131         132 :           has(SkipProjectClone.class, testDesc.getTestClass()),
     132         132 :           has(UseSsh.class, testDesc.getTestClass()),
     133         132 :           verifyNoPiiInChangeNotes != null && verifyNoPiiInChangeNotes.value(),
     134             :           false, // @UseSystemTime is only valid on methods.
     135         132 :           get(UseClockStep.class, testDesc.getTestClass()),
     136         132 :           get(UseTimezone.class, testDesc.getTestClass()),
     137             :           null, // @GerritConfig is only valid on methods.
     138             :           null, // @GerritConfigs is only valid on methods.
     139             :           null, // @GlobalPluginConfig is only valid on methods.
     140             :           null); // @GlobalPluginConfigs is only valid on methods.
     141             :     }
     142             : 
     143             :     public static Description forTestMethod(
     144             :         org.junit.runner.Description testDesc, String configName) {
     145         138 :       UseClockStep useClockStep = testDesc.getAnnotation(UseClockStep.class);
     146         138 :       if (testDesc.getAnnotation(UseSystemTime.class) == null && useClockStep == null) {
     147             :         // Only read the UseClockStep from the class if on method level neither @UseSystemTime nor
     148             :         // @UseClockStep have been used.
     149             :         // If the method defines @UseSystemTime or @UseClockStep it should overwrite @UseClockStep
     150             :         // on class level.
     151         138 :         useClockStep = get(UseClockStep.class, testDesc.getTestClass());
     152             :       }
     153         138 :       VerifyNoPiiInChangeNotes verifyNoPiiInChangeNotes =
     154         138 :           testDesc.getAnnotation(VerifyNoPiiInChangeNotes.class);
     155         138 :       if (verifyNoPiiInChangeNotes == null) {
     156         138 :         verifyNoPiiInChangeNotes = get(VerifyNoPiiInChangeNotes.class, testDesc.getTestClass());
     157             :       }
     158             : 
     159         138 :       return new AutoValue_GerritServer_Description(
     160             :           testDesc,
     161             :           configName,
     162         138 :           (testDesc.getAnnotation(UseLocalDisk.class) == null
     163         138 :                   && !has(UseLocalDisk.class, testDesc.getTestClass()))
     164         138 :               && !forceLocalDisk(),
     165         138 :           testDesc.getAnnotation(NoHttpd.class) == null
     166         138 :               && !has(NoHttpd.class, testDesc.getTestClass()),
     167         138 :           testDesc.getAnnotation(Sandboxed.class) != null
     168         138 :               || has(Sandboxed.class, testDesc.getTestClass()),
     169         138 :           testDesc.getAnnotation(SkipProjectClone.class) != null
     170         138 :               || has(SkipProjectClone.class, testDesc.getTestClass()),
     171         138 :           testDesc.getAnnotation(UseSsh.class) != null
     172         138 :               || has(UseSsh.class, testDesc.getTestClass()),
     173         138 :           verifyNoPiiInChangeNotes != null && verifyNoPiiInChangeNotes.value(),
     174         138 :           testDesc.getAnnotation(UseSystemTime.class) != null,
     175             :           useClockStep,
     176         138 :           testDesc.getAnnotation(UseTimezone.class) != null
     177           1 :               ? testDesc.getAnnotation(UseTimezone.class)
     178         138 :               : get(UseTimezone.class, testDesc.getTestClass()),
     179         138 :           testDesc.getAnnotation(GerritConfig.class),
     180         138 :           testDesc.getAnnotation(GerritConfigs.class),
     181         138 :           testDesc.getAnnotation(GlobalPluginConfig.class),
     182         138 :           testDesc.getAnnotation(GlobalPluginConfigs.class));
     183             :     }
     184             : 
     185             :     private static boolean has(Class<? extends Annotation> annotation, Class<?> clazz) {
     186         138 :       for (; clazz != null; clazz = clazz.getSuperclass()) {
     187         138 :         if (clazz.getAnnotation(annotation) != null) {
     188          64 :           return true;
     189             :         }
     190             :       }
     191         138 :       return false;
     192             :     }
     193             : 
     194             :     @Nullable
     195             :     private static <T extends Annotation> T get(Class<T> annotation, Class<?> clazz) {
     196         138 :       for (; clazz != null; clazz = clazz.getSuperclass()) {
     197         138 :         if (clazz.getAnnotation(annotation) != null) {
     198          19 :           return clazz.getAnnotation(annotation);
     199             :         }
     200             :       }
     201         138 :       return null;
     202             :     }
     203             : 
     204             :     abstract org.junit.runner.Description testDescription();
     205             : 
     206             :     @Nullable
     207             :     abstract String configName();
     208             : 
     209             :     abstract boolean memory();
     210             : 
     211             :     abstract boolean httpd();
     212             : 
     213             :     abstract boolean sandboxed();
     214             : 
     215             :     abstract boolean skipProjectClone();
     216             : 
     217             :     abstract boolean useSshAnnotation();
     218             : 
     219             :     abstract boolean verifyNoPiiInChangeNotes();
     220             : 
     221             :     boolean useSsh() {
     222         138 :       return useSshAnnotation() && SshMode.useSsh();
     223             :     }
     224             : 
     225             :     abstract boolean useSystemTime();
     226             : 
     227             :     @Nullable
     228             :     abstract UseClockStep useClockStep();
     229             : 
     230             :     @Nullable
     231             :     abstract UseTimezone useTimezone();
     232             : 
     233             :     @Nullable
     234             :     abstract GerritConfig config();
     235             : 
     236             :     @Nullable
     237             :     abstract GerritConfigs configs();
     238             : 
     239             :     @Nullable
     240             :     abstract GlobalPluginConfig pluginConfig();
     241             : 
     242             :     @Nullable
     243             :     abstract GlobalPluginConfigs pluginConfigs();
     244             : 
     245             :     private void checkValidAnnotations() {
     246         138 :       if (useClockStep() != null && useSystemTime()) {
     247           0 :         throw new IllegalStateException("Use either @UseClockStep or @UseSystemTime, not both");
     248             :       }
     249         138 :       if (configs() != null && config() != null) {
     250           0 :         throw new IllegalStateException("Use either @GerritConfigs or @GerritConfig, not both");
     251             :       }
     252         138 :       if (pluginConfigs() != null && pluginConfig() != null) {
     253           0 :         throw new IllegalStateException(
     254             :             "Use either @GlobalPluginConfig or @GlobalPluginConfigs, not both");
     255             :       }
     256         138 :       if ((pluginConfigs() != null || pluginConfig() != null) && memory()) {
     257           0 :         throw new IllegalStateException("Must use @UseLocalDisk with @GlobalPluginConfig(s)");
     258             :       }
     259         138 :     }
     260             : 
     261             :     private Config buildConfig(Config baseConfig) {
     262         138 :       if (configs() != null) {
     263          15 :         return ConfigAnnotationParser.parse(baseConfig, configs());
     264         137 :       } else if (config() != null) {
     265          45 :         return ConfigAnnotationParser.parse(baseConfig, config());
     266             :       } else {
     267         136 :         return baseConfig;
     268             :       }
     269             :     }
     270             : 
     271             :     private Map<String, Config> buildPluginConfigs() {
     272          15 :       if (pluginConfigs() != null) {
     273           1 :         return ConfigAnnotationParser.parse(pluginConfigs());
     274          15 :       } else if (pluginConfig() != null) {
     275           1 :         return ConfigAnnotationParser.parse(pluginConfig());
     276             :       }
     277          14 :       return new HashMap<>();
     278             :     }
     279             :   }
     280             : 
     281             :   private static boolean forceLocalDisk() {
     282         132 :     String value = Strings.nullToEmpty(System.getenv("GERRIT_FORCE_LOCAL_DISK"));
     283         132 :     if (value.isEmpty()) {
     284         132 :       value = Strings.nullToEmpty(System.getProperty("gerrit.forceLocalDisk"));
     285             :     }
     286         132 :     switch (value.trim().toLowerCase(Locale.US)) {
     287             :       case "1":
     288             :       case "yes":
     289             :       case "true":
     290           0 :         return true;
     291             :       default:
     292         132 :         return false;
     293             :     }
     294             :   }
     295             : 
     296             :   /**
     297             :    * Initializes on-disk site but does not start server.
     298             :    *
     299             :    * @param desc server description
     300             :    * @param baseConfig default config values; merged with config from {@code desc} and then written
     301             :    *     into {@code site/etc/gerrit.config}.
     302             :    * @param site temp directory where site will live.
     303             :    */
     304             :   public static void init(Description desc, Config baseConfig, Path site) throws Exception {
     305          15 :     checkArgument(!desc.memory(), "can't initialize site path for in-memory test: %s", desc);
     306          15 :     Config cfg = desc.buildConfig(baseConfig);
     307          15 :     Map<String, Config> pluginConfigs = desc.buildPluginConfigs();
     308             : 
     309          15 :     MergeableFileBasedConfig gerritConfig =
     310             :         new MergeableFileBasedConfig(
     311          15 :             site.resolve("etc").resolve("gerrit.config").toFile(), FS.DETECTED);
     312          15 :     gerritConfig.load();
     313          15 :     gerritConfig.merge(cfg);
     314          15 :     mergeTestConfig(gerritConfig);
     315          15 :     String configuredIndexBackend = cfg.getString("index", null, "type");
     316          15 :     if (configuredIndexBackend == null) {
     317             :       // Propagate index type to pgms that run off of the gerrit.config file on local disk.
     318          15 :       IndexType indexType = IndexType.fromEnvironment().orElse(new IndexType("fake"));
     319          15 :       gerritConfig.setString("index", null, "type", indexType.isLucene() ? "lucene" : "fake");
     320             :     }
     321          15 :     gerritConfig.save();
     322             : 
     323          15 :     Init init = new Init();
     324          15 :     int rc =
     325          15 :         init.main(
     326             :             new String[] {
     327          15 :               "-d", site.toString(), "--batch", "--no-auto-start", "--skip-plugins",
     328             :             });
     329          15 :     if (rc != 0) {
     330           0 :       throw new RuntimeException("Couldn't initialize site");
     331             :     }
     332             : 
     333          15 :     for (String pluginName : pluginConfigs.keySet()) {
     334           1 :       MergeableFileBasedConfig pluginCfg =
     335             :           new MergeableFileBasedConfig(
     336           1 :               site.resolve("etc").resolve(pluginName + ".config").toFile(), FS.DETECTED);
     337           1 :       pluginCfg.load();
     338           1 :       pluginCfg.merge(pluginConfigs.get(pluginName));
     339           1 :       pluginCfg.save();
     340           1 :     }
     341          15 :   }
     342             : 
     343             :   /**
     344             :    * Initializes new Gerrit site and returns started server.
     345             :    *
     346             :    * <p>A new temporary directory for the site will be created with {@code temporaryFolder}, even in
     347             :    * the server is otherwise configured in-memory. Closing the server stops the daemon but does not
     348             :    * delete the temporary directory..
     349             :    *
     350             :    * @param temporaryFolder helper rule for creating site directories.
     351             :    * @param desc server description.
     352             :    * @param baseConfig default config values; merged with config from {@code desc}.
     353             :    * @param testSysModule additional Guice module to use.
     354             :    * @param testSshModule additional Guice module to use.
     355             :    * @return started server.
     356             :    */
     357             :   public static GerritServer initAndStart(
     358             :       TemporaryFolder temporaryFolder,
     359             :       Description desc,
     360             :       Config baseConfig,
     361             :       @Nullable Module testSysModule,
     362             :       @Nullable Module testAuditModule,
     363             :       @Nullable Module testSshModule)
     364             :       throws Exception {
     365         132 :     Path site = temporaryFolder.newFolder().toPath();
     366             :     try {
     367         132 :       if (!desc.memory()) {
     368           8 :         init(desc, baseConfig, site);
     369             :       }
     370         132 :       return start(desc, baseConfig, site, testSysModule, testAuditModule, testSshModule, null);
     371           1 :     } catch (Exception e) {
     372           1 :       throw e;
     373             :     }
     374             :   }
     375             : 
     376             :   /**
     377             :    * Starts Gerrit server from existing on-disk site.
     378             :    *
     379             :    * @param desc server description.
     380             :    * @param baseConfig default config values; merged with config from {@code desc}.
     381             :    * @param site existing temporary directory for site. Required, but may be empty, for in-memory
     382             :    *     servers. For on-disk servers, assumes that {@link #init} was previously called to
     383             :    *     initialize this directory. Can be retrieved from the returned instance via {@link
     384             :    *     #getSitePath()}.
     385             :    * @param testSysModule optional additional module to add to the system injector.
     386             :    * @param testSshModule optional additional module to add to the ssh injector.
     387             :    * @param inMemoryRepoManager {@link InMemoryRepositoryManager} that should be used if the site is
     388             :    *     started in memory
     389             :    * @param additionalArgs additional command-line arguments for the daemon program; only allowed if
     390             :    *     the test is not in-memory.
     391             :    * @return started server.
     392             :    */
     393             :   public static GerritServer start(
     394             :       Description desc,
     395             :       Config baseConfig,
     396             :       Path site,
     397             :       @Nullable Module testSysModule,
     398             :       @Nullable Module testAuditModule,
     399             :       @Nullable Module testSshModule,
     400             :       @Nullable InMemoryRepositoryManager inMemoryRepoManager,
     401             :       String... additionalArgs)
     402             :       throws Exception {
     403         138 :     checkArgument(site != null, "site is required (even for in-memory server");
     404         138 :     desc.checkValidAnnotations();
     405         138 :     TestLoggingActivator.configureLogging();
     406         138 :     CyclicBarrier serverStarted = new CyclicBarrier(2);
     407         138 :     Daemon daemon =
     408             :         new Daemon(
     409             :             () -> {
     410             :               try {
     411          15 :                 serverStarted.await();
     412           0 :               } catch (InterruptedException | BrokenBarrierException e) {
     413           0 :                 throw new RuntimeException(e);
     414          15 :               }
     415          15 :             },
     416             :             site);
     417         138 :     daemon.setEmailModuleForTesting(new FakeEmailSenderModule());
     418         138 :     daemon.setAuditEventModuleForTesting(
     419         138 :         MoreObjects.firstNonNull(testAuditModule, new FakeGroupAuditServiceModule()));
     420         138 :     if (testSysModule != null) {
     421          17 :       daemon.addAdditionalSysModuleForTesting(testSysModule);
     422             :     }
     423         138 :     if (testSshModule != null) {
     424           1 :       daemon.addAdditionalSshModuleForTesting(testSshModule);
     425             :     }
     426         138 :     daemon.setEnableSshd(desc.useSsh());
     427         138 :     daemon.addAdditionalSysModuleForTesting(
     428         138 :         new AbstractModule() {
     429             :           @Override
     430             :           protected void configure() {
     431         138 :             bind(CommitValidationListener.class)
     432         138 :                 .annotatedWith(Exports.named("object-visibility-listener"))
     433         138 :                 .to(GitObjectVisibilityChecker.class);
     434         138 :           }
     435             :         });
     436         138 :     daemon.addAdditionalSysModuleForTesting(
     437         138 :         new AbstractModule() {
     438             :           @Override
     439             :           protected void configure() {
     440         138 :             super.configure();
     441             :             // GerritServer isn't restarted between tests. TestTicker allows to replace actual
     442             :             // Ticker in tests without restarting server and transparently for other code.
     443             :             // Alternative option with Provider<Ticker> is less convinient, because it affects how
     444             :             // gerrit code should be written - i.e. Ticker must not be stored in fields and must
     445             :             // always be obtained from the provider.
     446         138 :             TestTicker testTicker = new TestTicker();
     447         138 :             OptionalBinder.newOptionalBinder(binder(), Ticker.class)
     448         138 :                 .setBinding()
     449         138 :                 .toInstance(testTicker);
     450         138 :             bind(TestTicker.class).toInstance(testTicker);
     451         138 :           }
     452             :         });
     453             : 
     454         138 :     if (desc.memory()) {
     455         132 :       checkArgument(additionalArgs.length == 0, "cannot pass args to in-memory server");
     456         132 :       return startInMemory(desc, site, baseConfig, daemon, inMemoryRepoManager);
     457             :     }
     458          15 :     return startOnDisk(desc, site, daemon, serverStarted, additionalArgs);
     459             :   }
     460             : 
     461             :   private static GerritServer startInMemory(
     462             :       Description desc,
     463             :       Path site,
     464             :       Config baseConfig,
     465             :       Daemon daemon,
     466             :       @Nullable InMemoryRepositoryManager inMemoryRepoManager)
     467             :       throws Exception {
     468         132 :     Config cfg = desc.buildConfig(baseConfig);
     469         132 :     daemon.setReplica(ReplicaUtil.isReplica(baseConfig) || ReplicaUtil.isReplica(cfg));
     470         132 :     mergeTestConfig(cfg);
     471             :     // Set the log4j configuration to an invalid one to prevent system logs
     472             :     // from getting configured and creating log files.
     473         132 :     System.setProperty(SystemLog.LOG4J_CONFIGURATION, "invalidConfiguration");
     474         132 :     cfg.setBoolean("httpd", null, "requestLog", false);
     475         132 :     cfg.setBoolean("sshd", null, "requestLog", false);
     476         132 :     cfg.setBoolean("index", "lucene", "testInmemory", true);
     477         132 :     cfg.setBoolean("index", null, "onlineUpgrade", false);
     478         132 :     cfg.setString("gitweb", null, "cgi", "");
     479         132 :     cfg.setString(
     480             :         "accountPatchReviewDb", null, "url", JdbcAccountPatchReviewStore.TEST_IN_MEMORY_URL);
     481             : 
     482         132 :     String configuredIndexBackend = cfg.getString("index", null, "type");
     483             :     IndexType indexType;
     484         132 :     if (configuredIndexBackend != null) {
     485             :       // Explicitly configured index backend from gerrit.config trumps any other ways to configure
     486             :       // index backends so that Reindex tests can be explicit about the backend they want to test
     487             :       // against.
     488           1 :       indexType = new IndexType(configuredIndexBackend);
     489             :     } else {
     490             :       // Allow configuring the index backend based on sys/env variables so that integration tests
     491             :       // can be run against different index backends.
     492         132 :       indexType = IndexType.fromEnvironment().orElse(new IndexType("fake"));
     493             :     }
     494         132 :     if (indexType.isLucene()) {
     495           1 :       daemon.setIndexModule(
     496           1 :           LuceneIndexModule.singleVersionAllLatest(
     497           1 :               0, ReplicaUtil.isReplica(baseConfig), AutoFlush.ENABLED));
     498             :     } else {
     499         132 :       daemon.setIndexModule(FakeIndexModule.latestVersion(false));
     500             :     }
     501             : 
     502         132 :     daemon.setEnableHttpd(desc.httpd());
     503         132 :     daemon.setInMemory(true);
     504         132 :     daemon.setDatabaseForTesting(
     505         132 :         ImmutableList.of(
     506             :             new InMemoryTestingDatabaseModule(cfg, site, inMemoryRepoManager),
     507         132 :             new AbstractModule() {
     508             :               @Override
     509             :               protected void configure() {
     510         132 :                 bind(GerritRuntime.class).toInstance(GerritRuntime.DAEMON);
     511         132 :               }
     512             :             },
     513             :             new ConfigExperimentFeaturesModule()));
     514         132 :     daemon.addAdditionalSysModuleForTesting(
     515             :         new ReindexProjectsAtStartupModule(), new ReindexGroupsAtStartupModule());
     516         132 :     daemon.start();
     517         132 :     return new GerritServer(desc, null, createTestInjector(daemon), daemon, null);
     518             :   }
     519             : 
     520             :   private static GerritServer startOnDisk(
     521             :       Description desc,
     522             :       Path site,
     523             :       Daemon daemon,
     524             :       CyclicBarrier serverStarted,
     525             :       String[] additionalArgs)
     526             :       throws Exception {
     527          15 :     requireNonNull(site);
     528          15 :     daemon.addAdditionalSysModuleForTesting(
     529             :         new ReindexProjectsAtStartupModule(), new ReindexGroupsAtStartupModule());
     530          15 :     ExecutorService daemonService = Executors.newSingleThreadExecutor();
     531          15 :     String[] args =
     532          15 :         Stream.concat(
     533          15 :                 Stream.of(
     534          15 :                     "-d", site.toString(), "--headless", "--console-log", "--show-stack-trace"),
     535          15 :                 Arrays.stream(additionalArgs))
     536          15 :             .toArray(String[]::new);
     537             :     @SuppressWarnings("unused")
     538          15 :     Future<?> possiblyIgnoredError =
     539          15 :         daemonService.submit(
     540             :             () -> {
     541          15 :               int rc = daemon.main(args);
     542          15 :               if (rc != 0) {
     543           1 :                 System.err.println("Failed to start Gerrit daemon");
     544           1 :                 serverStarted.reset();
     545             :               }
     546          15 :               return null;
     547             :             });
     548             :     try {
     549          15 :       serverStarted.await();
     550           1 :     } catch (BrokenBarrierException e) {
     551           1 :       daemon.stop();
     552           1 :       throw new StartupException("Failed to start Gerrit daemon; see log", e);
     553          15 :     }
     554          15 :     System.out.println("Gerrit Server Started");
     555             : 
     556          15 :     return new GerritServer(desc, site, createTestInjector(daemon), daemon, daemonService);
     557             :   }
     558             : 
     559             :   private static void mergeTestConfig(Config cfg) {
     560         138 :     String forceEphemeralPort = String.format("%s:0", getLocalHost().getHostName());
     561         138 :     String url = "http://" + forceEphemeralPort + "/";
     562             : 
     563         138 :     if (cfg.getString("gerrit", null, "canonicalWebUrl") == null) {
     564         138 :       cfg.setString("gerrit", null, "canonicalWebUrl", url);
     565             :     }
     566         138 :     if (cfg.getString("httpd", null, "listenUrl") == null) {
     567         138 :       cfg.setString("httpd", null, "listenUrl", url);
     568             :     }
     569         138 :     if (cfg.getString("sshd", null, "listenAddress") == null) {
     570          20 :       cfg.setString("sshd", null, "listenAddress", forceEphemeralPort);
     571             :     }
     572         138 :     cfg.setBoolean("sshd", null, "testUseInsecureRandom", true);
     573         138 :     cfg.unset("cache", null, "directory");
     574         138 :     cfg.setString("gerrit", null, "basePath", "git");
     575         138 :     cfg.setBoolean("sendemail", null, "enable", true);
     576         138 :     cfg.setInt("sendemail", null, "threadPoolSize", 0);
     577         138 :     cfg.setInt("plugins", null, "checkFrequency", 0);
     578             : 
     579         138 :     cfg.setInt("sshd", null, "threads", 1);
     580         138 :     cfg.setInt("sshd", null, "commandStartThreads", 1);
     581         138 :     cfg.setInt("receive", null, "threadPoolSize", 1);
     582         138 :     cfg.setInt("index", null, "threads", 1);
     583         138 :     if (cfg.getString("index", null, "mergeabilityComputationBehavior") == null) {
     584         138 :       cfg.setString("index", null, "mergeabilityComputationBehavior", "NEVER");
     585             :     }
     586         138 :   }
     587             : 
     588             :   private static Injector createTestInjector(Daemon daemon) throws Exception {
     589         138 :     Injector sysInjector = getInjector(daemon, "sysInjector");
     590         138 :     Module module =
     591         138 :         new FactoryModule() {
     592             :           @Override
     593             :           protected void configure() {
     594         138 :             bindConstant().annotatedWith(SshEnabled.class).to(daemon.getEnableSshd());
     595         138 :             bind(AccountCreator.class);
     596         138 :             bind(AccountOperations.class).to(AccountOperationsImpl.class);
     597         138 :             bind(GroupOperations.class).to(GroupOperationsImpl.class);
     598         138 :             bind(ProjectOperations.class).to(ProjectOperationsImpl.class);
     599         138 :             bind(RequestScopeOperations.class).to(RequestScopeOperationsImpl.class);
     600         138 :             bind(ChangeOperations.class).to(ChangeOperationsImpl.class);
     601         138 :             factory(PerPatchsetOperationsImpl.Factory.class);
     602         138 :             factory(PerCommentOperationsImpl.Factory.class);
     603         138 :             factory(PerDraftCommentOperationsImpl.Factory.class);
     604         138 :             factory(PerRobotCommentOperationsImpl.Factory.class);
     605         138 :             factory(PushOneCommit.Factory.class);
     606         138 :             install(InProcessProtocol.module());
     607         138 :             install(new NoSshModule());
     608         138 :             install(new AsyncReceiveCommitsModule());
     609         138 :             factory(ProjectResetter.Builder.Factory.class);
     610         138 :           }
     611             : 
     612             :           @Provides
     613             :           @Singleton
     614             :           @Nullable
     615             :           @TestSshServerAddress
     616             :           InetSocketAddress getSshAddress(@GerritServerConfig Config cfg) {
     617         138 :             String addr = cfg.getString("sshd", null, "listenAddress");
     618             :             // We do not use InitSshd.isOff to avoid coupling GerritServer to the SSH code.
     619         138 :             return !"off".equalsIgnoreCase(addr)
     620          20 :                 ? SocketUtil.resolve(cfg.getString("sshd", null, "listenAddress"), 0)
     621         125 :                 : null;
     622             :           }
     623             :         };
     624         138 :     return sysInjector.createChildInjector(module);
     625             :   }
     626             : 
     627             :   private static Injector getInjector(Object obj, String field)
     628             :       throws SecurityException, NoSuchFieldException, IllegalArgumentException,
     629             :           IllegalAccessException {
     630         138 :     Field f = obj.getClass().getDeclaredField(field);
     631         138 :     f.setAccessible(true);
     632         138 :     Object v = f.get(obj);
     633         138 :     checkArgument(v instanceof Injector, "not an Injector: %s", v);
     634         138 :     return (Injector) f.get(obj);
     635             :   }
     636             : 
     637             :   private static InetAddress getLocalHost() {
     638         138 :     return InetAddress.getLoopbackAddress();
     639             :   }
     640             : 
     641             :   private final Description desc;
     642             :   private final Path sitePath;
     643             : 
     644             :   private Daemon daemon;
     645             :   private ExecutorService daemonService;
     646             :   private Injector testInjector;
     647             :   private String url;
     648             :   private InetSocketAddress httpAddress;
     649             : 
     650             :   private GerritServer(
     651             :       Description desc,
     652             :       @Nullable Path sitePath,
     653             :       Injector testInjector,
     654             :       Daemon daemon,
     655         138 :       @Nullable ExecutorService daemonService) {
     656         138 :     this.desc = requireNonNull(desc);
     657         138 :     this.sitePath = sitePath;
     658         138 :     this.testInjector = requireNonNull(testInjector);
     659         138 :     this.daemon = requireNonNull(daemon);
     660         138 :     this.daemonService = daemonService;
     661             : 
     662         138 :     Config cfg = testInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
     663         138 :     url = cfg.getString("gerrit", null, "canonicalWebUrl");
     664         138 :     URI uri = URI.create(url);
     665         138 :     httpAddress = new InetSocketAddress(uri.getHost(), uri.getPort());
     666         138 :   }
     667             : 
     668             :   public String getUrl() {
     669         132 :     return url;
     670             :   }
     671             : 
     672             :   InetSocketAddress getHttpAddress() {
     673           6 :     return httpAddress;
     674             :   }
     675             : 
     676             :   public Injector getTestInjector() {
     677         138 :     return testInjector;
     678             :   }
     679             : 
     680             :   public Injector getHttpdInjector() {
     681           2 :     return daemon.getHttpdInjector();
     682             :   }
     683             : 
     684             :   Description getDescription() {
     685           0 :     return desc;
     686             :   }
     687             : 
     688             :   public static GerritServer restartAsSlave(GerritServer server) throws Exception {
     689           3 :     checkState(server.desc.sandboxed(), "restarting as slave requires @Sandboxed");
     690             : 
     691           3 :     Path site = server.testInjector.getInstance(Key.get(Path.class, SitePath.class));
     692             : 
     693           3 :     Config cfg = server.testInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
     694           3 :     cfg.setBoolean("container", null, "replica", true);
     695             : 
     696           3 :     InMemoryRepositoryManager inMemoryRepoManager = null;
     697           3 :     if (hasBinding(server.testInjector, InMemoryRepositoryManager.class)) {
     698           3 :       inMemoryRepoManager = server.testInjector.getInstance(InMemoryRepositoryManager.class);
     699             :     }
     700             : 
     701           3 :     server.close();
     702           3 :     server.daemon.stop();
     703           3 :     return start(server.desc, cfg, site, null, null, null, inMemoryRepoManager);
     704             :   }
     705             : 
     706             :   public static GerritServer restart(
     707             :       GerritServer server, @Nullable Module testSysModule, @Nullable Module testSshModule)
     708             :       throws Exception {
     709           1 :     checkState(server.desc.sandboxed(), "restarting as slave requires @Sandboxed");
     710           1 :     Config cfg = server.testInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
     711           1 :     Path site = server.testInjector.getInstance(Key.get(Path.class, SitePath.class));
     712             : 
     713           1 :     InMemoryRepositoryManager inMemoryRepoManager = null;
     714           1 :     if (hasBinding(server.testInjector, InMemoryRepositoryManager.class)) {
     715           1 :       inMemoryRepoManager = server.testInjector.getInstance(InMemoryRepositoryManager.class);
     716             :     }
     717             : 
     718           1 :     server.close();
     719           1 :     server.daemon.stop();
     720           1 :     return start(server.desc, cfg, site, testSysModule, null, testSshModule, inMemoryRepoManager);
     721             :   }
     722             : 
     723             :   private static boolean hasBinding(Injector injector, Class<?> clazz) {
     724           3 :     return injector.getExistingBinding(Key.get(clazz)) != null;
     725             :   }
     726             : 
     727             :   @Override
     728             :   public void close() throws Exception {
     729         138 :     daemon.getLifecycleManager().stop();
     730         138 :     if (daemonService != null) {
     731          15 :       System.out.println("Gerrit Server Shutdown");
     732          15 :       daemonService.shutdownNow();
     733          15 :       daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
     734             :     }
     735         138 :     RepositoryCache.clear();
     736         138 :   }
     737             : 
     738             :   public Path getSitePath() {
     739           0 :     return sitePath;
     740             :   }
     741             : 
     742             :   @Override
     743             :   public String toString() {
     744           0 :     return MoreObjects.toStringHelper(this).addValue(desc).toString();
     745             :   }
     746             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750