= jmeter-gradle-plugin
ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]
ifndef::env-github[]
:icons: font
endif::[]
:jm_base: https://jmeter.apache.org
:jm_tm: {jm_base}/[JMeter(TM),window=_blank]
:jm_doc_base: {jm_base}/usermanual
:jm_remoteing: {jm_doc_base}/remote-test.html
:jm_cli: {jm_doc_base}/get-started.html#override
:gh_rp: https://github.com/qualersoft/jmeter-gradle-plugin
:toc: preamble
[cols="1,~", frame=none, grid=none]
|===
|General
|image:https://img.shields.io/github/license/qualersoft/jmeter-gradle-plugin[link={gh_rp}/blob/main/LICENSE]
image:https://app.fossa.com/api/projects/custom%2B17788%2Fgithub.com%2Fqualersoft%2Fjmeter-gradle-plugin.svg?type=shield[link=https://app.fossa.com/projects/custom%2B17788%2Fjmeter-gradle-plugin/refs/branch/main/]
|Main
|image:{gh_rp}/actions/workflows/build.yml/badge.svg?branch=main[title="Build status", link={gh_rp}/blob/main/.github/workflows/build.yml]
image:https://www.codefactor.io/repository/github/qualersoft/jmeter-gradle-plugin/badge/main[title="Code quality", link=https://www.codefactor.io/repository/github/qualersoft/jmeter-gradle-plugin/overview/main]
image:https://codecov.io/gh/qualersoft/jmeter-gradle-plugin/branch/main/graph/badge.svg?token=Z5CT2C7LN1[title="Coverage", link=https://app.codecov.io/gh/qualersoft/jmeter-gradle-plugin/branch/main]
|Develop
|image:{gh_rp}/actions/workflows/build.yml/badge.svg?branch=develop[title="Build status", link={gh_rp}/blob/develop/.github/workflows/build.yml]
image:https://www.codefactor.io/repository/github/qualersoft/jmeter-gradle-plugin/badge/develop[title="Code quality", link=https://www.codefactor.io/repository/github/qualersoft/jmeter-gradle-plugin/overview/develop]
image:https://codecov.io/gh/qualersoft/jmeter-gradle-plugin/branch/develop/graph/badge.svg?token=XT7QzRFkaj[title="Coverage", link=https://app.codecov.io/gh/qualersoft/jmeter-gradle-plugin/branch/develop]
|===
Gradle plugin to integrate {jm_tm} tests into the gradle ecosystem. +
This plugin arose from the need of a simple to start, but easy to customize plugin. The current available plugins are either hardwired to older {jm_tm} version or configuration is not so well documented.
== Usage
=== Applying the plugin
.Kotlin DSL
[%collapsible%open]
[source,kotlin]
plugins {
id("de.qualersoft.jmeter") version ""
}
====
.Groovy DSL
[%collapsible]
[source,groovy]
plugins {
id 'de.qualersoft.jmeter' version ''
}
====
=== Customization
The easiest way to customize the plugin is via its jmeter
extension. +
The extension offers the following properties
[source,kotlin]
jmeter {
systemPropertyFiles // <.>
systemProperties // <.>
mainPropertyFile // <.>
additionalPropertyFiles // <.>
jmeterProperties // <.>
customReportTemplate // <.>
globalPropertiesFile // <.>
globalProperties // <.>
proxxScheme // <.>
proxyHost // <.>
proxyPort // <.>
nonProxyHosts // <.>
logConfig // <.>
logOutputFile // <.>
jmxRootDir // <.>
resultDir // <.>
reportDir // <.>
maxHeap // <.>
jvmArgs //<.>
enableRemoteExecution // <.>
exitRemoteServers // <.>
}
[%collapsible]
<.> Additional system property file(s).
<.> Define additional system properties.
<.> The jmeter property file to use.
<.> Additional JMeter property file(s).
<.> Define additional JMeter properties.
<.> Path to a custom report-template folder used by report generator.
<.> Path to a JMeter property file which will be sent to all servers.
<.> Properties which will be sent to remote servers.
<.> Scheme of the proxy (e.g. for non-http).
<.> Proxy server hostname or ip address.
<.> Proxy server port.
<.> Non-proxy hosts (e.g *.apache.org).
<.> Custom log configuration file (currently log4j2) +
Defaults to bundled configuration.
<.> File where jmeter log will be written to. +
Defaults to /logs/jmeter.log
<.> Used to search for jmx files. +
Defaults to src/test/jmeter
<.> Directory to which the jtl-files will be written. +
Defaults to /test-results/jmeter
<.> Root directory where to put the reports +
Defaults to /reports/jmeter
<.> [Optional] Specifies the maximum heap size the JVM process will start with.
<.> [Optional] additional JVM arguments that will be passed to the jvm directly.
<.> [Optional] tells {jm_tm} to run the tests on the configured remote-servers (see {jm_remoteing}[remoting]) +
Defaults to false
.
<.> [Optional] Flag to exit remote servers at the end of the test. Only effective iff enableRemoteExecution
is true
. +
Defaults to false
.
These configurations will be applied to all tasks (where appropriate) and can be overridden or extended on a per task base.
== Quickstarter
[IMPORTANT,title=Important]
To use the quickstarter you must have gradle installed and available on your path
=== Running a jmeter-test
-
In a folder of your choice (referred to as root
), execute:
+
[source,shell script]
root> gradle init --dsl kotlin --type basic
This brings up the setup. We are going to create a basic
project and using Kotlin
as build script DSL.
-
Create the following folder structure (gradle stuff from 1. left out)
+
[source]
root
├── src
│ └── test
│ └── jmeter
│ └── Test.jmx <.>
└── build.gradle.kts <.>
<1> default folder for jmx-files is `src/test/jmeter` +
You can copy the `Test.jmx` from link:./src/functionalTest/resources[functional test resources]
<2> build.gradle.kts is generated by gradle; we need it in next step.
-
Put the following into build.gradle.kts
+
[source,kotlin]
import de.qualersoft.jmeter.gradleplugin.task.* // <.>
plugins {
id("de.qualersoft.jmeter") version "" // <.>
}
repositories {
mavenCentral() // <.>
}
tasks {
register("runJMeter") { // <.>
jmxFile.set("Test.jmx") // <.>
}
}
<1> Import `task` package. (to save some typing later on 😋)
<2> Apply the plugin. (Don't forget to correct the version 😉)
<3> We need a repository to retrieve jmeter-library. `mavenCentral` should work in almost any case.
<4> Register a run-task and give it a name (if we wouldn't had imported the `task` package in (1), we would have to use the full qualified path)
<5> Configure the task to use our test.jmx file under `src/test/jmeter`
4. Run it by opening a cli of your choice in `root`
+
[source, shell script]
----
root> ./gradlew runJMeter
----
+
[source, shell script,title=Output]
----
...
Starting standalone test @ Sat Sep 04 18:53:51 CEST 2021 (1630774431340)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
Warning: Nashorn engine is planned to be removed from a future JDK release
summary = 30 in 00:00:03 = 10,0/s Avg: 206 Min: 108 Max: 345 Err: 2 (6,67%)
Tidying up ... @ Sat Sep 04 18:53:55 CEST 2021 (1630774435185)
... end of run
BUILD SUCCESSFUL in 15s
1 actionable task: 1 executed
----
👏 Congratulations, you've run your first jmeter script with this plugin. +
🎉 4 steps, that's it. Simple, wasn't it?
=== Generating a report
After you've run your first jmeter script successfully, you might want to have a report showing some nice charts and stats.
No problem, just:
1. add the following to your `build.gradel.kts` s `task` section
+
[source,kotlin]
----
tasks {
register
("runJMeter") {
jmxFile.set("Test.jmx")
}
register("jmeterReport") { // <.>
jmxFile.set("Test.jmx") // <.>
}
}
----
<1> registering a `JMeterReportTask` task (remember the include? Now it pays off 😊)
<2> by pointing it to our `jmx` file the plugin knows where to find everything
2. back in CLI run
+
[source, shell script]
----
root> ./gradlew jmeterReport
----
This generates the report under `build/reports/jmeter/Test`
[NOTE,title=Note]
The directory 'Test' is retrieved from the jmx-file's name.
🎉 Voila, just 2 steps to get a report.
Remark that to generate a report, you have to execute the `runJMeter` task before. There are two ways you can get it in one rush.
1. Declare a `dependsOn` in report task
+
[source,kotlin]
----
register("jmeterReport") {
jmxFile.set("Test.jmx")
dependsOn("runJMeter")
}
----
if you now execute `jmeterReport`, `runJMeter` get executed first if required
2. Or let the 'run' task always generate a report with `generateReport` flag
+
[source,kotlin]
----
register("runTest") {
jmxFile.set("Test.jmx")
generateReport = true
}
----
[TIP,title=Tip]
If you are going to rerun the task without cleaning outputs you will get an error because the report already exists. In such cases just enable the `deleteResults` property
=== Want to modify the jmx-Script with jmeter UI?
No problem, just add the following task to your build-script
[source,kotlin]
----
tasks {
register("edit") {
jmxFile.set("Test.jmx")
}
}
----
And back to CLI
[source,shell script]
----
root> ./gradlew edit
----
As an alternative, if you don't want to clutter your tasks-section, you can use the `jmeter`-extension
[source,kotlin]
----
jmeter {
withGuiTask("edit") {
jmxFile.set("Test.jmx")
}
}
----
== Cli arguments
All tasks also provide some of their properties through cli-arguments. +
To see what arguments are supported by a task simply run
[source,shell script]
----
root> ./gradlew help --task <.>
----
<1> with being a JMeter*Task defined in your build script. E.g. our 'runTest' task from above.
== Configure jmeter
As mentioned in the preamble, this plugin is designed to be as flexible as possible. +
By that, the used jmeter runner artifact as well as plugins or libraries aren't hardwired but can be configured.
=== Configure the runner
You can easily configure not only the version but also its coordinates. All this can be done through the `jmeter.tool` property.
[source,kotlin]
----
jmeter {
tool {
group // <.>
name // <.>
version // <.>
mainConfigureClosure // <.>
mainClass // <.>
}
}
----
[%collapsible]
====
<1> The group-id of the jmeter-runner. +
Defaults to 'org.apache.jmeter'.
<2> The name (artifact-id) of the jmeter-runner. +
Defaults to 'ApacheJMeter'.
<3> the version of the jmeter-runner. +
Defaults to '5.5'.
<4> A closure/lambda to configure the dependency any further. +
Will only applied if not `null` (which is the default).
<5> The main class used to execute the jmeter runner. +
Defaults to 'org.apache.jmeter.NewDriver'.
====
=== Adding plugins
Because the runner itself is quite useless without any plugins you can add them with the `jmeterPlugin` dependency handler
[source,kotlin]
----
dependencies {
jmeterPlugin("org.jmeter:a-plugin:1.2.3") // <.>
}
----
<1> Resolves the 'a-plugin' and puts its artifact into `/lib/ext`, transitive dependencies will be put to `lib` directory.
[NOTE]
====
Please note the <> section.
====
By default, this plugin includes the following plugins (as they are also default plugins in a normal JMeter installation):
====
"bolt", "components", "core", "ftp", "functions", "http", "java", "jdbc", "jms", "junit", "ldap", "mail", "mongodb", "native", "tcp"
====
[%collapsible, title=Info]
====
At the current time, these plugins are hardwired and cannot be modified. +
(Yeah, I know, so much about flexibility... Mea culpa! 😉)
====
=== Adding support libraries
Sometimes you have quite special and reusable code that you wouldn't maintain within JMeter. Or you just want to use an existing libraries functions within JMeter. +
To make them available to JMeter you can use the `jmeterLibrary` dependency handler
[source,kotlin]
----
dependencies {
jmeterLibrary("org.apache.commons:commons-csv:1.9.0") // <.>
}
----
<1> Resolves the 'commons-csv' artifact and puts its artifact, and all its transitive dependencies, under `/lib` directory.
[NOTE]
====
Please note the <> section.
====
[CAUTION,title=Internal only]
====
Within an IDE with autocomplete, you may also notice the `jmeterRunner` dependency handler. This is for internal use only! Please use the respective `jmeter.tool` properties to configure the runner.
====
=== Pitfalls when using jmeter-dependencies/-plugins
Some of the jmeter dependencies or plugins, which you want to apply through `jmeterLibrary` or `jmeterPlugin` might
depend on 'org.apache.jmeter:bom'.
This dependency seems not available on any maven-repository (for further information refer to https://bz.apache.org/bugzilla/show_bug.cgi?id=64465[Issue 64465]).
If you are affected by this issue, you will see an error message similar to
----
...
> Could not resolve all dependencies for configuration ':jmeterPlugin'.
> Could not find org.apache.jmeter:bom:5.5.
Required by:
project > ...
----
when executing one of the jmeter-tasks.
As a convenient workaround, the `jmeter-gradle-plugin` provides the `jmeter.tool.applyBomWorkaround` function.
You can apply it to the affected dependencies like this:
[source,kotlin]
----
dependencies {
// in case a library is affected
jmeterLibrary("org.apache.jmeter:a-library:1.2.3") {
jmeter.tool.applyBomWorkaround(this)
}
// or in case a plugin is affected
jmeterPlugin("org.jmeter:a-plugin:1.2.3") {
jmeter.tool.applyBomWorkaround(this)
}
}
----