Merge "Merge branch 'stable-3.1' into stable-3.2" into stable-3.2
This commit is contained in:
		@@ -527,9 +527,6 @@ topics, a change can have multiple hashtags, and they are only used for
 | 
			
		||||
informational grouping; changes with the same hashtags are not necessarily
 | 
			
		||||
submitted together.
 | 
			
		||||
 | 
			
		||||
The hashtag feature is only available when running under
 | 
			
		||||
link:note-db.html[NoteDb].
 | 
			
		||||
 | 
			
		||||
.Set Hashtag on Push
 | 
			
		||||
----
 | 
			
		||||
  $ git push origin HEAD:refs/for/master%t=stable-bugfix
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
:linkattrs:
 | 
			
		||||
= Gerrit Code Review - NoteDb Backend
 | 
			
		||||
 | 
			
		||||
NoteDb is the next generation of Gerrit storage backend, which replaces the
 | 
			
		||||
traditional SQL backend for change, account and group metadata with storing
 | 
			
		||||
data in the same repository as code changes.
 | 
			
		||||
NoteDb is the storage backend for code review metadata. It is based on
 | 
			
		||||
Git, so code reviews are stored together with the code under review.
 | 
			
		||||
NoteDb replaced the traditional SQL backend for change, account and group
 | 
			
		||||
metadata that was used in the 2.x series.
 | 
			
		||||
 | 
			
		||||
.Advantages
 | 
			
		||||
- *Simplicity*: All data is stored in one location in the site directory, rather
 | 
			
		||||
@@ -22,33 +23,19 @@ data in the same repository as code changes.
 | 
			
		||||
- *New features*: Enables simple federation between Gerrit servers, as well as
 | 
			
		||||
  offline code review and interoperation with other tools.
 | 
			
		||||
 | 
			
		||||
== Current Status
 | 
			
		||||
 | 
			
		||||
- Storing change metadata is fully implemented in the 2.15 release, and is the
 | 
			
		||||
  default for new sites.
 | 
			
		||||
- Admins may use an link:#offline-migration[offline] or
 | 
			
		||||
  link:#online-migration[online] tool to migrate change data in an existing
 | 
			
		||||
  site from ReviewDb.
 | 
			
		||||
- Storing link:config-accounts.html[account data] is fully implemented in the
 | 
			
		||||
  2.15 release. Account data is migrated automatically during the upgrade
 | 
			
		||||
  process by running `gerrit.war init`.
 | 
			
		||||
- Storing link:config-groups.html[group metadata] is fully implemented
 | 
			
		||||
  in the 2.16 release. Group data is migrated automatically during
 | 
			
		||||
  the upgrade process by running `gerrit.war init`
 | 
			
		||||
- Account, group and change metadata on the servers behind `googlesource.com` is fully
 | 
			
		||||
  migrated to NoteDb. In other words, if you use
 | 
			
		||||
  link:https://gerrit-review.googlesource.com/[gerrit-review,role=external,window=_blank], you're already
 | 
			
		||||
  using NoteDb.
 | 
			
		||||
- NoteDb is the only database format supported by Gerrit 3.0. The change data
 | 
			
		||||
  migration tools are only included in Gerrit 2.15 and 2.16; they are not
 | 
			
		||||
  available in 3.0.
 | 
			
		||||
 | 
			
		||||
For an example NoteDb change, poke around at this one:
 | 
			
		||||
----
 | 
			
		||||
  git fetch https://gerrit.googlesource.com/gerrit refs/changes/70/98070/meta \
 | 
			
		||||
      && git log -p FETCH_HEAD
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
== Current Status
 | 
			
		||||
 | 
			
		||||
NoteDb is the only database format supported by Gerrit 3.0+. The
 | 
			
		||||
change data migration tools are only included in Gerrit 2.16; they are
 | 
			
		||||
not available in 3.0, so any upgrade from Gerrit 2.x to 3.x must go through
 | 
			
		||||
2.16 to effect the NoteDb upgrade.
 | 
			
		||||
 | 
			
		||||
[[migration]]
 | 
			
		||||
== Migration
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -979,8 +979,6 @@ If the change has no assignee the response is "`204 No Content`".
 | 
			
		||||
Returns a list of every user ever assigned to a change, in the order in which
 | 
			
		||||
they were first assigned.
 | 
			
		||||
 | 
			
		||||
[NOTE] Past assignees are only available when NoteDb is enabled.
 | 
			
		||||
 | 
			
		||||
.Request
 | 
			
		||||
----
 | 
			
		||||
  GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/past_assignees HTTP/1.0
 | 
			
		||||
@@ -2457,8 +2455,6 @@ This allows users to "highlight" changes in their dashboard
 | 
			
		||||
 | 
			
		||||
Gets the hashtags associated with a change.
 | 
			
		||||
 | 
			
		||||
[NOTE] Hashtags are only available when NoteDb is enabled.
 | 
			
		||||
 | 
			
		||||
.Request
 | 
			
		||||
----
 | 
			
		||||
  GET /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/hashtags HTTP/1.0
 | 
			
		||||
@@ -2487,8 +2483,6 @@ As response the change's hashtags are returned as a list of strings.
 | 
			
		||||
 | 
			
		||||
Adds and/or removes hashtags from a change.
 | 
			
		||||
 | 
			
		||||
[NOTE] Hashtags are only available when NoteDb is enabled.
 | 
			
		||||
 | 
			
		||||
The hashtags to add or remove must be provided in the request body inside a
 | 
			
		||||
link:#hashtags-input[HashtagsInput] entity.
 | 
			
		||||
 | 
			
		||||
@@ -6018,8 +6012,7 @@ Only set if link:#detailed-labels[detailed labels] are requested.
 | 
			
		||||
|`reviewer_updates`|optional|
 | 
			
		||||
Updates to reviewers set for the change as
 | 
			
		||||
link:#review-update-info[ReviewerUpdateInfo] entities.
 | 
			
		||||
Only set if link:#reviewer-updates[reviewer updates] are requested and
 | 
			
		||||
if NoteDb is enabled.
 | 
			
		||||
Only set if link:#reviewer-updates[reviewer updates] are requested.
 | 
			
		||||
|`messages`|optional|
 | 
			
		||||
Messages associated with the change as a list of
 | 
			
		||||
link:#change-message-info[ChangeMessageInfo] entities. +
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "url": "http://HOSTNAME:HTTP_PORT1/a/projects/PROJECT/branches/master"
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
@@ -0,0 +1,5 @@
 | 
			
		||||
[
 | 
			
		||||
  {
 | 
			
		||||
    "url": "http://HOSTNAME:HTTP_PORT/a/projects/PROJECT/branches/master"
 | 
			
		||||
  }
 | 
			
		||||
]
 | 
			
		||||
@@ -43,6 +43,6 @@ class ApproveChange extends GerritSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,73 @@
 | 
			
		||||
// Copyright (C) 2020 The Android Open Source Project
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package com.google.gerrit.scenarios
 | 
			
		||||
 | 
			
		||||
import com.typesafe.config.ConfigFactory
 | 
			
		||||
import io.gatling.core.Predef._
 | 
			
		||||
import io.gatling.core.feeder.FeederBuilder
 | 
			
		||||
import io.gatling.core.structure.ScenarioBuilder
 | 
			
		||||
import io.gatling.http.Predef._
 | 
			
		||||
 | 
			
		||||
import scala.concurrent.duration._
 | 
			
		||||
 | 
			
		||||
class CheckMasterBranchReplica1 extends ProjectSimulation {
 | 
			
		||||
  private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
 | 
			
		||||
 | 
			
		||||
  override def replaceOverride(in: String): String = {
 | 
			
		||||
    val next = replaceProperty("http_port1", 8081, in)
 | 
			
		||||
    super.replaceOverride(next)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private val httpForReplica = http.basicAuth(
 | 
			
		||||
    conf.httpConfiguration.userName,
 | 
			
		||||
    ConfigFactory.load().getString("http.password_replica"))
 | 
			
		||||
 | 
			
		||||
  private val createChange = new CreateChange
 | 
			
		||||
  private val approveChange = new ApproveChange(createChange)
 | 
			
		||||
  private val submitChange = new SubmitChange(createChange)
 | 
			
		||||
  private val getBranch = new GetMasterBranchRevision
 | 
			
		||||
 | 
			
		||||
  private val test: ScenarioBuilder = scenario(unique)
 | 
			
		||||
      .feed(data)
 | 
			
		||||
      .exec(session => {
 | 
			
		||||
        session.set(getBranch.revisionKey, getBranch.revision.get)
 | 
			
		||||
      })
 | 
			
		||||
      .exec(http(unique).get("${url}")
 | 
			
		||||
          .check(regex(getBranch.revisionPattern)
 | 
			
		||||
              .is(session => session(getBranch.revisionKey).as[String])))
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    createChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createChange) seconds),
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    approveChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(approveChange) seconds),
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    submitChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(submitChange) seconds),
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    getBranch.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(getBranch) seconds),
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ).protocols(httpForReplica),
 | 
			
		||||
  ).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
@@ -42,6 +42,6 @@ class CheckProjectsCacheFlushEntries extends CacheFlushSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,15 +39,15 @@ class CloneUsingBothProtocols extends GitSimulation {
 | 
			
		||||
  setUp(
 | 
			
		||||
    createProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
      constantUsersPerSec(1) during (duration seconds)
 | 
			
		||||
      constantUsersPerSec(single) during (duration seconds)
 | 
			
		||||
    ),
 | 
			
		||||
    deleteProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(deleteProject) + duration seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
  ).protocols(gitProtocol, httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,19 +50,19 @@ class CreateChange extends ProjectSimulation {
 | 
			
		||||
  setUp(
 | 
			
		||||
    createProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    deleteChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(deleteChange) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    deleteProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(deleteProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
  ).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,6 @@ class CreateProject extends ProjectSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,6 @@ class DeleteChange extends GerritSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,6 @@ class DeleteProject extends ProjectSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,23 +38,23 @@ class FlushProjectsCache extends CacheFlushSimulation {
 | 
			
		||||
  setUp(
 | 
			
		||||
    createProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    getCacheEntriesAfterProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(getCacheEntriesAfterProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    flushCache.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    checkCacheEntriesAfterFlush.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(checkCacheEntriesAfterFlush) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    deleteProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(deleteProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
  ).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ class GerritSimulation extends Simulation {
 | 
			
		||||
  protected val resource: String = s"$pathName.json"
 | 
			
		||||
  protected val body: String = s"$pathName-body.json"
 | 
			
		||||
  protected val unique: String = name + "-" + this.hashCode()
 | 
			
		||||
  protected val single = 1
 | 
			
		||||
 | 
			
		||||
  private val powerFactor: Double = replaceProperty("power_factor", 1.0).toDouble
 | 
			
		||||
  protected val SecondsPerWeightUnit: Int = 2
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
// Copyright (C) 2020 The Android Open Source Project
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
// http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package com.google.gerrit.scenarios
 | 
			
		||||
 | 
			
		||||
import io.gatling.core.Predef._
 | 
			
		||||
import io.gatling.core.feeder.FeederBuilder
 | 
			
		||||
import io.gatling.core.structure.ScenarioBuilder
 | 
			
		||||
import io.gatling.http.Predef._
 | 
			
		||||
 | 
			
		||||
class GetMasterBranchRevision extends ProjectSimulation {
 | 
			
		||||
  private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
 | 
			
		||||
  var revision: Option[String] = None
 | 
			
		||||
  val revisionKey = "revision"
 | 
			
		||||
  val revisionPattern: String = "\"" + revisionKey + "\": \"(.+)\""
 | 
			
		||||
 | 
			
		||||
  val test: ScenarioBuilder = scenario(unique)
 | 
			
		||||
      .feed(data)
 | 
			
		||||
      .exec(http(unique).get("${url}")
 | 
			
		||||
          .check(regex(revisionPattern).saveAs(revisionKey)))
 | 
			
		||||
      .exec(session => {
 | 
			
		||||
        revision = Some(session(revisionKey).as[String])
 | 
			
		||||
        session
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
@@ -40,6 +40,6 @@ class GetProjectsCacheEntries extends CacheFlushSimulation {
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    test.inject(
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    )).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ class ReplayRecordsFromFeeder extends GitSimulation {
 | 
			
		||||
  setUp(
 | 
			
		||||
    createProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
@@ -54,7 +54,7 @@ class ReplayRecordsFromFeeder extends GitSimulation {
 | 
			
		||||
    ),
 | 
			
		||||
    deleteProject.test.inject(
 | 
			
		||||
      nothingFor(maxBeforeDelete seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
  ).protocols(gitProtocol, httpProtocol)
 | 
			
		||||
      .maxDuration(maxExecutionTime seconds)
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,16 @@ import scala.concurrent.duration._
 | 
			
		||||
class SubmitChange extends GerritSimulation {
 | 
			
		||||
  private val data: FeederBuilder = jsonFile(resource).convert(keys).queue
 | 
			
		||||
  private val default: String = name
 | 
			
		||||
  private var createChange = new CreateChange(default)
 | 
			
		||||
 | 
			
		||||
  private val test: ScenarioBuilder = scenario(unique)
 | 
			
		||||
  override def relativeRuntimeWeight = 10
 | 
			
		||||
 | 
			
		||||
  def this(createChange: CreateChange) {
 | 
			
		||||
    this()
 | 
			
		||||
    this.createChange = createChange
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  val test: ScenarioBuilder = scenario(unique)
 | 
			
		||||
      .feed(data)
 | 
			
		||||
      .exec(session => {
 | 
			
		||||
        session.set("number", createChange.number)
 | 
			
		||||
@@ -33,30 +41,29 @@ class SubmitChange extends GerritSimulation {
 | 
			
		||||
      .exec(http(unique).post("${url}${number}/submit"))
 | 
			
		||||
 | 
			
		||||
  private val createProject = new CreateProject(default)
 | 
			
		||||
  private val createChange = new CreateChange(default)
 | 
			
		||||
  private val approveChange = new ApproveChange(createChange)
 | 
			
		||||
  private val deleteProject = new DeleteProject(default)
 | 
			
		||||
 | 
			
		||||
  setUp(
 | 
			
		||||
    createProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    createChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(createChange) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    approveChange.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(approveChange) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(this) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
    deleteProject.test.inject(
 | 
			
		||||
      nothingFor(stepWaitTime(deleteProject) seconds),
 | 
			
		||||
      atOnceUsers(1)
 | 
			
		||||
      atOnceUsers(single)
 | 
			
		||||
    ),
 | 
			
		||||
  ).protocols(httpProtocol)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user