├── .gitignore
├── src
├── main
│ ├── resources
│ │ ├── har
│ │ │ └── readme.txt
│ │ └── config
│ │ │ ├── recorder.conf
│ │ │ └── gatling-recorder.properties
│ └── scala
│ │ └── nl
│ │ └── jpoint
│ │ └── gatling
│ │ ├── GatlingProperties.scala
│ │ ├── PathHelper.scala
│ │ └── GatlingRecorderWrapper.scala
└── test
│ ├── scala
│ └── simulations
│ │ ├── readme.txt
│ │ └── GoogleSimulation.scala
│ ├── resources
│ ├── request-bodies
│ │ └── readme.txt
│ ├── gatling-akka.conf
│ ├── logback-test.xml
│ └── gatling.conf
│ └── readme.txt
├── README.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .idea/*
3 | target/
--------------------------------------------------------------------------------
/src/main/resources/har/readme.txt:
--------------------------------------------------------------------------------
1 | Put exported HAR files here.
--------------------------------------------------------------------------------
/src/test/scala/simulations/readme.txt:
--------------------------------------------------------------------------------
1 | Put generated simulations here.
--------------------------------------------------------------------------------
/src/test/resources/request-bodies/readme.txt:
--------------------------------------------------------------------------------
1 | Put recorded request bodies here.
--------------------------------------------------------------------------------
/src/main/resources/config/recorder.conf:
--------------------------------------------------------------------------------
1 | // empty config file, necessary to start the recorder.
--------------------------------------------------------------------------------
/src/test/readme.txt:
--------------------------------------------------------------------------------
1 | This folder contains generated performance tests: the Gatling Scala DSL and accompanying request bodies (for PUT and POSTS requests).
--------------------------------------------------------------------------------
/src/main/resources/config/gatling-recorder.properties:
--------------------------------------------------------------------------------
1 | har=www.google.nl.har
2 | recorderWhiteList=(.*)www\\.google\\.nl(.+)
3 | simulationClassName=MyFirstGatlingSimulation
4 |
--------------------------------------------------------------------------------
/src/main/scala/nl/jpoint/gatling/GatlingProperties.scala:
--------------------------------------------------------------------------------
1 | package nl.jpoint.gatling
2 |
3 | object GatlingProperties {
4 | val SIMULATION_CLASS_NAME: String = "simulationClassName"
5 | val RECORDER_WHITE_LIST: String = "recorderWhiteList"
6 | }
7 |
--------------------------------------------------------------------------------
/src/test/resources/gatling-akka.conf:
--------------------------------------------------------------------------------
1 | akka {
2 | #loggers = ["akka.event.slf4j.Slf4jLogger"]
3 | #logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
4 | #log-dead-letters = off
5 | actor {
6 | default-dispatcher {
7 | #throughput = 20
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/test/scala/simulations/GoogleSimulation.scala:
--------------------------------------------------------------------------------
1 | package simulations
2 |
3 | import io.gatling.core.Predef._
4 | import io.gatling.http.Predef._
5 | import scala.concurrent.duration._
6 |
7 | class GoogleSimulation extends Simulation {
8 |
9 | val httpProtocol = http.baseUrl("https://www.google.nl").userAgentHeader("test")
10 |
11 | val myFirstScenario = scenario("Google search")
12 | .exec(
13 | http("Open the Google start page.")
14 | .get("/")
15 | .check(status.is(200))
16 | )
17 | .pause(1)
18 | .exec(
19 | http("Perform Google search on 'gatling'.")
20 | .get("/search?q=gatling")
21 | .check(status.is(200))
22 | // .check( bodyString.saveAs( "RESPONSE_DATA" ) ))
23 | // .exec( session => { println("Response: " + session("RESPONSE_DATA")); session }
24 | .check(regex("
Voordat je verdergaat naar Google Zoeken"))
25 | )
26 |
27 | setUp(myFirstScenario.inject(rampUsers(1) during (5 seconds))).protocols(httpProtocol)
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | gatling-seed
2 | ==========
3 | This project is a skeleton for performance tests with Gatling and Maven. You can use it to quickly bootstrap your Gatling test setup and development environment.
4 |
5 |
6 | Getting started
7 | ---
8 | Install the following dependencies:
9 | - Java 8 (Java 7 will probably work, not tested though)
10 | - Maven 3
11 |
12 |
13 | Recording a test
14 | ---
15 | To record a test, perform the following steps:
16 | - Click through the test path in your browser
17 | - Export the request flow as HAR file: standard available in Chrome, available as plugin in Firefox through a FireBug extension: http://www.softwareishard.com/blog/netexport/
18 | - Add details of the HAR filename and simulation name in ```src/main/resources/config/gatling-recorder.json```
19 | - Generate the Gatling script: ```mvn clean scala:run```
20 | - The Gatling simulation will be generated in ```src/test/scala/simulations```. Accompanying request bodies (in case of POST/PUT requests) will be in ```src/test/resources/request-bodies```
21 |
22 | Executing a test
23 | ---
24 | To execute a test, perform:
25 | ```mvn clean gatling:test```
26 |
27 |
28 | Or, when multiple simulations present:
29 | ```mvn gatling:test -Dgatling.simulationClass=simulations.```
30 |
--------------------------------------------------------------------------------
/src/main/scala/nl/jpoint/gatling/PathHelper.scala:
--------------------------------------------------------------------------------
1 | package nl.jpoint.gatling
2 |
3 | import io.gatling.commons.shared.unstable.util.PathHelper.RichPath
4 |
5 | import java.nio.file.{Path, Paths}
6 |
7 |
8 | object PathHelper {
9 |
10 | val recorderConfUrl: Path = Paths.get(ClassLoader.getSystemResource("config/recorder.conf").toURI)
11 | val projectRootDir = recorderConfUrl.ancestor(4)
12 | val mavenTargetDirectory = projectRootDir / "target"
13 | val recorderOutputPath = mavenTargetDirectory / "recorder-output"
14 | val simulationOutputFolder = (recorderOutputPath / "simulations").toString
15 | val simulationRequestBodiesFolder = (recorderOutputPath / "bodies").toString
16 | val mavenSourcesDirectory = projectRootDir / "src" / "main" / "scala"
17 | val mavenTestSourcesDirectory = projectRootDir / "src" / "test" / "scala"
18 | val mavenResourcesDirectory = projectRootDir / "src" / "main" / "resources"
19 | val mavenTestResourcesDirectory = projectRootDir / "src" / "test" / "resources"
20 | val harInputDirectory = (mavenResourcesDirectory / "har" ).toString
21 | val gatlingImportConfig = (mavenResourcesDirectory / "config" / "gatling-recorder.properties").toString
22 | val simulationTargetFolder = (mavenTestSourcesDirectory).toString
23 | val requestBodiesTargetFolder = (mavenTestResourcesDirectory / "request-bodies").toString
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/scala/nl/jpoint/gatling/GatlingRecorderWrapper.scala:
--------------------------------------------------------------------------------
1 | package nl.jpoint.gatling
2 |
3 | import io.gatling.recorder.GatlingRecorder
4 | import io.gatling.recorder.config.{RecorderMode, RecorderPropertiesBuilder}
5 | import org.apache.commons.io.FileUtils
6 |
7 | import java.io.{File, FileInputStream}
8 | import java.util
9 | import java.util.Properties
10 |
11 | object GatlingRecorderWrapper extends App {
12 |
13 | def startRecorder(props: RecorderPropertiesBuilder, simulationClassName : String): Unit = {
14 |
15 | println("Using project root dir " + PathHelper.projectRootDir)
16 |
17 | props.simulationsFolder(PathHelper.simulationOutputFolder)
18 | props.resourcesFolder(PathHelper.requestBodiesTargetFolder)
19 | props.simulationClassName(simulationClassName)
20 | props.simulationPackage("simulations")
21 | props.mode(RecorderMode.Har)
22 | props.headless(true)
23 | props.automaticReferer(true)
24 | props.checkResponseBodies(false)
25 | props.followRedirect(true)
26 | props.inferHtmlResources(true)
27 | props.removeCacheHeaders(true)
28 | props.encoding("utf-8")
29 | props.thresholdForPauseCreation("100")
30 | props.filterStrategy("BlacklistFirst")
31 | props.blacklist(util.Arrays.asList(
32 | ".*\\.js",
33 | ".*\\.css",
34 | ".*\\.gif",
35 | ".*\\.jpeg",
36 | ".*\\.jpg",
37 | ".*\\.ico",
38 | ".*\\.woff",
39 | ".*\\.(t|o)tf",
40 | ".*\\.png",
41 | ".*\\.svg"
42 | ))
43 |
44 | val recorderConfig = props.build
45 | println("Using recorder config: " + recorderConfig)
46 |
47 | GatlingRecorder.fromMap(recorderConfig, Some(PathHelper.recorderConfUrl))
48 | }
49 |
50 | def startRecorderFromConfig(): Unit = {
51 | val properties: Properties = new Properties()
52 | properties.load(new FileInputStream(PathHelper.gatlingImportConfig));
53 |
54 | def har = properties.getProperty("har")
55 | def recorderWhiteList = properties.getProperty(GatlingProperties.RECORDER_WHITE_LIST)
56 | def simulationClassName = properties.getProperty(GatlingProperties.SIMULATION_CLASS_NAME)
57 |
58 | println("Got config:")
59 | println(" har='" + har + "'")
60 | println(" recorderWhiteList='" + recorderWhiteList + "'")
61 | println(" simulationClassName='" + simulationClassName + "'")
62 |
63 | var props = new RecorderPropertiesBuilder
64 | props.harFilePath(PathHelper.harInputDirectory + "/" + har)
65 | props.whitelist(util.Arrays.asList(recorderWhiteList))
66 | GatlingRecorderWrapper.startRecorder(props, simulationClassName)
67 |
68 | }
69 |
70 | def copyGeneratedSimulation(): Unit = {
71 | // Copy generated simulation(s).
72 | //FileUtils.deleteDirectory(new File(PathHelper.simulationTargetFolder + "/simulations"))
73 | FileUtils.copyDirectory(new File(PathHelper.simulationOutputFolder), new File(PathHelper.simulationTargetFolder))
74 |
75 | // Copy generated request bodie(s) - when present.
76 | def bodiesFolder = new File(PathHelper.simulationRequestBodiesFolder)
77 | if (bodiesFolder.exists()) {
78 | FileUtils.copyDirectory(bodiesFolder, new File(PathHelper.requestBodiesTargetFolder))
79 | }
80 |
81 | }
82 |
83 | // Process config.
84 | GatlingRecorderWrapper.startRecorderFromConfig()
85 |
86 | // Copy generated simulation(s).
87 | GatlingRecorderWrapper.copyGeneratedSimulation()
88 |
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | nl.jpoint.gatling
7 | gatling-seed
8 | 1.0-SNAPSHOT
9 |
10 | Gatling Seed
11 |
12 |
13 | 1.8
14 | 1.8
15 | UTF-8
16 | 3.6.1
17 | 3.1.2
18 | 4.4.1
19 |
20 |
21 |
22 |
23 | io.gatling.highcharts
24 | gatling-charts-highcharts
25 | ${gatling.version}
26 |
27 |
28 | commons-io
29 | commons-io
30 | 2.11.0
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | net.alchim31.maven
39 | scala-maven-plugin
40 | ${scala-maven-plugin.version}
41 |
42 |
43 |
44 | recorder
45 | nl.jpoint.gatling.GatlingRecorderWrapper
46 |
47 |
48 |
49 |
50 |
51 |
52 | compile
53 | testCompile
54 |
55 |
56 |
57 | -Xss100M
58 |
59 |
60 | -target:jvm-1.8
61 | -deprecation
62 | -feature
63 | -unchecked
64 | -language:implicitConversions
65 | -language:postfixOps
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | io.gatling
75 | gatling-maven-plugin
76 | ${gatling-plugin.version}
77 |
78 | src/test/scala/simulations
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/test/resources/gatling.conf:
--------------------------------------------------------------------------------
1 | #########################
2 | # Gatling Configuration #
3 | #########################
4 |
5 | # This file contains all the settings configurable for Gatling with their default values
6 |
7 | gatling {
8 | core {
9 | #outputDirectoryBaseName = "" # The prefix for each simulation result folder (then suffixed by the report generation timestamp)
10 | #runDescription = "" # The description for this simulation run, displayed in each report
11 | #encoding = "utf-8" # Encoding to use throughout Gatling for file and string manipulation
12 | #simulationClass = "" # The FQCN of the simulation to run (when used in conjunction with noReports, the simulation for which assertions will be validated)
13 | #elFileBodiesCacheMaxCapacity = 200 # Cache size for request body EL templates, set to 0 to disable
14 | #rawFileBodiesCacheMaxCapacity = 200 # Cache size for request body Raw templates, set to 0 to disable
15 | #rawFileBodiesInMemoryMaxSize = 1000 # Below this limit, raw file bodies will be cached in memory
16 | #pebbleFileBodiesCacheMaxCapacity = 200 # Cache size for request body Peeble templates, set to 0 to disable
17 | #shutdownTimeout = 5000 # Milliseconds to wait for the actor system to shutdown
18 | extract {
19 | regex {
20 | #cacheMaxCapacity = 200 # Cache size for the compiled regexes, set to 0 to disable caching
21 | }
22 | xpath {
23 | #cacheMaxCapacity = 200 # Cache size for the compiled XPath queries, set to 0 to disable caching
24 | }
25 | jsonPath {
26 | #cacheMaxCapacity = 200 # Cache size for the compiled jsonPath queries, set to 0 to disable caching
27 | #preferJackson = false # When set to true, prefer Jackson over Boon for JSON-related operations
28 | }
29 | css {
30 | #cacheMaxCapacity = 200 # Cache size for the compiled CSS selectors queries, set to 0 to disable caching
31 | }
32 | }
33 | directory {
34 | #simulations = user-files/simulations # Directory where simulation classes are located (for bundle packaging only)
35 | #resources = user-files/resources # Directory where resources, such as feeder files and request bodies are located (for bundle packaging only)
36 | #reportsOnly = "" # If set, name of report folder to look for in order to generate its report
37 | #binaries = "" # If set, name of the folder where compiles classes are located: Defaults to GATLING_HOME/target.
38 | #results = results # Name of the folder where all reports folder are located
39 | }
40 | }
41 | charting {
42 | #noReports = false # When set to true, don't generate HTML reports
43 | #maxPlotPerSeries = 1000 # Number of points per graph in Gatling reports
44 | #useGroupDurationMetric = false # Switch group timings from cumulated response time to group duration.
45 | indicators {
46 | #lowerBound = 800 # Lower bound for the requests' response time to track in the reports and the console summary
47 | #higherBound = 1200 # Higher bound for the requests' response time to track in the reports and the console summary
48 | #percentile1 = 50 # Value for the 1st percentile to track in the reports, the console summary and Graphite
49 | #percentile2 = 75 # Value for the 2nd percentile to track in the reports, the console summary and Graphite
50 | #percentile3 = 95 # Value for the 3rd percentile to track in the reports, the console summary and Graphite
51 | #percentile4 = 99 # Value for the 4th percentile to track in the reports, the console summary and Graphite
52 | }
53 | }
54 | http {
55 | #fetchedCssCacheMaxCapacity = 200 # Cache size for CSS parsed content, set to 0 to disable
56 | #fetchedHtmlCacheMaxCapacity = 200 # Cache size for HTML parsed content, set to 0 to disable
57 | #perUserCacheMaxCapacity = 200 # Per virtual user cache size, set to 0 to disable
58 | #warmUpUrl = "https://gatling.io" # The URL to use to warm-up the HTTP stack (blank means disabled)
59 | #enableGA = true # Very light Google Analytics, please support
60 | ssl {
61 | keyStore {
62 | #type = "" # Type of SSLContext's KeyManagers store
63 | #file = "" # Location of SSLContext's KeyManagers store
64 | #password = "" # Password for SSLContext's KeyManagers store
65 | #algorithm = "" # Algorithm used SSLContext's KeyManagers store
66 | }
67 | trustStore {
68 | #type = "" # Type of SSLContext's TrustManagers store
69 | #file = "" # Location of SSLContext's TrustManagers store
70 | #password = "" # Password for SSLContext's TrustManagers store
71 | #algorithm = "" # Algorithm used by SSLContext's TrustManagers store
72 | }
73 | }
74 | ahc {
75 | #connectTimeout = 10000 # Timeout in millis for establishing a TCP socket
76 | #handshakeTimeout = 10000 # Timeout in millis for performing TLS handshake
77 | #pooledConnectionIdleTimeout = 60000 # Timeout in millis for a connection to stay idle in the pool
78 | #maxRetry = 2 # Number of times that a request should be tried again
79 | #requestTimeout = 60000 # Timeout in millis for performing an HTTP request
80 | #enableSni = true # When set to true, enable Server Name indication (SNI)
81 | #enableHostnameVerification = false # When set to true, enable hostname verification: SSLEngine.setHttpsEndpointIdentificationAlgorithm("HTTPS")
82 | #useInsecureTrustManager = true # Use an insecure TrustManager that trusts all server certificates
83 | #filterInsecureCipherSuites = true # Turn to false to not filter out insecure and weak cipher suites
84 | #sslEnabledProtocols = [TLSv1.2, TLSv1.1, TLSv1] # Array of enabled protocols for HTTPS, if empty use the JDK defaults
85 | #sslEnabledCipherSuites = [] # Array of enabled cipher suites for HTTPS, if empty use the AHC defaults
86 | #sslSessionCacheSize = 0 # SSLSession cache size, set to 0 to use JDK's default
87 | #sslSessionTimeout = 0 # SSLSession timeout in seconds, set to 0 to use JDK's default (24h)
88 | #disableSslSessionResumption = false # if true, SSLSessions won't be resumed
89 | #useOpenSsl = true # if OpenSSL should be used instead of JSSE
90 | #useNativeTransport = false # if native transport should be used instead of Java NIO (requires netty-transport-native-epoll, currently Linux only)
91 | #enableZeroCopy = true # if zero-copy upload should be used if possible
92 | #tcpNoDelay = true
93 | #soReuseAddress = false
94 | #allocator = "pooled" # switch to unpooled for unpooled ByteBufAllocator
95 | #maxThreadLocalCharBufferSize = 200000 # Netty's default is 16k
96 | }
97 | dns {
98 | #queryTimeout = 5000 # Timeout in millis of each DNS query in millis
99 | #maxQueriesPerResolve = 6 # Maximum allowed number of DNS queries for a given name resolution
100 | }
101 | }
102 | jms {
103 | #replyTimeoutScanPeriod = 1000 # scan period for timedout reply messages
104 | }
105 | data {
106 | #writers = [console, file] # The list of DataWriters to which Gatling write simulation data (currently supported : console, file, graphite, jdbc)
107 | console {
108 | #light = false # When set to true, displays a light version without detailed request stats
109 | #writePeriod = 5 # Write interval, in seconds
110 | }
111 | file {
112 | #bufferSize = 8192 # FileDataWriter's internal data buffer size, in bytes
113 | }
114 | leak {
115 | #noActivityTimeout = 30 # Period, in seconds, for which Gatling may have no activity before considering a leak may be happening
116 | }
117 | graphite {
118 | #light = false # only send the all* stats
119 | #host = "localhost" # The host where the Carbon server is located
120 | #port = 2003 # The port to which the Carbon server listens to (2003 is default for plaintext, 2004 is default for pickle)
121 | #protocol = "tcp" # The protocol used to send data to Carbon (currently supported : "tcp", "udp")
122 | #rootPathPrefix = "gatling" # The common prefix of all metrics sent to Graphite
123 | #bufferSize = 8192 # Internal data buffer size, in bytes
124 | #writePeriod = 1 # Write period, in seconds
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------