├── .gitignore
├── docker
└── jenkins
│ ├── init.groovy
│ ├── plugins.txt
│ ├── hudson.tasks.Maven.xml
│ ├── settings.xml
│ ├── plugins.sh
│ ├── jenkins.sh
│ ├── Dockerfile
│ ├── config.xml
│ └── jobs
│ └── jmeter-maven-example
│ └── config.xml
├── src
├── main
│ ├── webapp
│ │ └── WEB-INF
│ │ │ └── web.xml
│ └── java
│ │ └── de
│ │ └── codecentric
│ │ └── jmeter
│ │ └── example
│ │ └── ExampleServlet.java
└── test
│ └── jmeter
│ └── SimpleWebservicePerformanceTest.jmx
├── README.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.iml
3 | target
4 | *.log
--------------------------------------------------------------------------------
/docker/jenkins/init.groovy:
--------------------------------------------------------------------------------
1 | import hudson.model.*;
2 | import jenkins.model.*;
3 |
4 |
5 | Thread.start {
6 | sleep 10000
7 | println "--> setting agent port for jnlp"
8 | Jenkins.instance.setSlaveAgentPort(50000)
9 | }
10 |
--------------------------------------------------------------------------------
/docker/jenkins/plugins.txt:
--------------------------------------------------------------------------------
1 | copyartifact:1.35
2 | git-client:1.16.1
3 | github-api:1.59
4 | github:1.11
5 | git:2.3.4
6 | jquery:1.7.2-1
7 | mercurial:1.51
8 | ruby-runtime:0.12
9 | scm-api:0.2
10 | token-macro:1.10
11 | parameterized-trigger:2.25
12 |
--------------------------------------------------------------------------------
/docker/jenkins/hudson.tasks.Maven.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Maven
6 | /usr/share/maven
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | example
4 | de.codecentric.jmeter.example.ExampleServlet
5 |
6 |
7 | example
8 | /*
9 |
10 |
--------------------------------------------------------------------------------
/docker/jenkins/settings.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/docker/jenkins/plugins.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # Parse a support-core plugin -style txt file as specification for jenkins plugins to be installed
4 | # in the reference directory, so user can define a derived Docker image with just :
5 | #
6 | # FROM jenkins
7 | # COPY plugins.txt /plugins.txt
8 | # RUN /usr/share/jenkins/plugins.sh /plugins.txt
9 | #
10 |
11 | REF=/usr/share/jenkins/ref/plugins
12 | mkdir -p $REF
13 |
14 | while read spec; do
15 | plugin=(${spec//:/ });
16 | curl -L ${JENKINS_UC}/download/plugins/${plugin[0]}/${plugin[1]}/${plugin[0]}.hpi -o $REF/${plugin[0]}.hpi;
17 | done < $1
18 |
--------------------------------------------------------------------------------
/src/main/java/de/codecentric/jmeter/example/ExampleServlet.java:
--------------------------------------------------------------------------------
1 | package de.codecentric.jmeter.example;
2 |
3 | import javax.servlet.GenericServlet;
4 | import javax.servlet.ServletException;
5 | import javax.servlet.ServletRequest;
6 | import javax.servlet.ServletResponse;
7 | import java.io.IOException;
8 | import java.util.Random;
9 |
10 |
11 | public class ExampleServlet extends GenericServlet {
12 | private Random random = new Random();
13 |
14 | @Override
15 | public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
16 | sleep(100);
17 | res.getOutputStream().print("Hello ...");
18 | res.getOutputStream().flush();
19 | sleep(100);
20 | res.getOutputStream().print("... World");
21 | }
22 |
23 | private void sleep(int interval) {
24 | try {
25 | // Wait a random time between 0.5*interval and 1.5*interval msec
26 | Thread.sleep(random.nextInt(interval) + interval/2);
27 | } catch (InterruptedException e) {
28 | // Don't care if we've been interrupted
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docker/jenkins/jenkins.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | # Copy files from /usr/share/jenkins/ref into /var/jenkins_home
4 | # So the initial JENKINS-HOME is set with expected content.
5 | # Don't override, as this is just a reference setup, and use from UI
6 | # can then change this, upgrade plugins, etc.
7 | copy_reference_file() {
8 | f=${1%/}
9 | echo "$f"
10 | rel=${f:23}
11 | dir=$(dirname ${f})
12 | echo " $f -> $rel"
13 | if [[ ! -e /var/jenkins_home/${rel} ]]
14 | then
15 | echo "copy $rel to JENKINS_HOME"
16 | mkdir -p /var/jenkins_home/${dir:23}
17 | cp -r /usr/share/jenkins/ref/${rel} /var/jenkins_home/${rel};
18 | fi;
19 | }
20 | export -f copy_reference_file
21 | find /usr/share/jenkins/ref/ -type f -exec bash -c 'copy_reference_file {}' \;
22 |
23 | # if `docker run` first argument start with `--` the user is passing jenkins launcher arguments
24 | if [[ $# -lt 1 ]] || [[ "$1" == "--"* ]]; then
25 | exec java $JAVA_OPTS -jar /usr/share/jenkins/jenkins.war $JENKINS_OPTS "$@"
26 | fi
27 |
28 | # As argument is not jenkins, assume user want to run his own process, for sample a `bash` shell to explore this image
29 | exec "$@"
30 |
31 |
--------------------------------------------------------------------------------
/docker/jenkins/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM java:8-jdk
2 |
3 | RUN apt-get update && apt-get install -y wget git curl maven zip && rm -rf /var/lib/apt/lists/*
4 |
5 | ENV JENKINS_HOME /var/jenkins_home
6 |
7 | # Jenkins is ran with user `jenkins`, uid = 1000
8 | # If you bind mount a volume from host/vloume from a data container,
9 | # ensure you use same uid
10 | RUN useradd -d "$JENKINS_HOME" -u 1000 -m -s /bin/bash jenkins
11 |
12 | # Jenkins home directoy is a volume, so configuration and build history
13 | # can be persisted and survive image upgrades
14 | VOLUME /var/jenkins_home
15 |
16 | # `/usr/share/jenkins/ref/` contains all reference configuration we want
17 | # to set on a fresh new installation. Use it to bundle additional plugins
18 | # or config file with your custom jenkins Docker image.
19 | RUN mkdir -p /usr/share/jenkins/ref/init.groovy.d
20 |
21 | COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/tcp-slave-angent-port.groovy
22 |
23 | ENV JENKINS_VERSION 1.601
24 |
25 | # could use ADD but this one does not check Last-Modified header
26 | # see https://github.com/docker/docker/issues/8331
27 | RUN curl -L http://mirrors.jenkins-ci.org/war/1.601/jenkins.war -o /usr/share/jenkins/jenkins.war
28 |
29 | ENV JENKINS_UC https://updates.jenkins-ci.org
30 | RUN chown -R jenkins "$JENKINS_HOME" /usr/share/jenkins/ref
31 |
32 | # for main web interface:
33 | EXPOSE 8080
34 |
35 | # will be used by attached slave agents:
36 | EXPOSE 50000
37 |
38 | COPY jenkins.sh /usr/local/bin/jenkins.sh
39 |
40 | ENTRYPOINT ["/usr/local/bin/jenkins.sh"]
41 |
42 | # from a derived Dockerfile, can use `RUN plugin.sh active.txt` to setup /usr/share/jenkins/ref/plugins from a support bundle
43 | COPY plugins.sh /usr/local/bin/plugins.sh
44 | COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
45 | RUN plugins.sh /usr/share/jenkins/ref/plugins.txt
46 |
47 | # Here comes our special scrum-for-developers-training configuration
48 | COPY settings.xml /usr/share/jenkins/ref/.m2/settings.xml
49 | COPY config.xml /usr/share/jenkins/ref/config.xml
50 | COPY org.jfrog.hudson.ArtifactoryBuilder.xml /usr/share/jenkins/ref/org.jfrog.hudson.ArtifactoryBuilder.xml
51 | COPY hudson.tasks.Maven.xml /usr/share/jenkins/ref/hudson.tasks.Maven.xml
52 | ADD jobs /usr/share/jenkins/ref/jobs
53 |
54 | ENV JENKINS_OPTS --prefix=/jenkins
55 |
56 | USER jenkins
57 |
--------------------------------------------------------------------------------
/docker/jenkins/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1.601
5 | 2
6 | NORMAL
7 | true
8 |
9 |
10 | false
11 |
12 | ${ITEM_ROOTDIR}/workspace
13 | ${ITEM_ROOTDIR}/builds
14 |
15 | false
16 |
17 |
18 |
19 | JDK
20 | /usr/lib/jvm/java-8-openjdk-amd64
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 5
29 | 0
30 |
31 |
32 |
33 | All
34 | false
35 | false
36 |
37 |
38 |
39 |
40 | Pipeline
41 | false
42 | false
43 |
44 |
45 |
46 | Worblehat
47 | worblehat-010-build
48 |
49 |
50 | 5
51 | false
52 | 1
53 | none
54 | false
55 | 2
56 | true
57 | true
58 |
59 |
60 |
61 | All
62 | 50000
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JMeter Maven Example
2 | Example how to integrate jmeter tests in a maven build and how to automatically generate graphs from the test results using the jmeter plugins CMDRunner.
3 |
4 | The jmeter tests can easily be used as part of a jenkins-job. See https://mlex.ci.cloudbees.com/job/jmeter-maven-example/. The repository also contains a docker-image of a preconfigured jenkins.
5 |
6 | This example was created to accompany a blog post: https://blog.codecentric.de/2013/12/jmeter-tests-mit-maven-und-jenkins-automatisieren/
7 |
8 | The [jmeter-maven-plugin](https://github.com/Ronnie76er/jmeter-maven-plugin) is used to integrate jmeter in the maven build. To generate graphs from the jmeter results, the [jmeter-graph-maven-plugin](https://github.com/codecentric/jmeter-graph-maven-plugin) is used.
9 |
10 | ## Jenkins
11 | Under `docker/jenkins` can find a jenkins with a preconfigured build-job that runs the jmeter tests and archives the results. Just build the docker image with
12 | ```
13 | cd docker/jenkins
14 | docker build -t jmeter-jenkins .
15 | ```
16 |
17 | and run the container with
18 | ```
19 | docker run -p=8080:8080 jmeter-jenkins
20 | ```
21 | and you can access the jenkins in your browser via `http://localhost:8080/jenkins/`.
22 |
23 | ## Quickstart
24 | Just execute
25 |
26 | ```bash
27 | mvn -Pembedded-jetty verify
28 | ```
29 |
30 | This will
31 | * start an embedded jetty server wit a small webapp,
32 | * run jmeter tests (just some http requests) against this webserver and
33 | * create some nice graphs of the result (you will find them in `target/jmeter/results`).
34 |
35 | ## JMeter GUI
36 |
37 | To start the JMeter GUI, use the `jmeter:gui` goal. The tests are located in `/src/test/jmeter`. If you start the tests, make sure that the example webapp is running. You can start the webapp explicitly with `jetty:run`.
38 |
39 | ## JMeter Headless
40 |
41 | To just execute the jmeter-tests from commandline (without gui, without embedded webapp, without graph-generation), use the `jmeter:jmeter` goal. The tests expect a running example webapp, so make sure at `http://localhost:9097/`. The results of the test-run can be found in `/target/jmeter/results`. If you want graph-generation, run `mvn verify` (without the "local" profile).
42 |
43 | ## Configuration
44 | The following maven-properties are available (to set them from commandline, simply add `-Dproperty=value`)
45 |
46 |
47 |
48 | | Property |
49 | Default |
50 |
51 |
52 | | jetty.port |
53 | 9097 |
54 |
55 |
56 | | performancetest.webservice.host |
57 | localhost |
58 |
59 |
60 | | performancetest.webservice.port |
61 | ${jetty.port} |
62 |
63 |
64 | | performancetest.webservice.path |
65 | / |
66 |
67 |
68 | | performancetest.connectTimeout |
69 | 1000 |
70 |
71 |
72 | | performancetest.responseTimeout |
73 | 3000 |
74 |
75 |
76 | | performancetest.threadCount |
77 | 20 |
78 |
79 |
80 | | performancetest.loopCount |
81 | 10 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/docker/jenkins/jobs/jmeter-maven-example/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <h2>Result of the last successfull build</h2>
5 | <p><a href="lastSuccessfulBuild/artifact/target/jmeter/results/SimpleWebservicePerformanceTest.jtl">Test results (as JTL-File)</a></p>
6 | <table width="100%">
7 | <tr>
8 | <td width="33%">
9 | <img width="100%" src="lastSuccessfulBuild/artifact/target/jmeter/results/SimpleWebservicePerformanceTest-ResponseTimesOverTime.png"/>
10 | </td>
11 | <td width="33%">
12 | <img width="100%" src="lastSuccessfulBuild/artifact/target/jmeter/results/SimpleWebservicePerformanceTest-ThreadsStateOverTime.png"/>
13 | </td>
14 | <td width="33%">
15 | <img width="100%" src="lastSuccessfulBuild/artifact/target/jmeter/results/SimpleWebservicePerformanceTest-TransactionsPerSecond.png"/>
16 | </td>
17 | </tr>
18 | </table>
19 |
20 | 60
21 | -1
22 | -1
23 | -1
24 |
25 | false
26 |
27 |
28 |
29 |
30 | THREAD_COUNT
31 | Number of parallel threads for the load test.
32 | 10
33 |
34 |
35 | LOOP_COUNT
36 | Number of iterations for each user thread.
37 | 10
38 |
39 |
40 |
41 |
42 |
43 | 2
44 |
45 |
46 | https://github.com/mlex/jmeter-maven-example
47 |
48 |
49 |
50 |
51 | */master
52 |
53 |
54 | false
55 |
56 |
57 |
58 | true
59 | false
60 | false
61 | false
62 |
63 | false
64 |
65 | de.codecentric.jmeter
66 | jmeter-maven-example
67 |
68 | clean -Pembedded-jetty verify -Dperformancetest.threadCount=$THREAD_COUNT -Dperformancetest.loopCount=$LOOP_COUNT
69 | true
70 | false
71 | false
72 | false
73 | false
74 | false
75 | false
76 | false
77 | -1
78 | false
79 | false
80 | true
81 |
82 |
83 |
84 |
85 |
86 | target/jmeter/results/*
87 | false
88 | false
89 | false
90 | true
91 |
92 |
93 |
94 |
95 |
96 |
97 | FAILURE
98 | 2
99 | RED
100 | true
101 |
102 |
103 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | de.codecentric.jmeter
7 | jmeter-maven-example
8 | 0.1.0-SNAPSHOT
9 | jar
10 | JMeter Maven Example
11 |
12 | Example how to integrate jmeter tests in a maven build and how to automatically
13 | generate graphs from the test results using the jmeter plugins CMDRunner.
14 |
15 |
16 |
17 | 9097
18 | 19097
19 | localhost
20 | ${jetty.port}
21 | /
22 | 1000
23 | 3000
24 | 20
25 | 10
26 |
27 |
28 |
29 |
30 | javax.servlet
31 | servlet-api
32 | 2.5
33 |
34 |
35 |
36 |
37 |
38 | jenkins
39 |
40 | tomcat7-example-webapp.mlex.cloudbees.net
41 | 80
42 | 5
43 | 5
44 |
45 |
46 |
47 | embedded-jetty
48 |
49 |
50 |
51 | org.mortbay.jetty
52 | jetty-maven-plugin
53 |
54 |
55 | start-jetty
56 |
57 | start
58 |
59 | pre-integration-test
60 |
61 | true
62 |
63 |
64 |
65 | stop-jetty
66 |
67 | stop
68 |
69 | post-integration-test
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | com.lazerycode.jmeter
82 | jmeter-maven-plugin
83 | 1.9.0
84 |
85 | false
86 | DEBUG
87 | false
88 | true
89 |
90 | ${performancetest.webservice.host}
91 | ${performancetest.webservice.port}
92 | ${performancetest.webservice.path}
93 | ${performancetest.connectTimeout}
94 | ${performancetest.responseTimeout}
95 | ${performancetest.threadCount}
96 | ${performancetest.threadCount}
97 |
98 |
99 | true
100 |
101 |
102 |
103 | kg.apc
104 | jmeter-plugins
105 |
106 |
107 |
108 |
109 |
110 | execute-jmeter-tests
111 |
112 | jmeter
113 |
114 | integration-test
115 |
116 |
117 |
118 |
119 | kg.apc
120 | jmeter-plugins
121 | 1.0.0
122 |
123 |
128 |
129 | kg.apc
130 | perfmon
131 |
132 |
133 | org.apache.hadoop
134 | hadoop-core
135 |
136 |
137 | org.apache.hbase
138 | hbase
139 |
140 |
141 |
145 |
146 | org.apache.jmeter
147 | jorphan
148 |
149 |
150 | org.apache.bsf
151 | bsf-api
152 |
153 |
154 | org.bouncycastle
155 | bcmail-jdk15
156 |
157 |
158 | org.bouncycastle
159 | bcprov-jdk15
160 |
161 |
162 | javax.activation
163 | activation
164 |
165 |
166 | commons-logging
167 | commons-logging
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | com.lazerycode.jmeter
176 | jmeter-analysis-maven-plugin
177 | 1.0.4
178 |
179 | ${project.build.directory}/jmeter/results/SimpleWebservicePerformanceTest.jtl
180 |
181 |
182 |
183 | create-html-report
184 | verify
185 |
186 | analyze
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 | org.mortbay.jetty
195 | jetty-maven-plugin
196 | 8.1.14.v20131031
197 |
198 |
199 |
200 | ${jetty.port}
201 |
202 |
203 | ${jetty.stopPort}
204 | STOP
205 |
206 |
207 |
208 |
209 | de.codecentric
210 | jmeter-graph-maven-plugin
211 | 0.1.0
212 |
213 |
214 | create-graph-threads
215 |
216 | create-graph
217 |
218 | verify
219 |
220 |
221 |
222 | ${project.build.directory}/jmeter/results/SimpleWebservicePerformanceTest.jtl
223 |
224 |
225 | ThreadsStateOverTime
226 | 800
227 | 600
228 | ${project.build.directory}/jmeter/results/SimpleWebservicePerformanceTest-ThreadsStateOverTime.png
229 |
230 |
231 | ResponseTimesOverTime
232 | 800
233 | 600
234 | ${project.build.directory}/jmeter/results/SimpleWebservicePerformanceTest-ResponseTimesOverTime.png
235 |
236 |
237 | TransactionsPerSecond
238 | 800
239 | 600
240 | ${project.build.directory}/jmeter/results/SimpleWebservicePerformanceTest-TransactionsPerSecond.png
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
--------------------------------------------------------------------------------
/src/test/jmeter/SimpleWebservicePerformanceTest.jmx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | false
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | HOST
18 | ${__P(webservice.host,localhost)}
19 | Hostname (or IP) of the webservice to test.
20 | =
21 |
22 |
23 | PORT
24 | ${__P(webservice.port,8080)}
25 | Port of the webservice.
26 | =
27 |
28 |
29 | PATH
30 | ${__P(webservice.path,/)}
31 | Path to the webservice.
32 | =
33 |
34 |
35 | CONNECT_TIMEOUT
36 | ${__P(webservice.connectTimeout,1000)}
37 | Timeout when connecting to webservice.
38 | =
39 |
40 |
41 | RESPONSE_TIMEOUT
42 | ${__P(webservice.responseTimeout,3000)}
43 | Webservice response timeout.
44 | =
45 |
46 |
47 | THREADCOUNT
48 | ${__P(threadCount, 20)}
49 | Maximal number of concurrent threads.
50 | =
51 |
52 |
53 | LOOPCOUNT
54 | ${__P(loopCount, 10)}
55 | Number of iterations for each thread.
56 | =
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | ${HOST}
66 | ${PORT}
67 | ${CONNECT_TIMEOUT}
68 | ${RESPONSE_TIMEOUT}
69 |
70 |
71 | ${PATH}
72 | 4
73 |
74 |
75 |
76 | continue
77 |
78 | false
79 | ${LOOPCOUNT}
80 |
81 | ${THREADCOUNT}
82 | ${THREADCOUNT}
83 | 1386699377000
84 | 1386699377000
85 | false
86 |
87 |
88 |
89 |
90 |
91 | 200
92 | 200
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | GET
107 | true
108 | false
109 | true
110 | false
111 | false
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | false
120 |
121 | saveConfig
122 |
123 |
124 | true
125 | true
126 | true
127 |
128 | true
129 | true
130 | true
131 | true
132 | false
133 | true
134 | true
135 | false
136 | false
137 | false
138 | false
139 | false
140 | false
141 | false
142 | false
143 | 0
144 | true
145 | true
146 |
147 |
148 |
149 | 500
150 | false
151 |
152 |
153 |
154 |
155 |
156 | false
157 |
158 | saveConfig
159 |
160 |
161 | true
162 | true
163 | true
164 |
165 | true
166 | true
167 | true
168 | true
169 | false
170 | true
171 | true
172 | false
173 | false
174 | false
175 | false
176 | false
177 | false
178 | false
179 | false
180 | 0
181 | true
182 | true
183 |
184 |
185 |
186 | 500
187 | false
188 |
189 |
190 |
191 |
192 |
193 | false
194 |
195 | saveConfig
196 |
197 |
198 | true
199 | true
200 | true
201 |
202 | true
203 | true
204 | true
205 | true
206 | false
207 | true
208 | true
209 | false
210 | false
211 | false
212 | false
213 | false
214 | false
215 | false
216 | false
217 | 0
218 | true
219 | true
220 |
221 |
222 |
223 | 1000
224 | false
225 |
226 |
227 |
228 |
229 |
230 | false
231 |
232 | saveConfig
233 |
234 |
235 | true
236 | true
237 | true
238 |
239 | true
240 | true
241 | true
242 | true
243 | false
244 | true
245 | true
246 | false
247 | false
248 | false
249 | false
250 | false
251 | false
252 | false
253 | false
254 | 0
255 | true
256 | true
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
--------------------------------------------------------------------------------