Skip to content

Commit 78868aa

Browse files
author
Mark Pollack
committed
Framework smoke matrix: the Spring WebSocket agent cell
The servlet host now takes the WebSocket upgrade on server.port, so the Spring agent serves ws as well as http: smoke.json moves ws from pendingAgentTransports into agentTransports, the launcher accepts --transport ws (spring.acp.agent.transport.type=websocket), and the generated fw-spring-agent-ws cell joins the matrix. The Spring program depends on acp-http-servlet, the module a servlet web application needs, instead of acp-streamable-http-jetty.
1 parent 0380b28 commit 78868aa

5 files changed

Lines changed: 80 additions & 16 deletions

File tree

‎integration-testing/README.md‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,10 @@ the commit being released (`framework-smoke.yml`, or the local command below), n
157157

158158
| Framework | Agent transports | Client | Program |
159159
|---|---|---|---|
160-
| Spring Boot 4.1 | stdio (`spring.main.keep-alive=true`), HTTP (the SDK servlet on `server.port` in a servlet web application) | HTTP | [programs/spring](programs/spring) |
160+
| Spring Boot 4.1 | stdio (`spring.main.keep-alive=true`), HTTP and WebSocket (the SDK servlet, `acp-http-servlet`, on `server.port` in a servlet web application) | HTTP | [programs/spring](programs/spring) |
161161
| Micronaut 4 | stdio, HTTP, WebSocket (the SDK listener) | HTTP | [programs/micronaut](programs/micronaut) |
162162
| Quarkus | stdio, HTTP, WebSocket (the Quarkus HTTP server); one package per build-time transport | HTTP | [programs/quarkus](programs/quarkus) |
163163

164-
Spring has no WebSocket cell yet: the servlet takes no WebSocket upgrades on `server.port`. When it
165-
does, add `"ws"` to `frameworks.spring.agentTransports` in `smoke.json` (it is listed under
166-
`pendingAgentTransports` until then) and regenerate.
167-
168164
The agent handlers ([programs/framework/.../SmokeAgent.java](programs/framework/src/main/java/interop/framework/SmokeAgent.java))
169165
and the client steps ([SmokeClient.java](programs/framework/src/main/java/interop/framework/SmokeClient.java))
170166
are shared sources that every framework program compiles in; each framework adds only an
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"name": "fw-spring-agent-ws",
3+
"description": "typescript client -> spring-hosted java agent over ws, 13 smoke steps (generated from smoke.json)",
4+
"timeoutSec": 365,
5+
"peers": [
6+
"typescript-sdk"
7+
],
8+
"processes": [
9+
{
10+
"name": "agent",
11+
"language": "java",
12+
"role": "server",
13+
"dir": "${ROOT}/programs/spring",
14+
"build": "IT_ROOT=\"${ROOT}\" MVNW=\"${MVNW}\" ACP_VERSION=\"${ACP_VERSION}\" CACHE=\"${CACHE}\" ${ROOT}/programs/spring/launch/build.sh",
15+
"run": "${ROOT}/programs/spring/launch/agent.sh --transport ws --port ${PORT}",
16+
"env": {
17+
"TS_SDK": "${peer.typescript-sdk}"
18+
},
19+
"ready": {
20+
"line": "READY",
21+
"timeoutSec": 90
22+
}
23+
},
24+
{
25+
"name": "client",
26+
"language": "typescript",
27+
"role": "client",
28+
"dir": "${ROOT}/programs/node",
29+
"build": "IT_ROOT=\"${ROOT}\" MVNW=\"${MVNW}\" ACP_VERSION=\"${ACP_VERSION}\" CACHE=\"${CACHE}\" TS_SDK=\"${peer.typescript-sdk}\" ${ROOT}/programs/node/launch/build.sh",
30+
"run": "${ROOT}/programs/node/launch/client.sh --transport ws --url ws://127.0.0.1:${PORT}/acp",
31+
"env": {
32+
"STEPS": "init.initialize,init.agent-capabilities,init.agent-info,session.new,session.load,session.multi,update.agent_message_chunk,perm.selected,elicit.form,cancel.prompt,ext.client-request,error.method-not-found,conn.close",
33+
"TS_SDK": "${peer.typescript-sdk}"
34+
},
35+
"timeoutSec": 185
36+
}
37+
],
38+
"assertions": {
39+
"requiredOutput": {
40+
"agent": [
41+
"STEP agent.perm.selected PASS",
42+
"STEP agent.elicit.form PASS",
43+
"STEP agent.cancel.prompt PASS"
44+
]
45+
},
46+
"forbiddenOutput": {
47+
"agent": [
48+
" ERROR ",
49+
" WARN "
50+
]
51+
},
52+
"requiredPatterns": {
53+
"client": [
54+
"STEP init\\.initialize PASS .*\"name\":\"interop-spring-agent\""
55+
]
56+
},
57+
"checks": [
58+
"client RESULT pass == 13",
59+
"client RESULT fail == 0"
60+
],
61+
"expectedFailures": [],
62+
"report": {
63+
"client": [
64+
"TIMEOUT"
65+
]
66+
}
67+
},
68+
"comment": "GENERATED by GenConfigs.java from smoke.json, steps.json and matrix.json; do not edit, regenerate."
69+
}

‎integration-testing/programs/spring/pom.xml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,14 @@
4444
<version>${acp.version}</version>
4545
</dependency>
4646
<!-- spring.acp.agent.transport.type=http in a servlet web application: the SDK's servlet,
47-
mounted on the application's own server (server.port) -->
47+
mounted on the application's own server (server.port), Streamable HTTP and WebSocket -->
4848
<dependency>
4949
<groupId>org.springframework.boot</groupId>
5050
<artifactId>spring-boot-starter-webmvc</artifactId>
5151
</dependency>
5252
<dependency>
5353
<groupId>com.agentclientprotocol</groupId>
54-
<artifactId>acp-streamable-http-jetty</artifactId>
54+
<artifactId>acp-http-servlet</artifactId>
5555
<version>${acp.version}</version>
5656
</dependency>
5757
</dependencies>

‎integration-testing/programs/spring/src/main/java/interop/spring/agent/SpringAgentApp.java‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public static void main(String[] args) {
3737
usage("--transport is required");
3838
}
3939
boolean stdio = "stdio".equals(transport);
40-
if (!stdio && !"http".equals(transport)) {
41-
usage("unsupported transport " + transport + " (the Spring agent serves stdio and http)");
40+
if (!stdio && !"http".equals(transport) && !"ws".equals(transport)) {
41+
usage("unsupported transport " + transport + " (the Spring agent serves stdio, http and ws)");
4242
}
4343
Map<String, Object> properties = new HashMap<>();
4444
properties.put("spring.main.banner-mode", "off");
@@ -51,7 +51,8 @@ public static void main(String[] args) {
5151
properties.put("spring.main.web-application-type", "servlet");
5252
properties.put("server.address", "127.0.0.1");
5353
properties.put("server.port", port);
54-
properties.put("spring.acp.agent.transport.type", "http");
54+
// http and ws are one endpoint: the servlet takes the WebSocket upgrade on its path.
55+
properties.put("spring.acp.agent.transport.type", "ws".equals(transport) ? "websocket" : "http");
5556
properties.put("spring.acp.agent.transport.http.path", "/acp");
5657
}
5758
SpringApplication application = new SpringApplication(SpringAgentApp.class);
@@ -73,7 +74,7 @@ private static String value(String[] args, int i) {
7374

7475
private static void usage(String problem) {
7576
System.err.println(problem);
76-
System.err.println("usage: agent.sh --transport stdio | --transport http --port <port>");
77+
System.err.println("usage: agent.sh --transport stdio | --transport http|ws --port <port>");
7778
System.exit(2);
7879
}
7980

‎integration-testing/smoke.json‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,14 @@
3535
"dir": "programs/spring",
3636
"agentTransports": [
3737
"stdio",
38-
"http"
38+
"http",
39+
"ws"
3940
],
4041
"clientTransports": [
4142
"http"
4243
],
4344
"readyTimeoutSec": 90,
44-
"pendingAgentTransports": [
45-
"ws"
46-
],
47-
"comment": "http is the SDK servlet mounted on server.port in a servlet web application. TODO ws: add \"ws\" to agentTransports once the servlet + Jakarta WebSocket host serves WebSocket upgrades on server.port; pendingAgentTransports only documents it and generates nothing."
45+
"comment": "http and ws are the SDK servlet (acp-http-servlet) mounted on server.port in a servlet web application: Streamable HTTP and the WebSocket upgrade on one path."
4846
},
4947
"micronaut": {
5048
"dir": "programs/micronaut",

0 commit comments

Comments
 (0)