Merge branch 'stable-3.1' into stable-3.2
* stable-3.1:
BatchUpdateTest: Extend GerritBaseTests
dev-bazel: Fix package name in example test invocation
ReviewDbBatchUpdate: Fix typo in member name
Enable to run online noteDb migration using multiple threads
GerritSimulation: Support runtime factor property
GerritSimulation: Add replaceOverride javadoc tags
GerritSimulation: Support reusable step wait times
Change-Id: Ifdb0007187a3d772e0398c07aed3b4836e4a97a0
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 3653241..39bdd6a 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -387,7 +387,7 @@
`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
----
diff --git a/Documentation/dev-e2e-tests.txt b/Documentation/dev-e2e-tests.txt
index 6d897ec..8fe8f4e 100644
--- a/Documentation/dev-e2e-tests.txt
+++ b/Documentation/dev-e2e-tests.txt
@@ -170,6 +170,17 @@
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/CloneUsingBothProtocols.scala b/e2e-tests/src/test/scala/com/google/gerrit/scenarios/CloneUsingBothProtocols.scala
index c3f772a..ab91185 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 @@
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 @@
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 75fb0b7..39b6d42 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 @@
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 @@
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 0466ced..f3a2d14 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 @@
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 06f0bdf..36df627 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,26 @@
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 * powerFactor).toInt
+ 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,
@@ -54,11 +74,15 @@
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
@@ -84,8 +108,26 @@
* override def replaceOverride(in: String): String = {
* // Simple e.g., replaceProperty("EXTENSION_JSON_KEY", "default", in)
* </pre>
+ *
+ * @param in which string to perform the replacements.
+ * @return the resulting String.
*/
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 e0b3206d..74dc052 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 @@
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 @@
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)
}