From c62b95c620f413bc2c2f25b174a8f7c5e9ab1e25 Mon Sep 17 00:00:00 2001 From: Marco Miller Date: Fri, 17 Apr 2020 12:19:33 -0400 Subject: [PATCH 1/7] GerritSimulation: Support reusable step wait times Add support for relative runtime weights to scenarios. This way, each scenario can either weight like any other by default, or override that default with a greater weight value compared to siblings that are lighter on the execution time. Document that in GerritSimulation, where the abstraction and default are implemented. Define the default scenario weight unit (equal to 1). Allow scenarios heavier on the runtime to override that default. Define one single unit of weight as 2 seconds. This weight idea handily gets automatically factored in how long a scenario (step) needs to finish affecting the SUT. That step n-1 impact is assumed by the following step n (or next delegate scenario), in the aggregating scenario. Reuse this, hence unhardcode wait times in every core scenario step. Change-Id: I24e392b5ee1883225a77544c42608d8e49beee52 --- .../scenarios/CloneUsingBothProtocols.scala | 8 +++-- .../gerrit/scenarios/CreateChange.scala | 9 +++-- .../gerrit/scenarios/DeleteChange.scala | 2 ++ .../gerrit/scenarios/GerritSimulation.scala | 34 +++++++++++++++++++ .../scenarios/ReplayRecordsFromFeeder.scala | 10 ++++-- 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CloneUsingBothProtocols.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CloneUsingBothProtocols.scala index c3f772a81c..ab91185dee 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CloneUsingBothProtocols.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CloneUsingBothProtocols.scala @@ -23,6 +23,7 @@ import scala.concurrent.duration._ class CloneUsingBothProtocols extends GitSimulation { private val data: FileBasedFeederBuilder[Any]#F#F = jsonFile(resource).convert(keys).queue private val default: String = name + private val duration: Int = 2 override def replaceOverride(in: String): String = { replaceKeyWith("_project", default, in) @@ -37,14 +38,15 @@ class CloneUsingBothProtocols extends GitSimulation { setUp( createProject.test.inject( + nothingFor(stepWaitTime(createProject) seconds), atOnceUsers(1) ), test.inject( - nothingFor(2 seconds), - constantUsersPerSec(1) during (2 seconds) + nothingFor(stepWaitTime(this) seconds), + constantUsersPerSec(1) during (duration seconds) ), deleteProject.test.inject( - nothingFor(6 seconds), + nothingFor(stepWaitTime(deleteProject) + duration seconds), atOnceUsers(1) ), ).protocols(gitProtocol, httpProtocol) diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala index 75fb0b7a62..39b6d42cf7 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CreateChange.scala @@ -26,6 +26,8 @@ class CreateChange extends GerritSimulation { private val default: String = name private val numberKey = "_number" + override def relativeRuntimeWeight = 2 + val test: ScenarioBuilder = scenario(unique) .feed(data) .exec(httpRequest @@ -42,18 +44,19 @@ class CreateChange extends GerritSimulation { setUp( createProject.test.inject( + nothingFor(stepWaitTime(createProject) seconds), atOnceUsers(1) ), test.inject( - nothingFor(2 seconds), + nothingFor(stepWaitTime(this) seconds), atOnceUsers(1) ), deleteChange.test.inject( - nothingFor(6 seconds), + nothingFor(stepWaitTime(deleteChange) seconds), atOnceUsers(1) ), deleteProject.test.inject( - nothingFor(8 seconds), + nothingFor(stepWaitTime(deleteProject) seconds), atOnceUsers(1) ), ).protocols(httpProtocol) diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala index 0466ced538..f3a2d14f35 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/DeleteChange.scala @@ -23,6 +23,8 @@ class DeleteChange extends GerritSimulation { private val data: FileBasedFeederBuilder[Any]#F#F = jsonFile(resource).convert(keys).queue var number: Option[Int] = None + override def relativeRuntimeWeight = 2 + val test: ScenarioBuilder = scenario(unique) .feed(data) .exec(session => { diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala index 06f0bdfd78..2191b81b1a 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala @@ -31,6 +31,25 @@ class GerritSimulation extends Simulation { protected val body: String = s"$pathName-body.json" protected val unique: String = name + "-" + this.hashCode() + private val SecondsPerWeightUnit: Int = 2 + val maxExecutionTime: Int = SecondsPerWeightUnit * relativeRuntimeWeight + private var cumulativeWaitTime: Int = 0 + + /** + * How long a scenario step should wait before starting to execute. + * This is also registering that step's resulting wait time, so that time + * can be reused cumulatively by a potentially following scenario step. + * (Otherwise, the Gatling set-up scenario steps execute all at once.) + * + * @param scenario for which to return a wait time. + * @return that step's wait time as an Int. + */ + protected def stepWaitTime(scenario: GerritSimulation): Int = { + val currentWaitTime = cumulativeWaitTime + cumulativeWaitTime += scenario.maxExecutionTime + currentWaitTime + } + protected val httpRequest: HttpRequestBuilder = http(unique).post("${url}") protected val httpProtocol: HttpProtocolBuilder = http.basicAuth( conf.httpConfiguration.userName, @@ -88,4 +107,19 @@ class GerritSimulation extends Simulation { def replaceOverride(in: String): String = { in } + + /** + * Meant to be optionally overridden by (heavier) scenarios. + * This is the relative runtime weight of the scenario class or type, + * compared to other scenarios' own runtime weights. + * + * The default weight or unit of weight is the pre-assigned value below. + * This default applies to any scenario class that is not overriding it + * with a greater, relative runtime weight value. Overriding scenarios + * happen to relatively require more run time than siblings, prior to + * being expected as completed. + * + * @return the relative runtime weight of this scenario as an Int. + */ + def relativeRuntimeWeight = 1 } diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ReplayRecordsFromFeeder.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ReplayRecordsFromFeeder.scala index e0b3206d11..74dc052136 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ReplayRecordsFromFeeder.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/ReplayRecordsFromFeeder.scala @@ -24,6 +24,8 @@ class ReplayRecordsFromFeeder extends GitSimulation { private val data: FileBasedFeederBuilder[Any]#F#F = jsonFile(resource).convert(keys).circular private val default: String = name + override def relativeRuntimeWeight = 30 + override def replaceOverride(in: String): String = { replaceKeyWith("_project", default, in) } @@ -36,22 +38,24 @@ class ReplayRecordsFromFeeder extends GitSimulation { private val createProject = new CreateProject(default) private val deleteProject = new DeleteProject(default) + private val maxBeforeDelete: Int = maxExecutionTime - deleteProject.maxExecutionTime setUp( createProject.test.inject( + nothingFor(stepWaitTime(createProject) seconds), atOnceUsers(1) ), test.inject( - nothingFor(4 seconds), + nothingFor(stepWaitTime(this) seconds), atOnceUsers(10), rampUsers(10) during (5 seconds), constantUsersPerSec(20) during (15 seconds), constantUsersPerSec(20) during (15 seconds) randomized ), deleteProject.test.inject( - nothingFor(59 seconds), + nothingFor(maxBeforeDelete seconds), atOnceUsers(1) ), ).protocols(gitProtocol, httpProtocol) - .maxDuration(61 seconds) + .maxDuration(maxExecutionTime seconds) } From 8d14867a00223c300efd89db08e5d722344fc0f8 Mon Sep 17 00:00:00 2001 From: Marco Miller Date: Tue, 28 Apr 2020 15:22:50 -0400 Subject: [PATCH 2/7] GerritSimulation: Add replaceOverride javadoc tags As these were missing before. Align with the other documented methods. Change-Id: I605c6b5f386c89852ba63b0300a753807868ff21 --- .../scala/com/google/gerrit/scenarios/GerritSimulation.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala index 2191b81b1a..3d7abf2aee 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala @@ -103,6 +103,9 @@ class GerritSimulation extends Simulation { * override def replaceOverride(in: String): String = { * // Simple e.g., replaceProperty("EXTENSION_JSON_KEY", "default", in) * + * + * @param in which string to perform the replacements. + * @return the resulting String. */ def replaceOverride(in: String): String = { in From 0b2c50ab8d437c605c746a9b2052e2664aa5040e Mon Sep 17 00:00:00 2001 From: Marco Miller Date: Fri, 17 Apr 2020 14:04:08 -0400 Subject: [PATCH 3/7] GerritSimulation: Support runtime factor property Add support for a core framework JAVA_OPTS property [1] that can be optionally set depending on the runtime environment. For slower or more complex execution environments, that property value can be increased, to make scenarios wait longer before considering their steps as completed. Document that new property, why and how to use it if necessary. [1] https://gerrit-review.googlesource.com/Documentation/dev-e2e-tests.html#_environment_properties Change-Id: Ie477a079f205b712643fce766b7043cbde5f1487 --- Documentation/dev-e2e-tests.txt | 11 +++++++++++ .../google/gerrit/scenarios/GerritSimulation.scala | 9 +++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Documentation/dev-e2e-tests.txt b/Documentation/dev-e2e-tests.txt index a0fe551cce..bac516933a 100644 --- a/Documentation/dev-e2e-tests.txt +++ b/Documentation/dev-e2e-tests.txt @@ -167,6 +167,17 @@ Further above, the `_PROJECT` keyword is prefixed with an underscore, which mean gets automatically generated by the scenario. Any property setting for it is therefore not applicable. Its usage differs from the non-prefixed `PROJECT` keyword, in that sense. +The following core property can be optionally set depending on the runtime environment. The test +environments used as reference for scenarios development assume its default value, `1.0`. For +slower or more complex execution environments, the value can be increased this way for example: + +* `-Dcom.google.gerrit.scenarios.power_factor=1.5` + +This will make the scenario steps take half more time to expect proper completion. A value smaller +than the default, say `0.8`, will make scenarios wait somewhat less than how they were developed. +Scenario development is often done using locally running Gerrit systems under test, which are +sometimes dockerized. + == How to run tests Run all tests: diff --git a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala index 3d7abf2aee..36df62797f 100644 --- a/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala +++ b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/GerritSimulation.scala @@ -31,8 +31,9 @@ class GerritSimulation extends Simulation { protected val body: String = s"$pathName-body.json" protected val unique: String = name + "-" + this.hashCode() + private val powerFactor: Double = replaceProperty("power_factor", 1.0).toDouble private val SecondsPerWeightUnit: Int = 2 - val maxExecutionTime: Int = SecondsPerWeightUnit * relativeRuntimeWeight + val maxExecutionTime: Int = (SecondsPerWeightUnit * relativeRuntimeWeight * powerFactor).toInt private var cumulativeWaitTime: Int = 0 /** @@ -73,11 +74,15 @@ class GerritSimulation extends Simulation { replaceProperty(term, term, in) } + private def replaceProperty(term: String, default: Any): String = { + replaceProperty(term, default, term.toUpperCase) + } + protected def replaceProperty(term: String, default: Any, in: String): String = { val property = pack + "." + term var value = default default match { - case _: String => + case _: String | _: Double => val propertyValue = Option(System.getProperty(property)) if (propertyValue.nonEmpty) { value = propertyValue.get From 83388e1fe75fc8b55dbcae3ca084519bb709d59e Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Thu, 9 Apr 2020 15:57:11 +0200 Subject: [PATCH 4/7] Enable to run online noteDb migration using multiple threads So far online migration only used a single thread for migration from reviewDb to noteDb. Introduce a configuration parameter notedb.onlineMigrationThreads to allow tuning the number of threads the migration can use. This helps to speedup online migration at the expense of imposing a higher load on the Gerrit server running at the same time. Change-Id: Icac0ec4907b82d1402330d01eb05e09fcca28682 --- Documentation/config-gerrit.txt | 7 +++++++ .../notedb/rebuild/OnlineNoteDbMigrator.java | 15 ++++++++++++-- .../pgm/StandaloneNoteDbMigrationIT.java | 20 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 03c4beb557..cd15de70cc 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -3716,6 +3716,13 @@ each process retrieves at once. + By default, 1. +[[notedb.onlineMigrationThreads]] notedb.onlineMigrationThreads:: ++ +The number of threads used to run the online migration from reviewDb to noteDb. +This allows to speed up online migration from reviewDb to noteDb at the expense +of imposing a higher load on the running server. ++ +By default, 1. [[oauth]] === Section oauth diff --git a/java/com/google/gerrit/server/notedb/rebuild/OnlineNoteDbMigrator.java b/java/com/google/gerrit/server/notedb/rebuild/OnlineNoteDbMigrator.java index b5a8236059..46f5b22e91 100644 --- a/java/com/google/gerrit/server/notedb/rebuild/OnlineNoteDbMigrator.java +++ b/java/com/google/gerrit/server/notedb/rebuild/OnlineNoteDbMigrator.java @@ -14,6 +14,8 @@ package com.google.gerrit.server.notedb.rebuild; +import static com.google.gerrit.server.notedb.NotesMigration.SECTION_NOTE_DB; + import com.google.common.base.Stopwatch; import com.google.common.flogger.FluentLogger; import com.google.gerrit.extensions.events.LifecycleListener; @@ -35,6 +37,8 @@ public class OnlineNoteDbMigrator implements LifecycleListener { private static final String TRIAL = "OnlineNoteDbMigrator/trial"; + private static final String ONLINE_MIGRATION_THREADS = "onlineMigrationThreads"; + public static class Module extends LifecycleModule { private final boolean trial; @@ -54,6 +58,7 @@ public class OnlineNoteDbMigrator implements LifecycleListener { private final Provider migratorBuilderProvider; private final boolean upgradeIndex; private final boolean trial; + private final int threads; @Inject OnlineNoteDbMigrator( @@ -67,6 +72,7 @@ public class OnlineNoteDbMigrator implements LifecycleListener { this.migratorBuilderProvider = migratorBuilderProvider; this.upgradeIndex = VersionManager.getOnlineUpgrade(cfg); this.trial = trial || NoteDbMigrator.getTrialMode(cfg); + this.threads = cfg.getInt(SECTION_NOTE_DB, ONLINE_MIGRATION_THREADS, 1); } @Override @@ -84,9 +90,14 @@ public class OnlineNoteDbMigrator implements LifecycleListener { "Online index schema upgrades will be deferred until NoteDb migration is complete"); } Stopwatch sw = Stopwatch.createStarted(); - // TODO(dborowitz): Tune threads, maybe expose a progress monitor somewhere. + // TODO(dborowitz): maybe expose a progress monitor somewhere. try (NoteDbMigrator migrator = - migratorBuilderProvider.get().setAutoMigrate(true).setTrialMode(trial).build()) { + migratorBuilderProvider + .get() + .setThreads(threads) + .setAutoMigrate(true) + .setTrialMode(trial) + .build()) { migrator.migrate(); } catch (Exception e) { logger.atSevere().withCause(e).log("Error in online NoteDb migration"); diff --git a/javatests/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java b/javatests/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java index 1bb23fba9e..fd00e5444d 100644 --- a/javatests/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java +++ b/javatests/com/google/gerrit/acceptance/pgm/StandaloneNoteDbMigrationIT.java @@ -221,6 +221,26 @@ public class StandaloneNoteDbMigrationIT extends StandaloneSiteTest { assertAutoMigrateConfig(noteDbConfig, false); } + @Test + public void onlineMigrationMultithreaded() throws Exception { + assertNoAutoMigrateConfig(gerritConfig); + assertNoAutoMigrateConfig(noteDbConfig); + + testOnlineMigration( + u -> { + gerritConfig.setBoolean("noteDb", "changes", "autoMigrate", true); + gerritConfig.setInt("noteDb", null, "onlineMigrationThreads", 4); + gerritConfig.save(); + return startServer(u.module()); + }); + + // Auto-migration is turned off in notedb.config, which takes precedence, but is still on in + // gerrit.config. This means Puppet can continue overwriting gerrit.config without turning + // auto-migration back on. + assertAutoMigrateConfig(gerritConfig, true); + assertAutoMigrateConfig(noteDbConfig, false); + } + @Test public void onlineMigrationTrialModeViaFlag() throws Exception { assertNoAutoMigrateConfig(gerritConfig); From f39e3ac553e82cad1d23da3930cba3ec50b91afb Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 1 May 2020 10:20:46 +0900 Subject: [PATCH 5/7] ReviewDbBatchUpdate: Fix typo in member name Change-Id: I2a7267e3046de569eac6f9a6ebd2804cab0ed171 --- .../google/gerrit/server/update/ReviewDbBatchUpdate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java index cab96e5286..f14e9997f0 100644 --- a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java +++ b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java @@ -304,7 +304,7 @@ public class ReviewDbBatchUpdate extends BatchUpdate { private final ChangeNotes.Factory changeNotesFactory; private final ChangeUpdate.Factory changeUpdateFactory; private final GitReferenceUpdated gitRefUpdated; - private final ListeningExecutorService changeUpdateExector; + private final ListeningExecutorService changeUpdateExecutor; private final Metrics metrics; private final NoteDbUpdateManager.Factory updateManagerFactory; private final NotesMigration notesMigration; @@ -322,7 +322,7 @@ public class ReviewDbBatchUpdate extends BatchUpdate { AllUsersName allUsers, ChangeIndexer indexer, ChangeNotes.Factory changeNotesFactory, - @ChangeUpdateExecutor ListeningExecutorService changeUpdateExector, + @ChangeUpdateExecutor ListeningExecutorService changeUpdateExecutor, ChangeUpdate.Factory changeUpdateFactory, @GerritPersonIdent PersonIdent serverIdent, GitReferenceUpdated gitRefUpdated, @@ -338,7 +338,7 @@ public class ReviewDbBatchUpdate extends BatchUpdate { super(repoManager, serverIdent, project, user, when); this.allUsers = allUsers; this.changeNotesFactory = changeNotesFactory; - this.changeUpdateExector = changeUpdateExector; + this.changeUpdateExecutor = changeUpdateExecutor; this.changeUpdateFactory = changeUpdateFactory; this.gitRefUpdated = gitRefUpdated; this.indexer = indexer; @@ -440,7 +440,7 @@ public class ReviewDbBatchUpdate extends BatchUpdate { try { logDebug("Executing change ops (parallel? %s)", parallel); ListeningExecutorService executor = - parallel ? changeUpdateExector : MoreExecutors.newDirectExecutorService(); + parallel ? changeUpdateExecutor : MoreExecutors.newDirectExecutorService(); tasks = new ArrayList<>(ops.keySet().size()); try { From d623a5c6e1d9d2c1e1edf0712720ad9740377a45 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 1 May 2020 14:29:57 +0900 Subject: [PATCH 6/7] dev-bazel: Fix package name in example test invocation Invoking the test with the given example fails because 'google' is missing from the package: There was 1 failure: 1) initializationError(org.junit.runner.manipulation.Filter) java.lang.Exception: No tests found matching RegEx[com.gerrit.server.notedb.ChangeNotesTest] Change-Id: I5cd3a8e9358c29fdb59cceb4851db3841c26c749 --- Documentation/dev-bazel.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt index 03f81b5ab3..00ac348bbf 100644 --- a/Documentation/dev-bazel.txt +++ b/Documentation/dev-bazel.txt @@ -400,7 +400,7 @@ In IDE, set `-Dgerrit.logLevel=debug` as a VM argument. With `bazel`, pass `GERRIT_LOG_LEVEL=debug` environment variable: ---- - bazel test --test_filter=com.gerrit.server.notedb.ChangeNotesTest \ + bazel test --test_filter=com.google.gerrit.server.notedb.ChangeNotesTest \ --test_env=GERRIT_LOG_LEVEL=debug \ javatests/com/google/gerrit/server:server_tests ---- From a0f6acfd089ae74ad2e7a1df6aa8ea45d49e7e80 Mon Sep 17 00:00:00 2001 From: David Pursehouse Date: Fri, 1 May 2020 14:58:25 +0900 Subject: [PATCH 7/7] BatchUpdateTest: Extend GerritBaseTests GerritBaseTests sets up the logging configuration, so when the test does not derive from that the logging does not work as expected. There are probably some more unit tests that suffer the same problem but I have not explicitly looked for them. Change-Id: I16e3c91a7908923ab5d34dfda6b7964c96bbf16a --- javatests/com/google/gerrit/server/update/BatchUpdateTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javatests/com/google/gerrit/server/update/BatchUpdateTest.java b/javatests/com/google/gerrit/server/update/BatchUpdateTest.java index 70c4383cf8..7f8e1f444a 100644 --- a/javatests/com/google/gerrit/server/update/BatchUpdateTest.java +++ b/javatests/com/google/gerrit/server/update/BatchUpdateTest.java @@ -21,6 +21,7 @@ import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.util.time.TimeUtil; +import com.google.gerrit.testing.GerritBaseTests; import com.google.gerrit.testing.InMemoryTestEnvironment; import com.google.inject.Inject; import com.google.inject.Provider; @@ -31,7 +32,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; -public class BatchUpdateTest { +public class BatchUpdateTest extends GerritBaseTests { @Rule public InMemoryTestEnvironment testEnvironment = new InMemoryTestEnvironment(); @Inject private GitRepositoryManager repoManager;