Skip to content

Commit b0485c0

Browse files
Add module to run test plans in BlazeMeter
Additionally, fix documentation links to java classes and maven test execution.
1 parent 8b835f5 commit b0485c0

File tree

30 files changed

+1525
-152
lines changed

30 files changed

+1525
-152
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ jobs:
1212
with:
1313
java-version: 1.8
1414
- name: Run maven tests
15-
run: mvn clean test
15+
run: mvn clean test
16+
env:
17+
BZ_TOKEN: ${{ secrets.BZ_TOKEN }}

.github/workflows/release.yml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: publish release
22
on:
33
release:
4-
types: [published]
4+
types: [ published ]
55
jobs:
66
release:
77
runs-on: ubuntu-latest
@@ -15,11 +15,20 @@ jobs:
1515
run: mvn --batch-mode versions:set -DnewVersion=${GITHUB_REF#refs/tags/v} --settings .github/settings.xml
1616
- name: package release
1717
run: mvn clean package -DskipTests --settings .github/settings.xml
18-
- name: Upload release artifact
18+
env:
19+
BZ_TOKEN: ${{ secrets.BZ_TOKEN }}
20+
- name: Upload jmeter-java-dsl.jar to release
21+
uses: svenstaro/upload-release-action@v2
22+
with:
23+
repo_token: ${{ secrets.GITHUB_TOKEN }}
24+
file: ./jmeter-java-dsl/target/*.jar
25+
file_glob: true
26+
tag: ${{ github.ref }}
27+
- name: Upload jmeter-java-dsl-blazemeter.jar to release
1928
uses: svenstaro/upload-release-action@v2
2029
with:
2130
repo_token: ${{ secrets.GITHUB_TOKEN }}
22-
file: ./target/*.jar
31+
file: ./jmeter-java-dsl-blazemeter/target/*.jar
2332
file_glob: true
2433
tag: ${{ github.ref }}
2534
- name: publish to Nexus

CONTRIBUITING.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,25 @@ Test elements are classes that implement [DslTestElement] interface, which basic
1414

1515
To implement your own DslTestElement, the library already provides some base classes from where to start:
1616

17-
* [BaseTestElement](src/main/java/us/abstracta/jmeter/javadsl/core/BaseTestElement.java): This contains the very basics of test elements, allowing to abstract the common logic of all test elements (ie: naming them, setting common properties and adding them to a JMeter tree). Create a subclass of this class only if the test element can't nest children, otherwise extend [TestElementContainer]. Examples: [HttpHeaders] and [JtlWriter].
18-
* [TestElementContainer]: This represents a test element which can nest other test elements. If you need to implement a Sampler, then extend DslSampler instead. Examples: [DslTestPlan](src/main/java/us/abstracta/jmeter/javadsl/core/DslTestPlan.java), [DslThreadGroup](src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java).
19-
* [DslSampler]: This contains common logic for samplers, and should be the class extended in most of the cases. Examples: [DslHttpSampler](src/main/java/us/abstracta/jmeter/javadsl/http/DslHttpSampler.java)
17+
* [BaseTestElement](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/BaseTestElement.java): This contains the very basics of test elements, allowing to abstract the common logic of all test elements (ie: naming them, setting common properties and adding them to a JMeter tree). Create a subclass of this class only if the test element can't nest children, otherwise extend [TestElementContainer]. Examples: [HttpHeaders] and [JtlWriter].
18+
* [TestElementContainer]: This represents a test element which can nest other test elements. If you need to implement a Sampler, then extend DslSampler instead. Examples: [DslTestPlan](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslTestPlan.java), [DslThreadGroup](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java).
19+
* [DslSampler]: This contains common logic for samplers, and should be the class extended in most of the cases. Examples: [DslHttpSampler](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/http/DslHttpSampler.java)
2020

2121
As previously mentioned, DslTestElement instances can be nested, and when implementing one, you should define under what other test elements this element can be nested (eg: thread groups can only be added under test plans). To do that, just implement the appropriate interface required by the associated "parent" element, currently provided interfaces are:
2222

23-
* [TestPlanChild](src/main/java/us/abstracta/jmeter/javadsl/core/DslTestPlan.java)
24-
* [ThreadGroupChild](src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java)
25-
* [SamplerChild](src/main/java/us/abstracta/jmeter/javadsl/core/DslSampler.java)
23+
* [TestPlanChild](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslTestPlan.java)
24+
* [ThreadGroupChild](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java)
25+
* [SamplerChild](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslSampler.java)
2626

27-
So, for example, [DslThreadGroup](src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java) implements TestPlanChild and [DslSampler] implements ThreadGroupChild. You might implement multiple interfaces if the element can be used at different levels, for example check [HttpHeaders] and [JtlWriter] implement multiple interfaces.
27+
So, for example, [DslThreadGroup](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslThreadGroup.java) implements TestPlanChild and [DslSampler] implements ThreadGroupChild. You might implement multiple interfaces if the element can be used at different levels, for example check [HttpHeaders] and [JtlWriter] implement multiple interfaces.
2828

2929
You might also implement a new "child" interface if you need additional hierarchy levels (like ControllerChild).
3030

3131
## Test runs
3232

33-
When you want to run a test plan, it needs to run in a JMeter engine. By default, DslTestPlan uses [EmbeddedJMeterEngine](src/main/java/us/abstracta/jmeter/javadsl/core/EmbeddedJmeterEngine.java), which is the fastest and easiest way to run a test plan, but you might use EmbeddedJMeterEngine as an example and implement your own engine (for example to run tests on BlazeMeter, or in a distributed fashion).
33+
When you want to run a test plan, it needs to run in a JMeter engine. By default, DslTestPlan uses [EmbeddedJMeterEngine](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/EmbeddedJmeterEngine.java), which is the fastest and easiest way to run a test plan, but you might use EmbeddedJMeterEngine as an example and implement your own engine (for example to run tests on BlazeMeter, or in a distributed fashion).
3434

35-
When a test plan runs, the engine returns an instance of [TestPlanStats](src/main/java/us/abstracta/jmeter/javadsl/core/TestPlanStats.java), grouping information by test element name (aka label). This allows to check the expected statistics and verify that everything worked within expected boundaries.
35+
When a test plan runs, the engine returns an instance of [TestPlanStats](jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/TestPlanStats.java), grouping information by test element name (aka label). This allows to check the expected statistics and verify that everything worked within expected boundaries.
3636

3737
## Class diagram
3838

@@ -82,12 +82,12 @@ Add proper tests and update documentation (if needed) so users know about the ne
8282

8383
Just create an issue in the repository stating what you need and why, and we will do our best to implement what you need :).
8484

85-
Or, check existing code. It contains embedded documentation with additional detail, and the code never lies.
85+
Or, check existing code. It contains embedded documentation with additional details, and the code never lies.
8686

87-
[JmeterDsl]: src/main/java/us/abstracta/jmeter/javadsl/JmeterDsl.java
88-
[DslTestElement]: src/main/java/us/abstracta/jmeter/javadsl/core/DslTestElement.java
89-
[TestElementContainer]: src/main/java/us/abstracta/jmeter/javadsl/core/TestElementContainer.java
90-
[HttpHeaders]: src/main/java/us/abstracta/jmeter/javadsl/http/HttpHeaders.java
91-
[DslSampler]: src/main/java/us/abstracta/jmeter/javadsl/core/DslSampler.java
92-
[JtlWriter]: src/main/java/us/abstracta/jmeter/javadsl/core/JtlWriter.java
87+
[JmeterDsl]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/JmeterDsl.java
88+
[DslTestElement]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslTestElement.java
89+
[TestElementContainer]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/TestElementContainer.java
90+
[HttpHeaders]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/http/HttpHeaders.java
91+
[DslSampler]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/DslSampler.java
92+
[JtlWriter]: jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/JtlWriter.java
9393
[Core classes section]: #core-classes

README.md

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ If you use [maven](https://maven.apache.org/what-is-maven.html), just include fo
1010
<dependency>
1111
<groupId>us.abstracta.jmeter</groupId>
1212
<projectId>jmeter-java-dsl</projectId>
13-
<version>0.1</version>
13+
<version>0.2</version>
1414
</dependency>
1515
```
1616

@@ -23,7 +23,7 @@ import static us.abstracta.jmeter.javadsl.JmeterDsl.*;
2323
import java.time.Duration;
2424
import org.eclipse.jetty.http.MimeTypes.Type;
2525
import org.junit.jupiter.api.Test;
26-
import us.abstracta.jmeter.javadsl.TestPlanStats;
26+
import us.abstracta.jmeter.javadsl.core.TestPlanStats;
2727

2828
public class PerformanceTest {
2929

@@ -45,9 +45,9 @@ public class PerformanceTest {
4545

4646
> This example also uses [AssertJ](https://joel-costigliola.github.io/assertj/assertj-core-quick-start.html) for assertions, but you can use whatever assertion library you chose.
4747
48-
More examples can be found in [tests](src/test/java/us/abstracta/jmeter/javadsl/JmeterDslTest.java)
48+
More examples can be found in [tests](jmeter-java-dsl/src/test/java/us/abstracta/jmeter/javadsl/JmeterDslTest.java)
4949

50-
> **Tip 1:** Since JMeter uses [log4j2](https://logging.apache.org/log4j/2.x/), if you want to control logging level or output, you can use something similar to the tests included [log4j2.xml](src/test/resources/log4j2.xml).
50+
> **Tip 1:** Since JMeter uses [log4j2](https://logging.apache.org/log4j/2.x/), if you want to control logging level or output, you can use something similar to the tests included [log4j2.xml](jmeter-java-dsl/src/test/resources/log4j2.xml).
5151
>
5252
> **Tip 2:** When working with multiple samplers in a test plan, specify their names to easily check their respective statistics.
5353
@@ -61,7 +61,7 @@ But, JMeter has some problems as well: sometimes might be slow to create test pl
6161

6262
Gatling does provide a simple API and a VCS friendly format, but requires scala knowledge and environment. Additionally, it doesn't provide as rich environment as JMeter (protocol support, plugins, tools) and requires learning a new framework for testing (if you already use JMeter, which is the most popular tool).
6363

64-
[Taurus](https://gettaurus.org/) is another open-source tool that allows specifying tests in a VCS friendly yaml syntax, and provides additional features like pass/fail criteria and easier CI/CD integration. But this tool requires a python environment, in addition to the java environment. Additionally, there is no built-in GUI or IDE auto-completion support, which makes it harder to discover and learn the actual syntax. Finally, Taurus syntax only supports a subset of the features JMeter provides, which reduces scope usage.
64+
[Taurus](https://gettaurus.org/) is another open-source tool that allows specifying tests in a VCS friendly yaml syntax, and provides additional features like pass/fail criteria and easier CI/CD integration. But, this tool requires a python environment, in addition to the java environment. Additionally, there is no built-in GUI or IDE auto-completion support, which makes it harder to discover and learn the actual syntax. Finally, Taurus syntax only supports a subset of the features JMeter provides, which reduces scope usage.
6565

6666
Finally, [ruby-dsl](https://github.com/flood-io/ruby-jmeter) is also an opensource library which allows specifying and run in ruby custom dsl JMeter test plans. This is the most similar tool to jmeter-java-dsl, but it requires ruby (in addition to java environment) with the additional performance impact, does not follow same naming and structure convention as JMeter, and lacks of debugging integration with JMeter execution engine.
6767

@@ -80,16 +80,77 @@ Here is a table with summary of main pros and cons of each tool:
8080

8181
## Additional features
8282

83+
### Run test at scale
84+
85+
Running a load test from one machine is not always enough, since you are limited to the machine hardware capabilities. Some times is necessary to run the test using a cluster of machines to be able to generate enough load for the system under test.
86+
87+
By including following module as dependency:
88+
89+
```xml
90+
<dependency>
91+
<groupId>us.abstracta.jmeter</groupId>
92+
<projectId>jmeter-java-dsl-blazemeter</projectId>
93+
<version>0.2</version>
94+
</dependency>
95+
```
96+
97+
You can easily run a JMeter test plan at scale in BlazeMeter like this:
98+
99+
```java
100+
import static org.assertj.core.api.Assertions.assertThat;
101+
import static us.abstracta.jmeter.javadsl.JmeterDsl.*;
102+
103+
import java.time.Duration;
104+
import org.eclipse.jetty.http.MimeTypes.Type;
105+
import org.junit.jupiter.api.Test;
106+
import us.abstracta.jmeter.javadsl.blazemeter.BlazeMeterEngine;
107+
import us.abstracta.jmeter.javadsl.core.TestPlanStats;
108+
109+
public class PerformanceTest {
110+
111+
@Test
112+
public void testPerformance() throws Exception {
113+
TestPlanStats stats = testPlan(
114+
// number of threads and iterations are in the end overwritten by BlazeMeter engine settings
115+
threadGroup(2, 10,
116+
httpSampler("http://my.service")
117+
.post("{\"name\": \"test\"}", Type.APPLICATION_JSON)
118+
)
119+
).runIn(new BlazeMeterEngine(System.getenv("BZ_TOKEN"))
120+
.testName("DSL test")
121+
.totalUsers(500)
122+
.holdFor(Duration.ofMinutes(10))
123+
.threadsPerEngine(100)
124+
.testTimeout(Duration.ofMinutes(20)));
125+
assertThat(stats.overall().elapsedTimePercentile99()).isLessThan(Duration.ofSeconds(5));
126+
}
127+
128+
}
129+
```
130+
> This test is using `BZ_TOKEN` (a custom environment variable) to get the BlazeMeter API authentication credentials (with `<KEY_ID>:<KEY_SECRET>` format).
131+
132+
Note that is as simple as [generating a BlazeMeter authentication token](https://guide.blazemeter.com/hc/en-us/articles/115002213289-BlazeMeter-API-keys-) and adding `.runIn(new BlazeMeterEngine(...))` to any existing `jmeter-java-dsl` test to get it running at scale in BlazeMeter.
133+
134+
Check [BlazeMeterEngine](jmeter-java-dsl-blazemeter/src/main/java/us/abstracta/jmeter/javadsl/blazemeter/BlazeMeterEngine.java) for details on usage and available settings when running tests in BlazeMeter.
135+
136+
> **Tip:** In case you want to get debug logs for HTTP calls to BlazeMeter API, you can include following setting to an existing `log4j2.xml` configuration file:
137+
>```xml
138+
><Logger name="us.abstracta.jmeter.javadsl.blazemeter.BlazeMeterClient" level="DEBUG"/>
139+
><Logger name="okhttp3" level="DEBUG"/>
140+
>```
141+
83142
### Save as JMX
84143
85144
In case you want to load a test plan in JMeter GUI, you can save it just invoking `saveAsJMX` method in the test plan as in following example:
86145
87146
```java
88147
import static us.abstracta.jmeter.javadsl.JmeterDsl.*;
89148
149+
import org.eclipse.jetty.http.MimeTypes.Type;
150+
90151
public class SaveTestPlanAsJMX {
91152
92-
public static void main(String[] args) throws IOException {
153+
public static void main(String[] args) throws Exception {
93154
testPlan(
94155
threadGroup(2, 10,
95156
httpSampler("http://my.service")
@@ -105,7 +166,7 @@ public class SaveTestPlanAsJMX {
105166
106167
> Take into consideration that currently there is no automatic way to migrate changes done in JMX to the Java DSL.
107168
108-
This can be helpful to share a Java DSL defined test plan with people not used to the DSL, or to use some JMeter feature (or plugin) that is not yet supported by the DSL (**but we strongly encourage you to report it as an issue**, so we can implement support for it).
169+
This can be helpful to share a Java DSL defined test plan with people not used to the DSL, or to use some JMeter feature (or plugin) that is not yet supported by the DSL (**but, we strongly encourage you to report it as an issue**, so we can implement support for it).
109170

110171
## Contributing & Requesting features
111172

checkstyle.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<module name="RightCurly">
3333
<property name="option" value="alone"/>
3434
<property name="tokens"
35-
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
35+
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, STATIC_INIT, INSTANCE_INIT"/>
3636
</module>
3737

3838
<module name="OneTopLevelClass"/>

docs/classes.puml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,20 @@ package core {
3131

3232
class DslTestPlan extends TestElementContainer {
3333
TestPlanStats run()
34+
TestPlanStats runIn(DslJmeterEngine engine)
3435
void saveAsJmx(String filePath)
3536
}
3637

3738
interface TestPlanChild extends DslTestElement {
3839
}
3940

40-
class EmbeddedJmeterEngine {
41+
interface DslJmeterEngine {
4142
TestPlanStats run(DslTestPlan testPlan)
4243
}
4344

45+
class EmbeddedJmeterEngine implements DslJmeterEngine {
46+
}
47+
4448
class DslThreadGroup extends TestElementContainer implements TestPlanChild {
4549
int threads
4650
int iterations

jmeter-java-dsl-blazemeter/pom.xml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>us.abstracta.jmeter</groupId>
9+
<artifactId>jmeter-java-dsl-parent</artifactId>
10+
<version>0.1-SNAPSHOT</version>
11+
<relativePath>../pom.xml</relativePath>
12+
</parent>
13+
<artifactId>jmeter-java-dsl-blazemeter</artifactId>
14+
<version>0.1-SNAPSHOT</version>
15+
16+
<name>${project.artifactId}</name>
17+
<description>Module which allows to easily run jmeter-java-dsl test plans at scale in
18+
BlazeMeter.
19+
</description>
20+
21+
<properties>
22+
<retrofit.version>2.9.0</retrofit.version>
23+
</properties>
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>us.abstracta.jmeter</groupId>
28+
<artifactId>jmeter-java-dsl</artifactId>
29+
<version>${project.version}</version>
30+
</dependency>
31+
<dependency>
32+
<groupId>com.squareup.retrofit2</groupId>
33+
<artifactId>retrofit</artifactId>
34+
<version>${retrofit.version}</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>com.squareup.retrofit2</groupId>
38+
<artifactId>converter-jackson</artifactId>
39+
<version>${retrofit.version}</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>com.github.devcsrj</groupId>
43+
<artifactId>slf4j-okhttp3-logging-interceptor</artifactId>
44+
<version>1.0.1</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>com.fasterxml.jackson.datatype</groupId>
48+
<artifactId>jackson-datatype-jsr310</artifactId>
49+
<version>2.11.3</version>
50+
</dependency>
51+
</dependencies>
52+
53+
</project>

0 commit comments

Comments
 (0)