e2e-tests: Pick then squash commits from stable-3.1

Back-port the whole e2e tests framework [1,2,3] downstream this way.

[1] new file: ./Documentation/dev-e2e-tests.txt
[2] modified: ./Documentation/dev-readme.txt
[3] new directory: ./e2e-tests

This is an orthogonal change, beside [2] which needed a few yet trivial
conflict resolutions. Below is the included git commits log, from the
interactive rebase todo list used:

* stable-3.1:
  f52c1ad01d e2e-tests: Document how to handle eviction warning
  4b5cddb5fe e2e-tests: Enable postfix operators with compiler
  4702984026 e2e-tests: Update Dockerfile gatling_git_version to 1.0.10
  ea5e616c8d e2e-tests: Align gatling version with gatling-git
  189030f3d5 e2e-tests: Introduce reused gatling version constant
  32e5b7887f e2e-tests: Rename the now reused json filename constant
  11e9026203 e2e-tests: Refactor documentation about functional
  15e1fd634a e2e-tests: Move core json files into scala package
  048dd3dd65 e2e-tests: Support adding/running non-core scenarios
  a8b7b7cff6 e2e-tests: Add create/delete project to CloneUsingBothProtocols
  4217eaff29 e2e-tests: Collapse the load-tests directory level
  f230d8c036 e2e-tests: Mention http credentials in documentation
  3cf119b25f e2e-tests: Make scenarios extend new GitSimulation
  1fd49ed118 e2e-tests: Mention the blog post in documentation
  5379c64da2 CloneUsingBothProtocols: Align closing parenthesis
  27e8680900 ReplayRecordsFromFeeder: Refactor the after method
  de76095532 ReplayRecordsFromFeeder: Align scenario building
  67955ae29e ReplayRecordsFromFeeder: Extract request to value
  cdd104937b ReplayRecordsFromFeeder: Un-hardcode json filename
  5cccbf9926 ReplayRecordsFromFeeder: Group implicit val at top
  b9d1f5af7c ReplayRecordsFromFeeder: Fix braces/parentheses warnings
  42536a4515 ReplayRecordsFromFeeder: Add type to public member
  ece535a703 e2e-tests: Rename ReplayRecordsFromFeeder scenario
  41db8e5397 e2e-tests: Reformat ReplayRecordsFromFeeder.scala
  e3612e35f0 e2e-tests: Upgrade sbt to 1.3.7
  c122b41ad4 e2e-tests: Introduce example to test local setups
  9fa0d98bac e2e-tests: Foster IntelliJ for Scala and build.sbt
  70a4f4dc54 e2e-tests: Sort and update some .gitignore entries
  d06498a489 e2e-tests: Expand ssh key generation documentation
  946d74eda4 e2e-tests: Document example test project existence
  4d3f2143a9 e2e-tests: Remove the note after sbt website fixed
  eca5aaab23 e2e-tests: Add support for log level configuration
  e4fae5e270 e2e-tests: Fix the documentation Table of Contents
  db44d3637d Documentation: Add e2e tests link from dev-readme
  44f259d016 e2e-tests: Move docker doc to Documentation page
  b810f6391d e2e-tests: Tell how to remove sbt credentials warning
  b867ba94d0 Dockerise Gatling tests
  b29a293963 Documentation: Fix dev-e2e-tests link text styling
  6c3e4691a8 Documentation: Fix dev-e2e-tests line length to <100
  cb7f03e79e Documentation: Fix e2e tests Input section's nits
  72f40513d1 Documentation: Fix e2e tests Setup link and typos
  1f9465bd4a Documentation: Un-hardcode the Scala version used
  386aebbe51 E2E load tests example scenarios

Change-Id: I66627d79aa46d593c348bbcb57bd30d8b41a91d4
This commit is contained in:
Fabio Ponciroli
2019-05-21 20:30:41 -07:00
committed by Marco Miller
parent 9eb0d7636e
commit e224456be4
24 changed files with 775 additions and 0 deletions

View 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]:

View File

@@ -123,6 +123,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
View 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
View 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
View 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

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

View File

@@ -0,0 +1 @@
sbt.version=1.3.7

View File

@@ -0,0 +1 @@
addSbtPlugin("io.gatling" % "gatling-sbt" % "3.0.0")

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

View File

@@ -0,0 +1,4 @@
*
!*/
!/com/google/gerrit/scenarios/*
!/.gitignore

View File

@@ -0,0 +1,10 @@
[
{
"url": "ssh://admin@localhost:29418/loadtest-repo",
"cmd": "clone"
},
{
"url": "http://localhost:8080/loadtest-repo",
"cmd": "clone"
}
]

View File

@@ -0,0 +1,5 @@
[
{
"url": "http://localhost:8080/a/projects/loadtest-repo"
}
]

View File

@@ -0,0 +1,5 @@
[
{
"url": "http://localhost:8080/a/projects/loadtest-repo/delete-project~delete"
}
]

View File

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

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

View 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"

View 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
View File

@@ -0,0 +1,4 @@
*
!*/
!/com/google/gerrit/scenarios/*
!/.gitignore

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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