From a54be44ecc34c0e8d5ffef13ce60c992d111cfae Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 13 Sep 2022 15:30:14 +0100 Subject: [PATCH] Add websocket-jetty smoke test Closes gh-72 --- ci/smoke-tests.yml | 1 + settings.gradle | 1 + websocket-jetty/README.adoc | 1 + websocket-jetty/build.gradle | 26 +++++++++ .../WebSocketJettyApplicationAotTests.java | 56 +++++++++++++++++++ .../java/com/example/websocket/jetty/CLR.java | 48 ++++++++++++++++ .../websocket/jetty/EchoWebSocketHandler.java | 33 +++++++++++ .../websocket/jetty/WebSocketConfig.java | 31 ++++++++++ .../jetty/WebSocketJettyApplication.java | 16 ++++++ .../jetty/WebSocketJettyApplicationTests.java | 14 +++++ websocket/README.adoc | 2 +- 11 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 websocket-jetty/README.adoc create mode 100644 websocket-jetty/build.gradle create mode 100644 websocket-jetty/src/aotSmokeTest/java/com/example/websocket/jetty/WebSocketJettyApplicationAotTests.java create mode 100644 websocket-jetty/src/main/java/com/example/websocket/jetty/CLR.java create mode 100644 websocket-jetty/src/main/java/com/example/websocket/jetty/EchoWebSocketHandler.java create mode 100644 websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketConfig.java create mode 100644 websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketJettyApplication.java create mode 100644 websocket-jetty/src/test/java/com/example/websocket/jetty/WebSocketJettyApplicationTests.java diff --git a/ci/smoke-tests.yml b/ci/smoke-tests.yml index c6277f66..9d5c36f4 100644 --- a/ci/smoke-tests.yml +++ b/ci/smoke-tests.yml @@ -80,6 +80,7 @@ groups: - webmvc-tomcat - webmvc-tomcat-tls - websocket + - websocket-jetty - websocket-stomp - name: integration smoke_tests: diff --git a/settings.gradle b/settings.gradle index 856d6043..4d5f0ba2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -113,5 +113,6 @@ include "webflux-netty-tls" include "webmvc-tomcat" include "webmvc-tomcat-tls" include "websocket" +include "websocket-jetty" include "websocket-stomp" diff --git a/websocket-jetty/README.adoc b/websocket-jetty/README.adoc new file mode 100644 index 00000000..0b3a79d3 --- /dev/null +++ b/websocket-jetty/README.adoc @@ -0,0 +1 @@ +Tests websocket support with Jetty. diff --git a/websocket-jetty/build.gradle b/websocket-jetty/build.gradle new file mode 100644 index 00000000..646efb8a --- /dev/null +++ b/websocket-jetty/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.aot.smoke-test' + id 'org.graalvm.buildtools.native' +} + +dependencies { + implementation(enforcedPlatform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation(project(":aot-smoke-test-third-party-hints")) + implementation("org.springframework.boot:spring-boot-starter-websocket") + implementation("org.springframework.boot:spring-boot-starter-jetty") + modules { + module("org.springframework.boot:spring-boot-starter-tomcat") { + replacedBy("org.springframework.boot:spring-boot-starter-jetty", "Use Jetty instead of Tomcat") + } + } + testImplementation("org.springframework.boot:spring-boot-starter-test") + + aotSmokeTestImplementation(project(":aot-smoke-test-support")) + aotSmokeTestImplementation("org.awaitility:awaitility:4.2.0") +} + +aotSmokeTest { + webApplication = true +} diff --git a/websocket-jetty/src/aotSmokeTest/java/com/example/websocket/jetty/WebSocketJettyApplicationAotTests.java b/websocket-jetty/src/aotSmokeTest/java/com/example/websocket/jetty/WebSocketJettyApplicationAotTests.java new file mode 100644 index 00000000..20b1a37c --- /dev/null +++ b/websocket-jetty/src/aotSmokeTest/java/com/example/websocket/jetty/WebSocketJettyApplicationAotTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.websocket.jetty; + +import java.time.Duration; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; + +import org.springframework.aot.smoketest.support.assertj.AssertableOutput; +import org.springframework.aot.smoketest.support.junit.AotSmokeTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@AotSmokeTest +class WebSocketJettyApplicationAotTests { + + @Test + void clientShouldSendMessage(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(output).hasSingleLineContaining("Client: Sent 'Hello Websocket'")); + } + + @Test + void serverShouldReceiveMessage(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(output).hasSingleLineContaining("Server: Received 'Hello Websocket'")); + } + + @Test + void serverShouldReply(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(output).hasSingleLineContaining("Server: Sent 'Hello Websocket'")); + } + + @Test + void clientShouldReceiveReply(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)) + .untilAsserted(() -> assertThat(output).hasSingleLineContaining("Client: Received 'Hello Websocket'")); + } + +} diff --git a/websocket-jetty/src/main/java/com/example/websocket/jetty/CLR.java b/websocket-jetty/src/main/java/com/example/websocket/jetty/CLR.java new file mode 100644 index 00000000..384d4388 --- /dev/null +++ b/websocket-jetty/src/main/java/com/example/websocket/jetty/CLR.java @@ -0,0 +1,48 @@ +package com.example.websocket.jetty; + +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.client.WebSocketClient; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +@Component +class CLR implements CommandLineRunner { + + private final WebSocketClient webSocketClient; + + private final ServletWebServerApplicationContext servletWebServerApplicationContext; + + CLR(WebSocketClient webSocketClient, ServletWebServerApplicationContext servletWebServerApplicationContext) { + this.webSocketClient = webSocketClient; + this.servletWebServerApplicationContext = servletWebServerApplicationContext; + } + + @Override + public void run(String... args) throws Exception { + WebSocketSession session = this.webSocketClient.doHandshake(new MyWebsocketHandler(), null, + URI.create("ws://localhost:%d/echo".formatted(getServerPort()))).get(5, TimeUnit.SECONDS); + TextMessage message = new TextMessage("Hello Websocket"); + session.sendMessage(message); + System.out.printf("Client: Sent '%s'%n", message.getPayload()); + } + + private int getServerPort() { + return this.servletWebServerApplicationContext.getWebServer().getPort(); + } + + private static class MyWebsocketHandler extends TextWebSocketHandler { + + @Override + protected void handleTextMessage(WebSocketSession session, TextMessage message) { + System.out.printf("Client: Received '%s'%n", message.getPayload()); + } + + } + +} diff --git a/websocket-jetty/src/main/java/com/example/websocket/jetty/EchoWebSocketHandler.java b/websocket-jetty/src/main/java/com/example/websocket/jetty/EchoWebSocketHandler.java new file mode 100644 index 00000000..64f634c3 --- /dev/null +++ b/websocket-jetty/src/main/java/com/example/websocket/jetty/EchoWebSocketHandler.java @@ -0,0 +1,33 @@ +package com.example.websocket.jetty; + +import org.springframework.stereotype.Component; +import org.springframework.web.socket.CloseStatus; +import org.springframework.web.socket.TextMessage; +import org.springframework.web.socket.WebSocketSession; +import org.springframework.web.socket.handler.TextWebSocketHandler; + +@Component +public class EchoWebSocketHandler extends TextWebSocketHandler { + + public EchoWebSocketHandler() { + } + + @Override + public void afterConnectionEstablished(WebSocketSession session) { + System.out.printf("Opened new session in instance %s%n", this); + } + + @Override + public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { + System.out.printf("Server: Received '%s' in %s%n", message.getPayload(), this); + session.sendMessage(message); + System.out.printf("Server: Sent '%s' in %s%n", message.getPayload(), this); + } + + @Override + public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { + System.out.printf("Closing connection in %s%n", this, exception); + session.close(CloseStatus.SERVER_ERROR); + } + +} diff --git a/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketConfig.java b/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketConfig.java new file mode 100644 index 00000000..da214e0b --- /dev/null +++ b/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketConfig.java @@ -0,0 +1,31 @@ +package com.example.websocket.jetty; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.client.WebSocketClient; +import org.springframework.web.socket.client.standard.StandardWebSocketClient; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +import org.springframework.web.socket.config.annotation.WebSocketConfigurer; +import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; + +@Configuration +@EnableWebSocket +public class WebSocketConfig implements WebSocketConfigurer { + + private final EchoWebSocketHandler echoWebSocketHandler; + + public WebSocketConfig(EchoWebSocketHandler echoWebSocketHandler) { + this.echoWebSocketHandler = echoWebSocketHandler; + } + + @Override + public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + registry.addHandler(this.echoWebSocketHandler, "/echo"); + } + + @Bean + public WebSocketClient webSocketClient() { + return new StandardWebSocketClient(); + } + +} diff --git a/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketJettyApplication.java b/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketJettyApplication.java new file mode 100644 index 00000000..1a3c5222 --- /dev/null +++ b/websocket-jetty/src/main/java/com/example/websocket/jetty/WebSocketJettyApplication.java @@ -0,0 +1,16 @@ +package com.example.websocket.jetty; + +import org.springframework.aot.smoketest.thirdpartyhints.JettyRuntimeHints; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ImportRuntimeHints; + +@SpringBootApplication +@ImportRuntimeHints(JettyRuntimeHints.class) +public class WebSocketJettyApplication { + + public static void main(String[] args) { + SpringApplication.run(WebSocketJettyApplication.class, args); + } + +} diff --git a/websocket-jetty/src/test/java/com/example/websocket/jetty/WebSocketJettyApplicationTests.java b/websocket-jetty/src/test/java/com/example/websocket/jetty/WebSocketJettyApplicationTests.java new file mode 100644 index 00000000..182fe1f4 --- /dev/null +++ b/websocket-jetty/src/test/java/com/example/websocket/jetty/WebSocketJettyApplicationTests.java @@ -0,0 +1,14 @@ +package com.example.websocket.jetty; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class WebSocketJettyApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/websocket/README.adoc b/websocket/README.adoc index 63540356..6a5aff6b 100644 --- a/websocket/README.adoc +++ b/websocket/README.adoc @@ -1 +1 @@ -Tests websocket support. +Tests websocket support with Tomcat.