Merge branch 'stable-2.16' into stable-3.0
* stable-2.16: e2e-tests: Pick then squash commits from stable-3.1 Change-Id: I6c85941e0b3281b2688722f480b8101db406e670
This commit is contained in:
198
Documentation/dev-e2e-tests.txt
Normal file
198
Documentation/dev-e2e-tests.txt
Normal file
@@ -0,0 +1,198 @@
|
||||
= Gerrit Code Review - End to end tests
|
||||
|
||||
This document provides descriptions of Gerrit end-to-end (`e2e`) test scenarios implemented using
|
||||
the link:https://gatling.io/[Gatling] framework.
|
||||
|
||||
Similar scenarios have been successfully used to compare performance of different Gerrit versions
|
||||
or study the Gerrit response under different load profiles. Although mostly for load, scenarios can
|
||||
either be for link:https://gatling.io/load-testing-continuous-integration/[load or functional]
|
||||
(e2e) testing purposes. Functional scenarios may then reuse this framework and Gatling's usability
|
||||
features such as its protocols (more below) and
|
||||
link:https://en.wikipedia.org/wiki/Domain-specific_language[DSL].
|
||||
|
||||
That cross test-scope reusability applies to both Gerrit core scenarios and non-core ones, such as
|
||||
for Gerrit plugins or other potential extensions. End-to-end testing may then include scopes like
|
||||
feature integration, deployment, smoke (and load) testing. These load and functional test scopes
|
||||
should remain orthogonal to the unit and component (aka Gerrit `IT`-suffixed or `acceptance`) ones.
|
||||
The term `acceptance` though may still be coined by organizations to target e2e functional testing.
|
||||
|
||||
== What is Gatling?
|
||||
|
||||
Gatling is mostly a load testing tool which provides out of the box support for the HTTP protocol.
|
||||
Documentation on how to write an HTTP load test can be found
|
||||
link:https://gatling.io/docs/current/http/http_protocol/[here]. However, in the scenarios that were
|
||||
initially proposed, the link:https://github.com/GerritForge/gatling-git[Gatling Git extension] was
|
||||
leveraged to run tests at the Git protocol level.
|
||||
|
||||
Gatling is written in Scala, but the abstraction provided by the Gatling DSL makes the scenarios
|
||||
implementation easy even without any Scala knowledge. The
|
||||
link:https://gitenterprise.me/2019/12/20/stress-your-gerrit-with-gatling/[Stress your Gerrit with Gatling]
|
||||
blog post has more introductory information.
|
||||
|
||||
Examples of scenarios can be found in the `e2e-tests` directory. The files in that directory should
|
||||
be formatted using the mainstream
|
||||
link:https://plugins.jetbrains.com/plugin/1347-scala[Scala plugin for IntelliJ]. The latter is not
|
||||
mandatory but preferred for `sbt` and Scala IDE purposes in this project.
|
||||
|
||||
== How to build the tests
|
||||
|
||||
An link:https://www.scala-sbt.org/download.html[sbt-based installation] of
|
||||
link:https://www.scala-lang.org/download/[Scala] is required.
|
||||
|
||||
The `scalaVersion` used by `sbt` once installed is defined in the `build.sbt` file. That specific
|
||||
version of Scala is automatically used by `sbt` while building:
|
||||
|
||||
----
|
||||
sbt compile
|
||||
----
|
||||
|
||||
The following warning, if present when executing `sbt` commands, can be removed by creating the
|
||||
link:https://www.scala-sbt.org/1.x/docs/Using-Sonatype.html#step+3%3A+Credentials[related credentials file]
|
||||
locally. Dummy values for `user` and `password` in that file can be used initially.
|
||||
|
||||
----
|
||||
[warn] Credentials file ~/.sbt/sonatype_credentials does not exist
|
||||
----
|
||||
|
||||
The other warning below can be safely ignored, so far. Running the proposed `sbt evicted` command
|
||||
should only list `scala-java8-compat_2.12` as `[warn]`. The other dependency conflicts should show
|
||||
as `[info]`. All of the listed conflicts get usually resolved seamlessly or so.
|
||||
|
||||
----
|
||||
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
|
||||
----
|
||||
|
||||
Every `sbt` command can include an optional log level
|
||||
link:https://www.scala-sbt.org/1.x/docs/Howto-Logging.html#Change+the+logging+level+globally[argument].
|
||||
Below, `[info]` logs are no longer shown:
|
||||
|
||||
----
|
||||
sbt --warn compile
|
||||
----
|
||||
|
||||
=== How to build using Docker
|
||||
|
||||
----
|
||||
docker build . -t e2e-tests
|
||||
----
|
||||
|
||||
== How to set-up
|
||||
|
||||
=== SSH keys
|
||||
|
||||
If you are running SSH commands, the private keys of the users used for testing need to go in
|
||||
`/tmp/ssh-keys`. The keys need to be generated this way (JSch won't validate them
|
||||
link:https://stackoverflow.com/questions/53134212/invalid-privatekey-when-using-jsch[otherwise]):
|
||||
|
||||
----
|
||||
mkdir /tmp/ssh-keys
|
||||
ssh-keygen -m PEM -t rsa -C "test@mail.com" -f /tmp/ssh-keys/id_rsa
|
||||
----
|
||||
|
||||
The public key in `/tmp/ssh-keys/id_rsa.pub` has to be added to the test user(s) `SSH Keys` in
|
||||
Gerrit. Now, the host from which the latter runs may need public key scanning to become known.
|
||||
This applies to the local user that runs the forthcoming `sbt` testing commands. An example
|
||||
assuming `localhost` follows:
|
||||
|
||||
----
|
||||
ssh-keyscan -t rsa -p 29418 localhost > ~/.ssh/known_hosts
|
||||
----
|
||||
|
||||
=== Input file
|
||||
|
||||
The `CloneUsingBothProtocols` scenario is fed with the data coming from the
|
||||
`src/test/resources/data/com/google/gerrit/scenarios/CloneUsingBothProtocols.json` file. Such a
|
||||
file contains the commands and repository used during the e2e test. That file currently looks like
|
||||
below. This scenario serves as a simple example with no actual load in it. It can be used to test
|
||||
or validate the local setup. More complex scenarios can be further developed, under the
|
||||
`com.google.gerrit.scenarios` package.
|
||||
|
||||
----
|
||||
[
|
||||
{
|
||||
"url": "ssh://admin@localhost:29418/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8080/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
}
|
||||
]
|
||||
----
|
||||
|
||||
Valid commands are:
|
||||
|
||||
* `clone`
|
||||
* `fetch`
|
||||
* `pull`
|
||||
* `push`
|
||||
|
||||
=== Project and HTTP credentials
|
||||
|
||||
The example above assumes that the `loadtest-repo` project exists in the Gerrit under test. The
|
||||
`CloneUsingBothProtocols` scenario already includes creating that project and deleting it once done
|
||||
with it. That scenario class can be used as an example of how a scenario can compose itself
|
||||
alongside other scenarios (here, `CreateProject` and `DeleteProject`).
|
||||
|
||||
The `HTTP Credentials` or password obtained from test user's `Settings` (in Gerrit) may be
|
||||
required, in `src/test/resources/application.conf`, depending on the above commands used. That
|
||||
file's `http` section shows which shell environment variables can be used to set those credentials.
|
||||
|
||||
Executing the `CloneUsingBothProtocols` scenario, as is, does require setting the http credentials.
|
||||
That is because of the aforementioned create/delete project (http) scenarios composed within it.
|
||||
|
||||
== How to run tests
|
||||
|
||||
Run all tests:
|
||||
----
|
||||
sbt "gatling:test"
|
||||
----
|
||||
|
||||
Run a single test:
|
||||
----
|
||||
sbt "gatling:testOnly com.google.gerrit.scenarios.CloneUsingBothProtocols"
|
||||
----
|
||||
|
||||
Generate the last report:
|
||||
----
|
||||
sbt "gatling:lastReport"
|
||||
----
|
||||
|
||||
The `src/test/resources/logback.xml` file
|
||||
link:http://logback.qos.ch/manual/configuration.html[configures] Gatling's logging level.
|
||||
|
||||
=== How to run using Docker
|
||||
|
||||
----
|
||||
docker run -it e2e-tests -s com.google.gerrit.scenarios.CloneUsingBothProtocols
|
||||
----
|
||||
|
||||
=== How to run non-core scenarios
|
||||
|
||||
Locally adding non-core scenarios, for example from Gerrit plugins, is as simple as copying such
|
||||
files in. Copying is necessary over linking, unless running using Docker (above) is not required.
|
||||
Docker does not support links for files it has to copy over through the Dockerfile (here, the
|
||||
scenario files). Here is how to proceed for adding such external (e.g., plugin) scenario files in:
|
||||
|
||||
----
|
||||
pushd e2e-tests/src/test/scala
|
||||
cp -r (or, ln -s) scalaPackageStructure .
|
||||
popd
|
||||
|
||||
pushd e2e-tests/src/test/resources/data
|
||||
cp -r (or, ln -s) jsonFilesPackageStructure .
|
||||
popd
|
||||
----
|
||||
|
||||
The destination folders above readily git-ignore every non-core scenario file added under them. If
|
||||
running using Docker, `e2e-tests/Dockerfile` may require another `COPY` line for the hereby added
|
||||
scenarios. Aforementioned `sbt` or `docker` commands can then be used to run the added tests.
|
||||
|
||||
GERRIT
|
||||
------
|
||||
Part of link:index.html[Gerrit Code Review]
|
||||
|
||||
SEARCHBOX
|
||||
---------
|
||||
|
||||
[scala]:
|
||||
@@ -124,6 +124,12 @@ shut down.
|
||||
For instructions on running the acceptance tests with Bazel,
|
||||
see <<dev-bazel#tests,Running Unit Tests with Bazel>>.
|
||||
|
||||
[[e2e]]
|
||||
=== End-to-end tests
|
||||
|
||||
<<dev-e2e-tests#,This document>> describes how `e2e` (load or functional) test
|
||||
scenarios are implemented using link:https://gatling.io/[`Gatling`].
|
||||
|
||||
[[run_daemon]]
|
||||
=== Running the Daemon
|
||||
|
||||
|
||||
13
e2e-tests/.gitignore
vendored
Normal file
13
e2e-tests/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/.idea/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
/.idea_modules/
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# Scala sbt
|
||||
target/
|
||||
32
e2e-tests/Dockerfile
Normal file
32
e2e-tests/Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM denvazh/gatling:3.2.1
|
||||
|
||||
ARG gatling_git_version=1.0.10
|
||||
RUN apk add --no-cache maven
|
||||
RUN mvn dependency:get \
|
||||
-DgroupId=com.gerritforge \
|
||||
-DartifactId=gatling-git_2.12 \
|
||||
-Dversion=$gatling_git_version \
|
||||
-Dtype=pom
|
||||
RUN mvn dependency:copy-dependencies \
|
||||
-f /root/.m2/repository/com/gerritforge/gatling-git_2.12/$gatling_git_version/gatling-git_2.12-$gatling_git_version.pom \
|
||||
-DoutputDirectory=/opt/gatling/lib/
|
||||
RUN mvn dependency:get \
|
||||
-Dartifact=com.gerritforge:gatling-git_2.12:$gatling_git_version:jar \
|
||||
-Ddest=/opt/gatling/lib/gatling-git.jar
|
||||
|
||||
ARG gatling_home=/home/gatling
|
||||
RUN addgroup -g 1000 -S appgroup && \
|
||||
adduser -u 1000 -S gatling -G appgroup -h $gatling_home
|
||||
RUN cp -R /opt/gatling/* $gatling_home && \
|
||||
chown -R gatling:appgroup $gatling_home
|
||||
|
||||
WORKDIR $gatling_home
|
||||
USER gatling
|
||||
|
||||
COPY ./src/test/scala/com/google/gerrit/scenarios $gatling_home/user-files/simulations
|
||||
COPY ./src/test/resources/application.conf $gatling_home/conf
|
||||
COPY ./src/test/resources/data $gatling_home/user-files/resources/data
|
||||
|
||||
ENV GATLING_HOME=$gatling_home
|
||||
|
||||
ENTRYPOINT ["/home/gatling/bin/gatling.sh"]
|
||||
19
e2e-tests/build.sbt
Normal file
19
e2e-tests/build.sbt
Normal file
@@ -0,0 +1,19 @@
|
||||
import Dependencies._
|
||||
|
||||
enablePlugins(GatlingPlugin)
|
||||
|
||||
lazy val gatlingGitExtension = RootProject(uri("git://github.com/GerritForge/gatling-git.git"))
|
||||
lazy val root = (project in file("."))
|
||||
.settings(
|
||||
inThisBuild(List(
|
||||
organization := "com.google.gerrit",
|
||||
scalaVersion := "2.12.8",
|
||||
version := "0.1.0-SNAPSHOT"
|
||||
)),
|
||||
name := "gerrit",
|
||||
libraryDependencies ++=
|
||||
gatling ++
|
||||
Seq("io.gatling" % "gatling-core" % GatlingVersion) ++
|
||||
Seq("io.gatling" % "gatling-app" % GatlingVersion),
|
||||
scalacOptions += "-language:postfixOps"
|
||||
) dependsOn gatlingGitExtension
|
||||
10
e2e-tests/project/Dependencies.scala
Normal file
10
e2e-tests/project/Dependencies.scala
Normal file
@@ -0,0 +1,10 @@
|
||||
import sbt._
|
||||
|
||||
object Dependencies {
|
||||
val GatlingVersion = "3.2.0"
|
||||
|
||||
lazy val gatling = Seq(
|
||||
"io.gatling.highcharts" % "gatling-charts-highcharts",
|
||||
"io.gatling" % "gatling-test-framework",
|
||||
).map(_ % GatlingVersion % Test)
|
||||
}
|
||||
1
e2e-tests/project/build.properties
Normal file
1
e2e-tests/project/build.properties
Normal file
@@ -0,0 +1 @@
|
||||
sbt.version=1.3.7
|
||||
1
e2e-tests/project/plugins.sbt
Normal file
1
e2e-tests/project/plugins.sbt
Normal file
@@ -0,0 +1 @@
|
||||
addSbtPlugin("io.gatling" % "gatling-sbt" % "3.0.0")
|
||||
30
e2e-tests/src/test/resources/application.conf
Normal file
30
e2e-tests/src/test/resources/application.conf
Normal file
@@ -0,0 +1,30 @@
|
||||
http {
|
||||
username: "default_username",
|
||||
username: ${?GIT_HTTP_USERNAME},
|
||||
|
||||
password: "default_password",
|
||||
password: ${?GIT_HTTP_PASSWORD},
|
||||
}
|
||||
|
||||
ssh {
|
||||
private_key_path: "/tmp/ssh-keys/id_rsa",
|
||||
private_key_path: ${?GIT_SSH_PRIVATE_KEY_PATH},
|
||||
}
|
||||
|
||||
tmpFiles {
|
||||
basePath: "/tmp"
|
||||
basePath: ${?TMP_BASE_PATH}
|
||||
}
|
||||
|
||||
commands {
|
||||
push {
|
||||
numFiles: 4
|
||||
numFiles: ${?NUM_FILES}
|
||||
minContentLength: 100
|
||||
minContentLength: ${?MIN_CONTENT_LEGTH}
|
||||
maxContentLength: 10000
|
||||
maxContentLength: ${?MAX_CONTENT_LEGTH}
|
||||
commitPrefix: ""
|
||||
commitPrefix: ${?COMMIT_PREFIX}
|
||||
}
|
||||
}
|
||||
4
e2e-tests/src/test/resources/data/.gitignore
vendored
Normal file
4
e2e-tests/src/test/resources/data/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!*/
|
||||
!/com/google/gerrit/scenarios/*
|
||||
!/.gitignore
|
||||
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"url": "ssh://admin@localhost:29418/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8080/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"url": "http://localhost:8080/a/projects/loadtest-repo"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
[
|
||||
{
|
||||
"url": "http://localhost:8080/a/projects/loadtest-repo/delete-project~delete"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"url": "ssh://admin@localhost:29418/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
},
|
||||
{
|
||||
"url": "ssh://admin@localhost:29418/loadtest-repo",
|
||||
"cmd": "pull"
|
||||
},
|
||||
{
|
||||
"url": "ssh://admin@localhost:29418/loadtest-repo",
|
||||
"cmd": "push"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8080/loadtest-repo",
|
||||
"cmd": "clone"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8080/loadtest-repo",
|
||||
"cmd": "pull"
|
||||
},
|
||||
{
|
||||
"url": "http://localhost:8080/loadtest-repo",
|
||||
"cmd": "push"
|
||||
}
|
||||
]
|
||||
128
e2e-tests/src/test/resources/gatling.conf
Normal file
128
e2e-tests/src/test/resources/gatling.conf
Normal file
@@ -0,0 +1,128 @@
|
||||
#########################
|
||||
# Gatling Configuration #
|
||||
#########################
|
||||
|
||||
# This file contains all the settings configurable for Gatling with their default values
|
||||
|
||||
gatling {
|
||||
core {
|
||||
#outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp)
|
||||
#runDescription = "" # The description for this simulation run, displayed in each report
|
||||
#encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation
|
||||
#simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated)
|
||||
#elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable
|
||||
#rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable
|
||||
#rawFileBodiesInMemoryMaxSize = 1000 # Below this limit, raw file bodies will be cached in memory
|
||||
#pebbleFileBodiesCacheMaxCapacity = 200 # Cache size for request body Peeble templates, set to 0 to disable
|
||||
#shutdownTimeout = 5000 # Milliseconds to wait for the actor system to shutdown
|
||||
extract {
|
||||
regex {
|
||||
#cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching
|
||||
}
|
||||
xpath {
|
||||
#cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching
|
||||
}
|
||||
jsonPath {
|
||||
#cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching
|
||||
#preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations
|
||||
}
|
||||
css {
|
||||
#cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching
|
||||
}
|
||||
}
|
||||
directory {
|
||||
simulations = "./src/test/scala"
|
||||
#simulations = user-files/simulations # Directory where simulation classes are located (for bundle packaging only)
|
||||
resources = "./src/test/resources/data" # Directory where resources, such as feeder files and request bodies are located (for bundle packaging only)
|
||||
#reportsOnly = "" # If set, name of report folder to look for in order to generate its report
|
||||
binaries = "./target/scala-2.12/classes" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target.
|
||||
#results = results # Name of the folder where all reports folder are located
|
||||
}
|
||||
}
|
||||
charting {
|
||||
#noReports = false # When set to true, don't generate HTML reports
|
||||
#maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports
|
||||
#useGroupDurationMetric = false # Switch group timings from cumulated response time to group duration.
|
||||
indicators {
|
||||
#lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary
|
||||
#higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary
|
||||
#percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and Graphite
|
||||
#percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and Graphite
|
||||
#percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and Graphite
|
||||
#percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and Graphite
|
||||
}
|
||||
}
|
||||
http {
|
||||
#fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable
|
||||
#fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable
|
||||
#perUserCacheMaxCapacity = 200 # Per virtual user cache size, set to 0 to disable
|
||||
#warmUpUrl = "https://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled)
|
||||
#enableGA = true # Very light Google Analytics, please support
|
||||
ssl {
|
||||
keyStore {
|
||||
#type = "" # Type of SSLContext's KeyManagers store
|
||||
#file = "" # Location of SSLContext's KeyManagers store
|
||||
#password = "" # Password for SSLContext's KeyManagers store
|
||||
#algorithm = "" # Algorithm used SSLContext's KeyManagers store
|
||||
}
|
||||
trustStore {
|
||||
#type = "" # Type of SSLContext's TrustManagers store
|
||||
#file = "" # Location of SSLContext's TrustManagers store
|
||||
#password = "" # Password for SSLContext's TrustManagers store
|
||||
#algorithm = "" # Algorithm used by SSLContext's TrustManagers store
|
||||
}
|
||||
}
|
||||
ahc {
|
||||
#connectTimeout = 10000 # Timeout in millis for establishing a TCP socket
|
||||
#handshakeTimeout = 10000 # Timeout in millis for performing TLS handshake
|
||||
#pooledConnectionIdleTimeout = 60000 # Timeout in millis for a connection to stay idle in the pool
|
||||
#maxRetry = 2 # Number of times that a request should be tried again
|
||||
#requestTimeout = 60000 # Timeout in millis for performing an HTTP request
|
||||
#enableSni = true # When set to true, enable Server Name indication (SNI)
|
||||
#enableHostnameVerification = false # When set to true, enable hostname verification: SSLEngine.setHttpsEndpointIdentificationAlgorithm("HTTPS")
|
||||
#useInsecureTrustManager = true # Use an insecure TrustManager that trusts all server certificates
|
||||
#filterInsecureCipherSuites = true # Turn to false to not filter out insecure and weak cipher suites
|
||||
#sslEnabledProtocols = [TLSv1.2, TLSv1.1, TLSv1] # Array of enabled protocols for HTTPS, if empty use the JDK defaults
|
||||
#sslEnabledCipherSuites = [] # Array of enabled cipher suites for HTTPS, if empty use the AHC defaults
|
||||
#sslSessionCacheSize = 0 # SSLSession cache size, set to 0 to use JDK's default
|
||||
#sslSessionTimeout = 0 # SSLSession timeout in seconds, set to 0 to use JDK's default (24h)
|
||||
#disableSslSessionResumption = false # if true, SSLSessions won't be resumed
|
||||
#useOpenSsl = true # if OpenSSL should be used instead of JSSE
|
||||
#useNativeTransport = false # if native transport should be used instead of Java NIO (requires netty-transport-native-epoll, currently Linux only)
|
||||
#enableZeroCopy = true # if zero-copy upload should be used if possible
|
||||
#tcpNoDelay = true
|
||||
#soReuseAddress = false
|
||||
#allocator = "pooled" # switch to unpooled for unpooled ByteBufAllocator
|
||||
#maxThreadLocalCharBufferSize = 200000 # Netty's default is 16k
|
||||
}
|
||||
dns {
|
||||
#queryTimeout = 5000 # Timeout in millis of each DNS query in millis
|
||||
#maxQueriesPerResolve = 6 # Maximum allowed number of DNS queries for a given name resolution
|
||||
}
|
||||
}
|
||||
jms {
|
||||
#replyTimeoutScanPeriod = 1000 # scan period for timedout reply messages
|
||||
}
|
||||
data {
|
||||
#writers = [console, file] # The list of DataWriters to which Gatling write simulation data (currently supported : console, file, graphite, jdbc)
|
||||
console {
|
||||
#light = false # When set to true, displays a light version without detailed request stats
|
||||
#writePeriod = 5 # Write interval, in seconds
|
||||
}
|
||||
file {
|
||||
#bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes
|
||||
}
|
||||
leak {
|
||||
#noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening
|
||||
}
|
||||
graphite {
|
||||
#light = false # only send the all* stats
|
||||
#host = "localhost" # The host where the Carbon server is located
|
||||
#port = 2003 # The port to which the Carbon server listens to (2003 is default for plaintext, 2004 is default for pickle)
|
||||
#protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp")
|
||||
#rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite
|
||||
#bufferSize = 8192 # Internal data buffer size, in bytes
|
||||
#writePeriod = 1 # Write period, in seconds
|
||||
}
|
||||
}
|
||||
}
|
||||
43
e2e-tests/src/test/resources/hooks/commit-msg
Normal file
43
e2e-tests/src/test/resources/hooks/commit-msg
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
|
||||
#
|
||||
# Copyright (C) 2009 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.
|
||||
|
||||
# avoid [[ which is not POSIX sh.
|
||||
if test "$#" != 1 ; then
|
||||
echo "$0 requires an argument."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -f "$1" ; then
|
||||
echo "file does not exist: $1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test ! -s "$1" ; then
|
||||
echo "file is empty: $1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# $RANDOM will be undefined if not using bash, so don't use set -u
|
||||
random=$( (whoami ; hostname ; date; cat $1 ; echo $RANDOM) | git hash-object --stdin)
|
||||
dest="$1.tmp.${random}"
|
||||
|
||||
# Avoid the --in-place option which only appeared in Git 2.8
|
||||
# Avoid the --if-exists option which only appeared in Git 2.15
|
||||
cat "$1" \
|
||||
| git -c trailer.ifexists=doNothing interpret-trailers --trailer "Change-Id: I${random}" > "${dest}" \
|
||||
&& mv "${dest}" "$1"
|
||||
12
e2e-tests/src/test/resources/logback.xml
Normal file
12
e2e-tests/src/test/resources/logback.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="warn">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</root>
|
||||
</configuration>
|
||||
4
e2e-tests/src/test/scala/.gitignore
vendored
Normal file
4
e2e-tests/src/test/scala/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*
|
||||
!*/
|
||||
!/com/google/gerrit/scenarios/*
|
||||
!/.gitignore
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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.FileBasedFeederBuilder
|
||||
import io.gatling.core.structure.ScenarioBuilder
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class CloneUsingBothProtocols extends GitSimulation {
|
||||
private val data: FileBasedFeederBuilder[Any]#F = jsonFile(resource).queue
|
||||
|
||||
private val test: ScenarioBuilder = scenario(name)
|
||||
.feed(data)
|
||||
.exec(gitRequest)
|
||||
|
||||
private val createProject = new CreateProject
|
||||
private val deleteProject = new DeleteProject
|
||||
|
||||
setUp(
|
||||
createProject.test.inject(
|
||||
atOnceUsers(1)
|
||||
),
|
||||
test.inject(
|
||||
nothingFor(1 second),
|
||||
constantUsersPerSec(1) during (2 seconds)
|
||||
),
|
||||
deleteProject.test.inject(
|
||||
nothingFor(3 second),
|
||||
atOnceUsers(1)
|
||||
),
|
||||
).protocols(gitProtocol, httpProtocol)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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.FileBasedFeederBuilder
|
||||
import io.gatling.core.structure.ScenarioBuilder
|
||||
|
||||
class CreateProject extends GerritSimulation {
|
||||
private val data: FileBasedFeederBuilder[Any]#F = jsonFile(resource).queue
|
||||
|
||||
val test: ScenarioBuilder = scenario(name)
|
||||
.feed(data)
|
||||
.exec(httpRequest)
|
||||
|
||||
setUp(
|
||||
test.inject(
|
||||
atOnceUsers(1)
|
||||
)).protocols(httpProtocol)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// 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.FileBasedFeederBuilder
|
||||
import io.gatling.core.structure.ScenarioBuilder
|
||||
|
||||
class DeleteProject extends GerritSimulation {
|
||||
private val data: FileBasedFeederBuilder[Any]#F = jsonFile(resource).queue
|
||||
|
||||
val test: ScenarioBuilder = scenario(name)
|
||||
.feed(data)
|
||||
.exec(httpRequest)
|
||||
|
||||
setUp(
|
||||
test.inject(
|
||||
atOnceUsers(1)
|
||||
)).protocols(httpProtocol)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.github.barbasa.gatling.git.GatlingGitConfiguration
|
||||
import io.gatling.core.Predef._
|
||||
import io.gatling.http.Predef.http
|
||||
import io.gatling.http.protocol.HttpProtocolBuilder
|
||||
import io.gatling.http.request.builder.HttpRequestBuilder
|
||||
|
||||
class GerritSimulation extends Simulation {
|
||||
implicit val conf: GatlingGitConfiguration = GatlingGitConfiguration()
|
||||
|
||||
private val path: String = this.getClass.getPackage.getName.replaceAllLiterally(".", "/")
|
||||
protected val name: String = this.getClass.getSimpleName
|
||||
protected val resource: String = s"data/$path/$name.json"
|
||||
|
||||
protected val httpRequest: HttpRequestBuilder = http(name).post("${url}")
|
||||
protected val httpProtocol: HttpProtocolBuilder = http.basicAuth(
|
||||
conf.httpConfiguration.userName,
|
||||
conf.httpConfiguration.password)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// 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 java.io.{File, IOException}
|
||||
|
||||
import com.github.barbasa.gatling.git.GitRequestSession
|
||||
import com.github.barbasa.gatling.git.protocol.GitProtocol
|
||||
import com.github.barbasa.gatling.git.request.builder.GitRequestBuilder
|
||||
import io.gatling.core.Predef._
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.eclipse.jgit.hooks.CommitMsgHook
|
||||
|
||||
class GitSimulation extends GerritSimulation {
|
||||
implicit val postMessageHook: Option[String] = Some(s"hooks/${CommitMsgHook.NAME}")
|
||||
|
||||
protected val gitRequest = new GitRequestBuilder(GitRequestSession("${cmd}", "${url}"))
|
||||
protected val gitProtocol: GitProtocol = GitProtocol()
|
||||
|
||||
after {
|
||||
Thread.sleep(5000)
|
||||
val path = conf.tmpBasePath
|
||||
try {
|
||||
FileUtils.deleteDirectory(new File(path))
|
||||
} catch {
|
||||
case e: IOException =>
|
||||
System.err.println("Unable to delete temporary directory " + path)
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2019 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.FileBasedFeederBuilder
|
||||
import io.gatling.core.structure.ScenarioBuilder
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class ReplayRecordsFromFeeder extends GitSimulation {
|
||||
private val data: FileBasedFeederBuilder[Any]#F = jsonFile(resource).circular
|
||||
|
||||
private val test: ScenarioBuilder = scenario(name)
|
||||
.repeat(10000) {
|
||||
feed(data)
|
||||
.exec(gitRequest)
|
||||
}
|
||||
|
||||
setUp(
|
||||
test.inject(
|
||||
nothingFor(4 seconds),
|
||||
atOnceUsers(10),
|
||||
rampUsers(10) during (5 seconds),
|
||||
constantUsersPerSec(20) during (15 seconds),
|
||||
constantUsersPerSec(20) during (15 seconds) randomized
|
||||
)).protocols(gitProtocol)
|
||||
.maxDuration(60 seconds)
|
||||
}
|
||||
Reference in New Issue
Block a user