From c62b95c620f413bc2c2f25b174a8f7c5e9ab1e25 Mon Sep 17 00:00:00 2001 From: Marco Miller Date: Fri, 17 Apr 2020 12:19:33 -0400 Subject: [PATCH] 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) }