Skip to content

Commit 9868bff

Browse files
Deprecate milliseconds contracts for timers to keep API consistency with durations
Also fix documentation grammar
1 parent 12f50d7 commit 9868bff

16 files changed

Lines changed: 526 additions & 367 deletions

File tree

README.md

Lines changed: 194 additions & 83 deletions
Large diffs are not rendered by default.

docs/guide/README.md

Lines changed: 206 additions & 208 deletions
Large diffs are not rendered by default.

docs/index.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ actionText: User Guide →
55
actionLink: /guide/
66
features:
77
- title: 💙 Git, IDE & Programmers Friendly
8-
details: Simple way of defining performance tests which takes advantage of IDEs autocompletion and inline documentation.
8+
details: Simple way of defining performance tests that takes advantage of IDEs autocompletion and inline documentation.
99
- title: 💪 JMeter ecosystem & community
10-
details: Use the most popular performance tool and take advantage of wide support of protocols and tools.
10+
details: Use the most popular performance tool and take advantage of the wide support of protocols and tools.
1111
- title: 😎 Built-in features & extensibility
12-
details: Built-in additional features which ease usage (like <a href="guide/#dsl-code-generation-from-jmx-file">jmx2dsl</a>) and CI/CD pipelines integration.
12+
details: Built-in additional features which ease usage (like <a href="guide/#dsl-code-generation-from-jmx-file">jmx2dsl</a>) and CI/CD pipelines integration.
1313
---
1414

1515
## Example

docs/motivation/README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ sidebar: auto
77

88
There are many tools to script performance/load tests, being [JMeter](http://jmeter.apache.org/) and [Gatling](https://gatling.io/) the most popular ones.
99

10+
Here we explore some alternatives, their pros & cons, and the main motivations behind the development of jmeter-java-dsl.
11+
1012
## Alternatives analysis
1113

1214
### JMeter
1315

1416
JMeter is great for people with no programming knowledge since it provides a graphical interface to create test plans and run them. Additionally, it is the most popular tool (with a lot of supporting tools built on it) and has a big amount of supported protocols and plugins making it very versatile.
1517

16-
But, JMeter has some downsides as well: sometimes might be slow to create test plans in JMeter GUI and you can't get the full picture of the test plan unless you dig in every tree node to check its properties. Furthermore, it doesn't provide a simple programmer friendly API (you can check [here](https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui/) for an example on how to run JMeter programmatically without jmeter-java-dsl), nor a Git friendly format (too verbose and hard to review). For example, for this test plan:
18+
But, JMeter has some downsides as well: sometimes it might be slow to create test plans in JMeter GUI and you can't get the full picture of the test plan unless you dig in every tree node to check its properties. Furthermore, it doesn't provide a simple programmer-friendly API (you can check [here](https://www.blazemeter.com/blog/5-ways-launch-jmeter-test-without-using-jmeter-gui/) for an example of how to run JMeter programmatically without jmeter-java-dsl), nor a Git-friendly format (too verbose and hard to review). For example, for this test plan:
1719

1820
```java
1921
import static org.assertj.core.api.Assertions.assertThat;
@@ -48,24 +50,24 @@ In JMeter, you would need a JMX file like [this](../../docs/motivation/sample.jm
4850

4951
### Gatling
5052

51-
Gatling does provide a simple API and a Git friendly format, but requires scala knowledge and environment [[1](#gatling-java)]. 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).
53+
Gatling does provide a simple API and Git-friendly format but requires scala knowledge and environment [[1](#gatling-java)]. Additionally, it doesn't provide as a 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).
5254

5355
### Taurus
5456

55-
[Taurus](https://gettaurus.org/) is another open-source tool that allows specifying tests in a Git 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.
57+
[Taurus](https://gettaurus.org/) is another open-source tool that allows specifying tests in a Git-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.
5658

5759
### ruby-dsl
5860

59-
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.
61+
Finally, [ruby-dsl](https://github.com/flood-io/ruby-jmeter) is also an open-source library that allows specifying and running in ruby custom DSL JMeter test plans. This is the most similar tool to jmeter-java-dsl, but it requires ruby (in addition to the java environment) with the additional performance impact, does not follow the same naming and structure convention as JMeter, and lacks debugging integration with JMeter execution engine.
6062

6163
### jmeter-java-dsl
6264

63-
jmeter-java-dsl tries to get the best of these tools by providing a simple java API with Git friendly format to run JMeter tests, taking advantage of all JMeter benefits and knowledge also providing many of the benefits of Gatling scripting.
64-
As shown in previous example, it can be easily executed with JUnit, modularized in code and easily integrated in any CI/CD pipeline. Additionally, it makes it easy to debug the execution of test plans with usual IDE debugger tools. Finally, as with most Java libraries, you can use it not only in a Java project, but also in projects of most JVM languages (like kotlin, scala, groovy, etc.).
65+
jmeter-java-dsl tries to get the best of these tools by providing a simple java API with Git friendly format to run JMeter tests, taking advantage of all JMeter benefits and knowledge and also providing many of the benefits of Gatling scripting.
66+
As shown in the previous example, it can be easily executed with JUnit, modularized in code, and easily integrated into any CI/CD pipeline. Additionally, it makes it easy to debug the execution of test plans with the usual IDE debugger tools. Finally, as with most Java libraries, you can use it not only in a Java project but also in projects of most JVM languages (like kotlin, scala, groovy, etc.).
6567

6668
## Comparison Table
6769

68-
Here is a table with summary of main pros and cons of each tool:
70+
Here is a table with a summary of the main pros and cons of each tool:
6971

7072
| Tool | Pros | Cons |
7173
|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -76,7 +78,7 @@ Here is a table with summary of main pros and cons of each tool:
7678
| jmeter-java-dsl | 👍 VCS friendly<br/>👍 IDE friendly (auto-complete and debug)<br/>👍 Natural CI/CD integration<br/>👍 Natural code modularization and reuse<br/>👍 Existing JMeter documentation<br/>👍 Easy to add support for JMeter supported protocols and new plugins<br/>👍 Could easily interact with JMX files and take advantage of JMeter ecosystem<br/>👍 All details of simple test plans at a glance<br/>👍 Simple way to do assertions on statistics | 👎 Basic Java knowledge required<br/>👎 Same resources (CPU & RAM) usage as JMeter |
7779

7880
::: tip Notes
79-
1. <a name="gatling-java"></a> One year after jmeter-java-dsl release, on November 2021, Gatling released [3.7 version](https://gatling.io/2021/11/gatling-3-7-java-dsl-kotlin-and-much-more/), including a Java friendly API for existing Gatling Scala API. This greatly simplifies usage for Java users and is a great addition to Gatling.
81+
1. <a name="gatling-java"></a> One year after jmeter-java-dsl release, on November 2021, Gatling released [3.7 version](https://gatling.io/2021/11/gatling-3-7-java-dsl-kotlin-and-much-more/), including a Java friendly API for existing Gatling Scala API. This greatly simplifies usage for Java users and is a great addition to Gatling.
8082

81-
As a side note, take into consideration that underlying code is still Scala and async model based, which makes debugging and understanding it harder for Java developers than JMeter code. Additionally, the model is still tied to `Simulator` classes and maven (gradle or sbt) plugin to be able to run the tests, compared to the simplicity and flexibility of jmeter-java-dsl tests execution.
82-
:::
83+
As a side note, take into consideration that the underlying code is still Scala and async model-based, which makes debugging and understanding it harder for Java developers than JMeter code. Additionally, the model is still tied to `Simulator` classes and maven (gradle or sbt) plugin to be able to run the tests, compared to the simplicity and flexibility of jmeter-java-dsl tests execution.
84+
:::

jmeter-java-dsl-jdbc/src/main/java/us/abstracta/jmeter/javadsl/jdbc/DslJdbcConnectionPool.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.sql.Connection;
55
import java.sql.Driver;
66
import java.time.Duration;
7-
import java.time.temporal.ChronoUnit;
87
import java.util.Collections;
98
import java.util.HashMap;
109
import java.util.List;
@@ -19,7 +18,6 @@
1918
import us.abstracta.jmeter.javadsl.codegeneration.MethodParam;
2019
import us.abstracta.jmeter.javadsl.codegeneration.SingleTestElementCallBuilder;
2120
import us.abstracta.jmeter.javadsl.codegeneration.TestElementParamBuilder;
22-
import us.abstracta.jmeter.javadsl.codegeneration.params.DurationParam;
2321
import us.abstracta.jmeter.javadsl.core.configs.BaseConfigElement;
2422

2523
/**
@@ -209,10 +207,8 @@ protected MethodCall buildMethodCall(DataSourceElement testElement, MethodCallCo
209207
.chain("password", paramBuilder.stringParam("password"))
210208
.chain("autoCommit", paramBuilder.boolParam("autocommit", true))
211209
.chain("maxConnections", paramBuilder.intParam("poolMax", 0))
212-
.chain("maxConnectionWait", paramBuilder.buildParam("timeout",
213-
(expression, defaultValue) -> new DurationParam(expression, defaultValue,
214-
ChronoUnit.MILLIS),
215-
DEFAULT_MAX_CONNECTION_WAIT))
210+
.chain("maxConnectionWait",
211+
paramBuilder.durationParamMillis("timeout", DEFAULT_MAX_CONNECTION_WAIT))
216212
.chain("transactionIsolation", new TransactionIsolationParam(
217213
testElement.getPropertyAsString("transactionIsolation")));
218214
}

jmeter-java-dsl-jmx2dsl/src/test/resources/TestPlan.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
///usr/bin/env jbang "$0" "$@" ; exit $?
22
/*
3-
These commented lines make the class executable if you have jbang installed by making file
3+
These commented lines make the class executable if you have jbang installed by making the file
44
executable (eg: chmod +x ./PerformanceTest.java) and just executing it with ./PerformanceTest.java
55
*/
66
//DEPS org.assertj:assertj-core:3.23.1
@@ -38,8 +38,8 @@ public void test() throws IOException {
3838
}
3939

4040
/*
41-
This method is only included to make test class self executable. You can remove it when
42-
executing tests with maven, gradle or some other tool.
41+
This method is only included to make the test class self-executable. You can remove it when
42+
executing tests with maven, gradle, or some other tool.
4343
*/
4444
public static void main(String[] args) {
4545
SummaryGeneratingListener summaryListener = new SummaryGeneratingListener();

jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/JmeterDsl.java

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,39 +1295,72 @@ public static DslViewResultsTree resultsTreeVisualizer() {
12951295
*
12961296
* @param durationMillis specifies the number of milliseconds for the timer to wait.
12971297
* @return the timer for usage in test plan.
1298+
* @see #constantTimer(Duration)
12981299
* @since 0.62
1300+
* @deprecated as of 0.66, use {@link #constantTimer(Duration)}
12991301
*/
1302+
@Deprecated
13001303
public static DslConstantTimer constantTimer(long durationMillis) {
1301-
return new DslConstantTimer(durationMillis);
1304+
return constantTimer(Duration.ofMillis(durationMillis));
1305+
}
1306+
1307+
/**
1308+
* Builds a Constant Timer which pauses the thread with for a given duration.
1309+
*
1310+
* @param duration specifies the duration for the timer to wait.
1311+
* @return the timer for usage in test plan.
1312+
* @since 0.66
1313+
*/
1314+
public static DslConstantTimer constantTimer(Duration duration) {
1315+
return new DslConstantTimer(duration);
1316+
}
1317+
1318+
/**
1319+
* Builds a Uniform Random Timer which pauses the thread with a random time with uniform
1320+
* distribution.
1321+
*
1322+
* @param minimumMillis is used to set the constant delay of the Uniform Random Timer.
1323+
* @param maximumMillis is used to set the maximum time the timer will be paused and will be used
1324+
* to obtain the random delay from the result of (maximumMillis -
1325+
* minimumMillis).
1326+
* @return The Uniform Random Timer instance
1327+
* @see DslUniformRandomTimer
1328+
* @see #uniformRandomTimer(Duration, Duration)
1329+
* @since 0.16
1330+
* @deprecated as of 0.66, use {@link #uniformRandomTimer(Duration, Duration)}
1331+
*/
1332+
@Deprecated
1333+
public static DslUniformRandomTimer uniformRandomTimer(long minimumMillis, long maximumMillis) {
1334+
return uniformRandomTimer(Duration.ofMillis(minimumMillis), Duration.ofMillis(maximumMillis));
13021335
}
13031336

13041337
/**
13051338
* Builds a Uniform Random Timer which pauses the thread with a random time with uniform
13061339
* distribution.
13071340
*
13081341
* <p>
1309-
* The timer uses the minimumMillis and maximumMillis to define the range of values to be used in
1342+
* The timer uses the minimum and maximum durations to define the range of values to be used in
13101343
* the uniformly distributed selected value. These values differ from the parameters used in
13111344
* JMeter Uniform Random Timer element to make it simpler for general users to use. The generated
1312-
* JMeter test element uses as "constant delay offset" the minimumMillis value, and as "maximum
1313-
* random delay" (maximumMillis - minimumMillis) value.
1345+
* JMeter test element uses as "constant delay offset" the minimum value, and as "maximum
1346+
* random delay" (maximum - minimum) value.
13141347
* </p>
13151348
*
13161349
* <p>
13171350
* EXAMPLE: wait at least 3 seconds and maximum of 10 seconds
1318-
* {@code uniformRandomTimer(3000,10000)}
1351+
* {@code uniformRandomTimer(Duration.ofSeconds(3), Duration.ofSeconds(10))}
13191352
* <p>
13201353
*
1321-
* @param minimumMillis is used to set the constant delay of the Uniform Random Timer.
1322-
* @param maximumMillis is used to set the maximum time the timer will be paused and will be used
1323-
* to obtain the random delay from the result of (maximumMillis -
1324-
* minimumMillis).
1354+
* @param minimum is used to set the constant delay of the Uniform Random Timer.
1355+
* @param maximum is used to set the maximum time the timer will be paused and will be used
1356+
* to obtain the random delay from the result of (maximum -
1357+
* minimum).
13251358
* @return The Uniform Random Timer instance
13261359
* @see DslUniformRandomTimer
1327-
* @since 0.16
1360+
* @since 0.66
13281361
*/
1329-
public static DslUniformRandomTimer uniformRandomTimer(long minimumMillis, long maximumMillis) {
1330-
return new DslUniformRandomTimer(minimumMillis, maximumMillis);
1362+
public static DslUniformRandomTimer uniformRandomTimer(Duration minimum, Duration maximum) {
1363+
return new DslUniformRandomTimer(minimum, maximum);
13311364
}
13321365

13331366
/**

jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/codegeneration/TestElementParamBuilder.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.nio.charset.Charset;
44
import java.time.Duration;
5+
import java.time.temporal.ChronoUnit;
56
import java.util.function.BiFunction;
67
import org.apache.jmeter.testelement.TestElement;
78
import org.apache.jmeter.testelement.property.JMeterProperty;
@@ -236,6 +237,22 @@ public MethodParam durationParam(String propName) {
236237
return durationParam(propName, null);
237238
}
238239

240+
/**
241+
* Gets a MethodParam representing a test element property containing a duration (in
242+
* milliseconds).
243+
*
244+
* @param propName is the name of the property. For nested properties (a property that is
245+
* inside another object property) you can use the slash character to separate
246+
* the levels (eg: http_config/use_proxy).
247+
* @param defaultValue the default value assigned to the JMeter test element property.
248+
* @return the {@link MethodParam} instance.
249+
*/
250+
public MethodParam durationParamMillis(String propName, Duration defaultValue) {
251+
return buildParam(propName,
252+
(expression, defValue) -> new DurationParam(expression, defValue, ChronoUnit.MILLIS),
253+
defaultValue);
254+
}
255+
239256
/**
240257
* Gets a MethodParam representing a test element property with a restricted set (enumerated) of
241258
* string values.

jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/samplers/DslDummySampler.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.lang.reflect.Method;
44
import java.time.Duration;
5-
import java.time.temporal.ChronoUnit;
65
import java.util.List;
76
import kg.apc.jmeter.dummy.DummyElement;
87
import kg.apc.jmeter.samplers.DummySampler;
@@ -12,7 +11,6 @@
1211
import us.abstracta.jmeter.javadsl.codegeneration.MethodCallContext;
1312
import us.abstracta.jmeter.javadsl.codegeneration.SingleTestElementCallBuilder;
1413
import us.abstracta.jmeter.javadsl.codegeneration.TestElementParamBuilder;
15-
import us.abstracta.jmeter.javadsl.codegeneration.params.DurationParam;
1614
import us.abstracta.jmeter.javadsl.core.util.JmeterFunction;
1715

1816
/**
@@ -189,9 +187,7 @@ protected MethodCall buildMethodCall(DummySampler testElement, MethodCallContext
189187
.chain("responseCode", paramBuilder.stringParam("RESPONSE_CODE", DEFAULT_RESPONSE_CODE))
190188
.chain("responseMessage",
191189
paramBuilder.stringParam("RESPONSE_MESSAGE", DEFAULT_RESPONSE_MESSAGE))
192-
.chain("responseTime", paramBuilder.buildParam("RESPONSE_TIME",
193-
(expression, defaultValue) -> new DurationParam(expression, null, ChronoUnit.MILLIS),
194-
null))
190+
.chain("responseTime", paramBuilder.durationParamMillis("RESPONSE_TIME", null))
195191
.chain("simulateResponseTime", paramBuilder.boolParam("WAITING", false))
196192
.chain("url", paramBuilder.stringParam("URL"))
197193
.chain("requestBody", paramBuilder.stringParam("REQUEST_DATA"));

0 commit comments

Comments
 (0)