Skip to content

Commit 2fc22a1

Browse files
Merge pull request #318 from abstracta/WEB_SOCKETS
Web sockets
2 parents 325c554 + 97da1c4 commit 2fc22a1

File tree

24 files changed

+1189
-56
lines changed

24 files changed

+1189
-56
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

docs/guide/protocols/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
<!-- @include: jdbc.md -->
66
<!-- @include: java.md -->
77
<!-- @include: selenium.md -->
8+
<!-- @include: websocket.md -->

docs/guide/protocols/websocket.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
### WebSocket
2+
3+
The `DslWebsocketSampler` class provides a Java DSL for creating WebSocket performance tests using JMeter. It supports the full WebSocket lifecycle including connection, data transmission, and disconnection operations. It is based on [WebSocket Samplers by Peter Doornbosch](https://bitbucket.org/pjtr/jmeter-websocket-samplers/src/master/) plugin.
4+
5+
To use it, add the following dependency to your project:
6+
7+
:::: code-group
8+
::: code-group-item Maven
9+
```xml
10+
<dependency>
11+
<groupId>us.abstracta.jmeter</groupId>
12+
<artifactId>jmeter-java-dsl-websocket</artifactId>
13+
<version>2.2</version>
14+
<scope>test</scope>
15+
</dependency>
16+
```
17+
:::
18+
::: code-group-item Gradle
19+
```groovy
20+
testImplementation 'us.abstracta.jmeter:jmeter-java-dsl-websocket:2.2'
21+
```
22+
:::
23+
::::
24+
25+
26+
27+
Below you can see a basic usage example of WebSocket protocol.
28+
29+
```java
30+
import static us.abstracta.jmeter.javadsl.JmeterDsl.*;
31+
import static us.abstracta.jmeter.javadsl.websocket.WebsocketJMeterDsl.*;
32+
import us.abstracta.jmeter.javadsl.core.TestPlanStats;
33+
34+
public class Test {
35+
public static void main(String[] args) throws Exception {
36+
TestPlanStats stats = testPlan(
37+
threadGroup(1, 1,
38+
websocketConnect("wss://ws.postman-echo.com/raw"),
39+
websocketWrite("Hello WebSocket!"),
40+
websocketRead()
41+
.children(
42+
responseAssertion()
43+
.equalsToStrings("Hello WebSocket!")
44+
),
45+
websocketDisconnect()
46+
)
47+
).run();
48+
}
49+
}
50+
```
51+
52+
::: warning
53+
Only `ws://` and `wss://` protocols are supported. Using any other scheme will throw an `IllegalArgumentException`.
54+
:::
55+
56+
::: tip
57+
You can use a non-blocking read if necessary in the following way:
58+
59+
```java
60+
websocketRead().waitForResponse(false)
61+
```
62+
63+
In this case, it is not recommended to add an assertion because the response could be empty.
64+
:::
65+
66+
::: warning
67+
The WebSocket plugin only supports one connection per thread at a time. If you want to change the WebSocket server during execution, you should add a disconnect sampler and then establish a new connection.
68+
:::

jmeter-java-dsl-cli/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@
6565
<artifactId>jmeter-java-dsl-recorder</artifactId>
6666
<version>${project.version}</version>
6767
</dependency>
68+
<dependency>
69+
<groupId>us.abstracta.jmeter</groupId>
70+
<artifactId>jmeter-java-dsl-websocket</artifactId>
71+
<version>${project.version}</version>
72+
</dependency>
6873
<dependency>
6974
<groupId>org.slf4j</groupId>
7075
<artifactId>jul-to-slf4j</artifactId>
@@ -165,6 +170,7 @@
165170
<include>com.blazemeter:jmeter-plugins-random-csv-data-set</include>
166171
<include>com.blazemeter:jmeter-plugins-wsc</include>
167172
<include>com.blazemeter:jmeter-parallel</include>
173+
<include>net.luminis.jmeter:jmeter-websocket-samplers</include>
168174
<include>info.picocli:*</include>
169175
<include>com.fifesoft:rsyntaxtextarea</include>
170176
<include>com.github.weisj:darklaf-extensions-rsyntaxarea</include>

jmeter-java-dsl-cli/src/main/java/us/abstracta/jmeter/javadsl/cli/Jmx2DslCommand.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import us.abstracta.jmeter.javadsl.graphql.DslGraphqlSampler;
1212
import us.abstracta.jmeter.javadsl.jdbc.JdbcJmeterDsl;
1313
import us.abstracta.jmeter.javadsl.parallel.ParallelController;
14+
import us.abstracta.jmeter.javadsl.websocket.WebsocketJMeterDsl;
1415
import us.abstracta.jmeter.javadsl.wrapper.WrapperJmeterDsl;
1516

1617
@Command(name = "jmx2dsl", header = "Converts a JMX file to DSL code",
@@ -48,6 +49,7 @@ public Integer call() throws Exception {
4849
addBuildersFrom(ElasticsearchBackendListener.class, "jmeter-java-dsl-elasticsearch-listener",
4950
codeGenerator);
5051
addBuildersFrom(DatadogBackendListener.class, "jmeter-java-dsl-datadog", codeGenerator);
52+
addBuildersFrom(WebsocketJMeterDsl.class, "jmeter-java-dsl-websocket", codeGenerator);
5153
System.out.println(codeGenerator.generateCodeFromJmx(jmxFile));
5254
return 0;
5355
}

jmeter-java-dsl-octoperf/src/main/java/us/abstracta/jmeter/javadsl/octoperf/OctoPerfEngine.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
import us.abstracta.jmeter.javadsl.octoperf.api.Scenario;
3232
import us.abstracta.jmeter.javadsl.octoperf.api.TableEntry;
3333
import us.abstracta.jmeter.javadsl.octoperf.api.User;
34-
import us.abstracta.jmeter.javadsl.octoperf.api.UserLoad;
35-
import us.abstracta.jmeter.javadsl.octoperf.api.UserLoad.UserLoadRampUp;
34+
import us.abstracta.jmeter.javadsl.octoperf.api.UserProfile;
35+
import us.abstracta.jmeter.javadsl.octoperf.api.UserProfile.UserLoadRampUp;
3636
import us.abstracta.jmeter.javadsl.octoperf.api.VirtualUser;
3737
import us.abstracta.jmeter.javadsl.octoperf.api.Workspace;
3838

@@ -264,8 +264,8 @@ private Scenario buildScenario(User user, Project project, List<VirtualUser> vus
264264
HashTree tree) throws IOException {
265265
Provider provider = apiClient.findProviderByWorkspace(project.getWorkspace());
266266
String defaultRegion = provider.getRegions().keySet().iterator().next();
267-
List<UserLoad> userLoads = vus.stream()
268-
.map(vu -> new UserLoad(vu.getId(), provider.getId(), defaultRegion,
267+
List<UserProfile> userLoads = vus.stream()
268+
.map(vu -> new UserProfile(vu.getId(), provider.getId(), defaultRegion,
269269
buildUserLoadConfig(tree)))
270270
.collect(Collectors.toList());
271271
Scenario ret = apiClient.createScenario(

jmeter-java-dsl-octoperf/src/main/java/us/abstracta/jmeter/javadsl/octoperf/api/Scenario.java

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import com.fasterxml.jackson.annotation.JsonIgnore;
55
import com.fasterxml.jackson.annotation.JsonProperty;
66
import java.time.Instant;
7-
import java.util.Collections;
87
import java.util.List;
98
import java.util.Set;
109

@@ -16,12 +15,11 @@ public class Scenario {
1615
private final String projectId;
1716
private final String name;
1817
private final String description = "";
19-
private final List<UserLoad> userLoads;
18+
private final List<UserProfile> userProfiles;
2019
private final String mode = "STANDARD";
2120
private final Instant created = Instant.now();
2221
private final Instant lastModified = Instant.now();
2322
private final Set<String> tags;
24-
private final BackendListenerSettings backendListeners = new BackendListenerSettings();
2523
private Project project;
2624

2725
@JsonCreator
@@ -30,18 +28,18 @@ public Scenario(@JsonProperty("id") String id, @JsonProperty("tags") Set<String>
3028
this.userId = null;
3129
this.projectId = null;
3230
this.name = null;
33-
this.userLoads = null;
31+
this.userProfiles = null;
3432
this.tags = tags;
3533
}
3634

37-
public Scenario(User user, Project project, String name, List<UserLoad> userLoads,
35+
public Scenario(User user, Project project, String name, List<UserProfile> userProfiles,
3836
Set<String> tags) {
3937
this.id = "";
4038
this.userId = user.getId();
4139
this.project = project;
4240
this.projectId = project.getId();
4341
this.name = name;
44-
this.userLoads = userLoads;
42+
this.userProfiles = userProfiles;
4543
this.tags = tags;
4644
}
4745

@@ -67,15 +65,4 @@ public String getUrl() {
6765
return project.getBaseUrl() + "/runtime/scenario/" + id;
6866
}
6967

70-
public static class BackendListenerSettings {
71-
72-
private final int queueSize = 5000;
73-
private final List<BackendListener> listeners = Collections.emptyList();
74-
75-
}
76-
77-
public static class BackendListener {
78-
79-
}
80-
8168
}

jmeter-java-dsl-octoperf/src/main/java/us/abstracta/jmeter/javadsl/octoperf/api/UserLoad.java renamed to jmeter-java-dsl-octoperf/src/main/java/us/abstracta/jmeter/javadsl/octoperf/api/UserProfile.java

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,37 +12,30 @@
1212
import org.apache.jmeter.threads.ThreadGroup;
1313
import us.abstracta.jmeter.javadsl.core.threadgroups.BaseThreadGroup.SampleErrorAction;
1414

15-
public class UserLoad {
15+
public class UserProfile {
1616

1717
// we don't need getters since Jackson gets the values from fields
1818
private final String name = "";
1919
private final String virtualUserId;
2020
private final String providerId;
21-
private final String region;
22-
private final UserLoadStrategy strategy;
23-
private final BandwidthSettings bandwidth = new BandwidthSettings();
24-
private final BrowserSettings browser = new BrowserSettings();
25-
private final DnsSettings dns = new DnsSettings();
26-
private final ThinkTimeSettings thinktime = new ThinkTimeSettings();
21+
private final String location;
22+
private final UserLoadStrategy load;
2723
private final MemorySettings memory = new MemorySettings();
28-
private final JtlSettings jtl = new JtlSettings();
29-
private final PropertiesSettings properties = new PropertiesSettings();
30-
private final SetUpTearDownSettings setUp = null;
31-
private final SetUpTearDownSettings tearDown = null;
24+
private final Engine engine = new Engine();
3225

33-
public UserLoad() {
26+
public UserProfile() {
3427
virtualUserId = null;
3528
providerId = null;
36-
region = null;
37-
strategy = null;
29+
location = null;
30+
load = null;
3831
}
3932

40-
public UserLoad(String virtualUserId, String providerId, String region,
33+
public UserProfile(String virtualUserId, String providerId, String location,
4134
UserLoadStrategy strategy) {
4235
this.virtualUserId = virtualUserId;
4336
this.providerId = providerId;
44-
this.region = region;
45-
this.strategy = strategy;
37+
this.location = location;
38+
this.load = strategy;
4639
}
4740

4841
@JsonTypeInfo(use = NAME, include = PROPERTY)
@@ -53,25 +46,24 @@ public abstract static class UserLoadStrategy {
5346

5447
}
5548

56-
@JsonTypeName("UserLoadRampup")
49+
@JsonTypeName("UserProfileLoadRampUp")
5750
public static class UserLoadRampUp extends UserLoadStrategy {
5851

59-
private final int userload;
60-
private final long rampup;
61-
private final long peak;
62-
private final long delay = 0;
63-
private final SampleErrorAction onSampleError = SampleErrorAction.CONTINUE;
52+
private final int plateauVus;
53+
private final long rampUpMs;
54+
private final long plateauMs;
55+
private final long delayMs = 0;
6456

6557
public UserLoadRampUp() {
66-
userload = 0;
67-
rampup = 0;
68-
peak = 0;
58+
plateauVus = 0;
59+
rampUpMs = 0;
60+
plateauMs = 0;
6961
}
7062

7163
public UserLoadRampUp(int userLoad, long rampUpMillis, long peakMillis) {
72-
this.userload = userLoad;
73-
this.rampup = rampUpMillis;
74-
this.peak = peakMillis;
64+
this.plateauVus = userLoad;
65+
this.rampUpMs = rampUpMillis;
66+
this.plateauMs = peakMillis;
7567
}
7668

7769
public static UserLoadRampUp fromThreadGroup(ThreadGroup threadGroup) {
@@ -85,6 +77,39 @@ public static UserLoadRampUp fromThreadGroup(ThreadGroup threadGroup) {
8577

8678
}
8779

80+
@JsonTypeInfo(use = NAME, include = PROPERTY)
81+
@JsonTypeName("JmeterUserProfileEngine")
82+
public static class Engine {
83+
84+
private final EngineSettings settings = new EngineSettings();
85+
private final BrowserSettings browser = new BrowserSettings();
86+
private final BandwidthSettings bandwidth = new BandwidthSettings();
87+
private final DnsSettings dns = new DnsSettings();
88+
private final JtlSettings jtl = new JtlSettings();
89+
private final PropertiesSettings properties = new PropertiesSettings();
90+
91+
}
92+
93+
public static class EngineSettings {
94+
95+
private final ExternalLiveReportingSettings externalLiveReporting =
96+
new ExternalLiveReportingSettings();
97+
private final SampleErrorAction errorHandling = SampleErrorAction.CONTINUE;
98+
private final ThinkTimeSettings thinkTime = new ThinkTimeSettings();
99+
private final SetUpTearDownSettings setUp = null;
100+
private final SetUpTearDownSettings tearDown = null;
101+
102+
}
103+
104+
@JsonTypeInfo(use = NAME, include = PROPERTY)
105+
@JsonTypeName("JmeterExternalLiveReportingSettings")
106+
public static class ExternalLiveReportingSettings {
107+
108+
private final List<String> listeners = Collections.emptyList();
109+
private final int queueSize = 5000;
110+
111+
}
112+
88113
public static class SetUpTearDownSettings {
89114

90115
}
@@ -102,6 +127,8 @@ public static class BrowserSettings {
102127
private final String userAgent = "";
103128
private final CacheManager cache = new CacheManager();
104129
private final CookiesManager cookies = new CookiesManager();
130+
private final Boolean downloadResources = null;
131+
private final Boolean keepAlive = null;
105132

106133
}
107134

jmeter-java-dsl-octoperf/src/test/java/us/abstracta/jmeter/javadsl/octoperf/OctoPerfEngineTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import static us.abstracta.jmeter.javadsl.JmeterDsl.threadGroup;
77

88
import java.time.Duration;
9-
import java.util.HashMap;
10-
import java.util.Map;
119
import org.junit.jupiter.api.Test;
1210
import us.abstracta.jmeter.javadsl.core.TestPlanStats;
1311

jmeter-java-dsl-websocket/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
<parent>
7+
<groupId>us.abstracta.jmeter</groupId>
8+
<artifactId>jmeter-java-dsl-parent</artifactId>
9+
<version>2.2-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<artifactId>jmeter-java-dsl-websocket</artifactId>
14+
15+
<dependencies>
16+
<dependency>
17+
<groupId>us.abstracta.jmeter</groupId>
18+
<artifactId>jmeter-java-dsl</artifactId>
19+
<version>${project.version}</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>net.luminis.jmeter</groupId>
23+
<artifactId>jmeter-websocket-samplers</artifactId>
24+
<version>1.3.1</version>
25+
<exclusions>
26+
<exclusion>
27+
<groupId>org.apache.jmeter</groupId>
28+
<artifactId>ApacheJMeter_core</artifactId>
29+
</exclusion>
30+
<exclusion>
31+
<groupId>org.apache.jmeter</groupId>
32+
<artifactId>jorphan</artifactId>
33+
</exclusion>
34+
</exclusions>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.java-websocket</groupId>
38+
<artifactId>Java-WebSocket</artifactId>
39+
<version>1.6.0</version>
40+
<scope>test</scope>
41+
</dependency>
42+
</dependencies>
43+
44+
</project>

0 commit comments

Comments
 (0)