Skip to content

Commit 5d14128

Browse files
Add counter for easy generation of auto increment values.
1 parent c75500b commit 5d14128

File tree

7 files changed

+169
-9
lines changed

7 files changed

+169
-9
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
### Counter
2+
3+
In scenarios that you need unique value for each request, for example for id parameters, you can use `counter` which provides easy means to have an auto incremental value that can be used in requests.
4+
5+
Here is an example:
6+
7+
```java
8+
testPlan(
9+
threadGroup(1, 10,
10+
counter("USER_ID")
11+
.startingValue(1000), // will generate 1000, 1001, 1002...
12+
httpSampler(wiremockUri + "/${USER_ID}")
13+
)
14+
).run();
15+
```
16+
17+
Check [DslCounter](/jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/configs/DslCounter.java) for more details.

docs/guide/request-generation/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
@include(if-controller.md)
44
@include(loops/index.md)
5-
@include(jsr223-pre-processor.md)
6-
@include(csv-dataset.md)
75
@include(transaction-controller.md)
6+
@include(csv-dataset.md)
7+
@include(counter.md)
8+
@include(jsr223-pre-processor.md)
89
@include(timers.md)
910
@include(throughput-timer.md)
1011
@include(percent-controller.md)

docs/guide/request-generation/jsr223-pre-processor.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
### Provide request parameters programmatically per request
22

3-
With the standard DSL you can provide static values to request parameters, such as a body. However, you may also want to be able to modify your requests for each call. This is common in cases where your request creates something that must have unique values.
3+
So far we have seen a few ways to generate requests with information extracted from CSV or through a counter, but this is not enough for some scenarios. When you need more flexibility and power you can use `jsr223preProcessor` to specify your own logic to build each request.
44

5-
Here is an example of how to achieve this:
5+
Here is an example:
66

77
```java
88
import static org.assertj.core.api.Assertions.assertThat;
@@ -59,4 +59,8 @@ post(s -> buildRequestBody(s.vars), Type.TEXT_PLAIN)
5959
Using java code (lambdas) will only work with embedded JMeter engine (no support for saving to JMX and running it in JMeter GUI, or running it with BlazeMeter or OctoPerf). Use the first option to avoid such limitations.
6060
:::
6161

62+
::: tip
63+
`jsr223PreProcessor` is quite powerful. But, provided example can easily be achieved through the usage of [counter element](./counter#counter).
64+
:::
65+
6266
Check [DslJsr223PreProcessor](/jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/core/preprocessors/DslJsr223PreProcessor.java) & [DslHttpSampler](/jmeter-java-dsl/src/main/java/us/abstracta/jmeter/javadsl/http/DslHttpSampler.java) for more details and additional options.

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import us.abstracta.jmeter.javadsl.core.DslTestPlan;
99
import us.abstracta.jmeter.javadsl.core.DslTestPlan.TestPlanChild;
1010
import us.abstracta.jmeter.javadsl.core.assertions.DslResponseAssertion;
11+
import us.abstracta.jmeter.javadsl.core.configs.DslCounter;
1112
import us.abstracta.jmeter.javadsl.core.configs.DslCsvDataSet;
1213
import us.abstracta.jmeter.javadsl.core.configs.DslVariables;
1314
import us.abstracta.jmeter.javadsl.core.controllers.DslForEachController;
@@ -98,10 +99,11 @@ public static DslTestPlan testPlan(TestPlanChild... children) {
9899
* thread group is configured to stop on error, or some other explicit
99100
* termination condition).
100101
* <p>
101-
* <b>Setting this property to -1 is in general not advised</b>, since you might
102-
* inadvertently end up running a test plan without
103-
* limits consuming unnecessary computing power. Prefer specifying a big value
104-
* as a safe limit for iterations or duration instead.
102+
* <b>Setting this property to -1 is in general not advised</b>, since you
103+
* might
104+
* inadvertently end up running a test plan without limits consuming unnecessary
105+
* computing power. Prefer specifying a big value as a safe limit for iterations
106+
* or duration instead.
105107
* @param children contains the test elements that each thread will execute in each iteration.
106108
* @return the thread group instance.
107109
* @see DslDefaultThreadGroup
@@ -1455,6 +1457,19 @@ public static DslCsvDataSet csvDataSet(TestResource resource) {
14551457
return new DslCsvDataSet(resource.filePath());
14561458
}
14571459

1460+
/**
1461+
* Builds a counter for easy usage of auto incremental numbers in test plans.
1462+
* <p>
1463+
* This element is handy when generating uto incremental ids, positions in a list, etc.
1464+
*
1465+
* @param name specifies the variable name used for holding the counter value.
1466+
* @return the counter for further configuration and usage.
1467+
* @since 1.10
1468+
*/
1469+
public static DslCounter counter(String name) {
1470+
return new DslCounter(name);
1471+
}
1472+
14581473
/**
14591474
* Allows easy usage of test resources like the ones in {@code src/test/resource} in maven
14601475
* projects.

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,21 @@ public JMeterProperty prop(String propName) {
133133
/**
134134
* Generates a MethodParam representing a long test element property.
135135
*
136+
* @param propName is the name of the property holding a long value. For nested properties (a
137+
* property that is inside another object property) you can use the slash
138+
* character to separate the levels (eg: http_config/use_proxy).
139+
* @param defaultValue is the default value used by the test element for this property.
140+
* @return the MethodParam instance.
141+
* @throws UnsupportedOperationException when no long can be parsed from the property value.
142+
* @since 1.10
143+
*/
144+
public MethodParam longParam(String propName, Long defaultValue) {
145+
return buildParam(propName, LongParam::new, defaultValue);
146+
}
147+
148+
/**
149+
* Same as {@link #longParam(String, Long)} but with no default value.
150+
*
136151
* @param propName is the name of the property holding a long value. For nested properties (a
137152
* property that is inside another object property) you can use the slash
138153
* character to separate the levels (eg: http_config/use_proxy).
@@ -141,7 +156,7 @@ public JMeterProperty prop(String propName) {
141156
* @since 0.61
142157
*/
143158
public MethodParam longParam(String propName) {
144-
return buildParam(propName, LongParam::new, (Long) null);
159+
return longParam(propName, null);
145160
}
146161

147162
/**
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package us.abstracta.jmeter.javadsl.core.configs;
2+
3+
import java.lang.reflect.Method;
4+
import java.util.List;
5+
import org.apache.jmeter.modifiers.CounterConfig;
6+
import org.apache.jmeter.modifiers.gui.CounterConfigGui;
7+
import org.apache.jmeter.testelement.TestElement;
8+
import us.abstracta.jmeter.javadsl.codegeneration.MethodCall;
9+
import us.abstracta.jmeter.javadsl.codegeneration.MethodCallContext;
10+
import us.abstracta.jmeter.javadsl.codegeneration.SingleTestElementCallBuilder;
11+
import us.abstracta.jmeter.javadsl.codegeneration.TestElementParamBuilder;
12+
13+
/**
14+
* Allows easy usage of auto incremental values in test plans.
15+
* <p>
16+
* This element is handy for generating incremental IDs, positions in certain list, etc.
17+
*
18+
* @since 1.10
19+
*/
20+
public class DslCounter extends BaseConfigElement {
21+
22+
private final String varName;
23+
private String start = "0";
24+
25+
public DslCounter(String varName) {
26+
super(varName, CounterConfigGui.class);
27+
this.varName = varName;
28+
}
29+
30+
/**
31+
* Allows specifying the starting value of the counter.
32+
*
33+
* @param start specifies the value to start the counter with. When not specified, 0 will be
34+
* used.
35+
* @return the counter for further configuration and usage.
36+
*/
37+
public DslCounter startingValue(long start) {
38+
return startingValue(String.valueOf(start));
39+
}
40+
41+
/**
42+
* Same as {@link #startingValue(long)} but allowing to use JMeter expressions for starting
43+
* value.
44+
* <p>
45+
* This method allows to extract the initial value of the counter for example from a JMeter
46+
* property (eg: ${__P(COUNT_INIT)}).
47+
*
48+
* @param start specifies a jmeter expression evaluating to a number that specifies the initial
49+
* value for the counter.
50+
* @return the counter for further configuration and usage.
51+
*/
52+
public DslCounter startingValue(String start) {
53+
this.start = start;
54+
return this;
55+
}
56+
57+
@Override
58+
protected TestElement buildTestElement() {
59+
CounterConfig ret = new CounterConfig();
60+
ret.setVarName(varName);
61+
ret.setStart(start);
62+
ret.setIncrement(1);
63+
return ret;
64+
}
65+
66+
public static class CodeBuilder extends SingleTestElementCallBuilder<CounterConfig> {
67+
68+
public CodeBuilder(List<Method> builderMethods) {
69+
super(CounterConfig.class, builderMethods);
70+
}
71+
72+
@Override
73+
protected MethodCall buildMethodCall(CounterConfig testElement, MethodCallContext context) {
74+
TestElementParamBuilder paramBuilder = new TestElementParamBuilder(testElement,
75+
"CounterConfig");
76+
MethodCall ret = buildMethodCall(paramBuilder.stringParam("name"));
77+
ret.chain("startingValue", paramBuilder.longParam("start", 0L));
78+
return ret;
79+
}
80+
81+
}
82+
83+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package us.abstracta.jmeter.javadsl.core.configs;
2+
3+
import static com.github.tomakehurst.wiremock.client.WireMock.*;
4+
import static us.abstracta.jmeter.javadsl.JmeterDsl.*;
5+
6+
import org.junit.jupiter.api.Test;
7+
import us.abstracta.jmeter.javadsl.JmeterDslTest;
8+
9+
public class DslCounterTest extends JmeterDslTest {
10+
11+
@Test
12+
public void shouldUseIncrementalValuesInRequestWhenCounterInRequest() throws Exception {
13+
int startingValue = 1;
14+
testPlan(
15+
threadGroup(1, 2,
16+
counter("USER_ID")
17+
.startingValue(startingValue),
18+
httpSampler(wiremockUri + "/${USER_ID}")
19+
)
20+
).run();
21+
verify(getRequestedFor(urlEqualTo("/" + startingValue)));
22+
verify(getRequestedFor(urlEqualTo("/" + (startingValue + 1))));
23+
}
24+
25+
}

0 commit comments

Comments
 (0)