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
This commit is contained in:
Marco Miller
2020-04-17 12:19:33 -04:00
parent 29caa64448
commit c62b95c620
5 changed files with 54 additions and 9 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 => {

View File

@@ -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
}

View File

@@ -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)
}