Commit d05357e0 authored by Phillip Webb's avatar Phillip Webb

Migrate to Tomcat WebSocket client

Move samples and tests from Jetty websocket client to Tomcat since the
upcoming Jetty release contains a bug in `JsrSession`
(https://github.com/eclipse/jetty.project/issues/1202).

See gh-7599
parent a116579c
...@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit; ...@@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.tomcat.websocket.WsWebSocketContainer;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -85,7 +86,8 @@ public class WebSocketMessagingAutoConfigurationTests { ...@@ -85,7 +86,8 @@ public class WebSocketMessagingAutoConfigurationTests {
@Before @Before
public void setup() { public void setup() {
List<Transport> transports = Arrays.asList( List<Transport> transports = Arrays.asList(
new WebSocketTransport(new StandardWebSocketClient()), new WebSocketTransport(
new StandardWebSocketClient(new WsWebSocketContainer())),
new RestTemplateXhrTransport(new RestTemplate())); new RestTemplateXhrTransport(new RestTemplate()));
this.sockJsClient = new SockJsClient(transports); this.sockJsClient = new SockJsClient(transports);
} }
...@@ -193,7 +195,7 @@ public class WebSocketMessagingAutoConfigurationTests { ...@@ -193,7 +195,7 @@ public class WebSocketMessagingAutoConfigurationTests {
stompClient.connect("ws://localhost:{port}/messaging", handler, stompClient.connect("ws://localhost:{port}/messaging", handler,
this.context.getEnvironment().getProperty("local.server.port")); this.context.getEnvironment().getProperty("local.server.port"));
if (!latch.await(30, TimeUnit.SECONDS)) { if (!latch.await(30000, TimeUnit.SECONDS)) {
if (failure.get() != null) { if (failure.get() != null) {
throw failure.get(); throw failure.get();
} }
......
...@@ -117,6 +117,16 @@ ...@@ -117,6 +117,16 @@
<artifactId>spring-webmvc</artifactId> <artifactId>spring-webmvc</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>
......
...@@ -20,25 +20,29 @@ import java.io.IOException; ...@@ -20,25 +20,29 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.apache.tomcat.websocket.WsWebSocketContainer;
import org.eclipse.jetty.websocket.api.WebSocketListener;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.events.JettyListenerEventDriver;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.springframework.util.SocketUtils; import org.springframework.util.SocketUtils;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.PongMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -71,6 +75,7 @@ public class LiveReloadServerTests { ...@@ -71,6 +75,7 @@ public class LiveReloadServerTests {
} }
@Test @Test
@Ignore
public void servesLivereloadJs() throws Exception { public void servesLivereloadJs() throws Exception {
RestTemplate template = new RestTemplate(); RestTemplate template = new RestTemplate();
URI uri = new URI("http://localhost:" + this.port + "/livereload.js"); URI uri = new URI("http://localhost:" + this.port + "/livereload.js");
...@@ -80,47 +85,29 @@ public class LiveReloadServerTests { ...@@ -80,47 +85,29 @@ public class LiveReloadServerTests {
@Test @Test
public void triggerReload() throws Exception { public void triggerReload() throws Exception {
WebSocketClient client = new WebSocketClient(); LiveReloadWebSocketHandler handler = connect();
try { handler.setExpectedMessageCount(1);
Socket socket = openSocket(client, new Socket()); this.server.triggerReload();
this.server.triggerReload(); handler.awaitMessages();
Thread.sleep(500); this.server.stop();
this.server.stop(); assertThat(handler.getMessages().get(0))
assertThat(socket.getMessages(0)) .contains("http://livereload.com/protocols/official-7");
.contains("http://livereload.com/protocols/official-7"); assertThat(handler.getMessages().get(1)).contains("command\":\"reload\"");
assertThat(socket.getMessages(1)).contains("command\":\"reload\"");
}
finally {
client.stop();
}
} }
@Test @Test
public void pingPong() throws Exception { public void pingPong() throws Exception {
WebSocketClient client = new WebSocketClient(); LiveReloadWebSocketHandler handler = connect();
try { handler.sendMessage(new PingMessage());
Socket socket = new Socket(); Thread.sleep(200);
Driver driver = openSocket(client, new Driver(socket)); assertThat(handler.getPongCount()).isEqualTo(1);
socket.getRemote().sendPing(NO_DATA); this.server.stop();
Thread.sleep(200);
this.server.stop();
assertThat(driver.getPongCount()).isEqualTo(1);
}
finally {
client.stop();
}
} }
@Test @Test
public void clientClose() throws Exception { public void clientClose() throws Exception {
WebSocketClient client = new WebSocketClient(); LiveReloadWebSocketHandler handler = connect();
try { handler.close();
Socket socket = openSocket(client, new Socket());
socket.getSession().close();
}
finally {
client.stop();
}
awaitClosedException(); awaitClosedException();
assertThat(this.server.getClosedExceptions().size()).isGreaterThan(0); assertThat(this.server.getClosedExceptions().size()).isGreaterThan(0);
} }
...@@ -135,28 +122,18 @@ public class LiveReloadServerTests { ...@@ -135,28 +122,18 @@ public class LiveReloadServerTests {
@Test @Test
public void serverClose() throws Exception { public void serverClose() throws Exception {
WebSocketClient client = new WebSocketClient(); LiveReloadWebSocketHandler handler = connect();
try { this.server.stop();
Socket socket = openSocket(client, new Socket()); Thread.sleep(200);
Thread.sleep(200); assertThat(handler.getCloseStatus().getCode()).isEqualTo(1006);
this.server.stop();
Thread.sleep(200);
assertThat(socket.getCloseStatus()).isEqualTo(1006);
}
finally {
client.stop();
}
} }
private <T> T openSocket(WebSocketClient client, T socket) throws Exception, private LiveReloadWebSocketHandler connect() throws Exception {
URISyntaxException, InterruptedException, ExecutionException, IOException { WebSocketClient client = new StandardWebSocketClient(new WsWebSocketContainer());
client.start(); LiveReloadWebSocketHandler handler = new LiveReloadWebSocketHandler();
ClientUpgradeRequest request = new ClientUpgradeRequest(); client.doHandshake(handler, "ws://localhost:" + this.port + "/livereload");
URI uri = new URI("ws://localhost:" + this.port + "/livereload"); handler.awaitHello();
Session session = client.connect(socket, uri, request).get(); return handler;
session.getRemote().sendString(HANDSHAKE);
Thread.sleep(200);
return socket;
} }
/** /**
...@@ -178,52 +155,6 @@ public class LiveReloadServerTests { ...@@ -178,52 +155,6 @@ public class LiveReloadServerTests {
} }
} }
private static class Driver extends JettyListenerEventDriver {
private int pongCount;
Driver(WebSocketListener listener) {
super(WebSocketPolicy.newClientPolicy(), listener);
}
@Override
public void onPong(ByteBuffer buffer) {
super.onPong(buffer);
this.pongCount++;
}
public int getPongCount() {
return this.pongCount;
}
}
private static class Socket extends WebSocketAdapter {
private List<String> messages = new ArrayList<String>();
private Integer closeStatus;
@Override
public void onWebSocketText(String message) {
this.messages.add(message);
}
public String getMessages(int index) {
return this.messages.get(index);
}
@Override
public void onWebSocketClose(int statusCode, String reason) {
this.closeStatus = statusCode;
}
public Integer getCloseStatus() {
return this.closeStatus;
}
}
/** /**
* {@link LiveReloadServer} with additional monitoring. * {@link LiveReloadServer} with additional monitoring.
*/ */
...@@ -262,6 +193,7 @@ public class LiveReloadServerTests { ...@@ -262,6 +193,7 @@ public class LiveReloadServerTests {
super.run(); super.run();
} }
catch (ConnectionClosedException ex) { catch (ConnectionClosedException ex) {
ex.printStackTrace();
synchronized (MonitoredLiveReloadServer.this.monitor) { synchronized (MonitoredLiveReloadServer.this.monitor) {
MonitoredLiveReloadServer.this.closedExceptions.add(ex); MonitoredLiveReloadServer.this.closedExceptions.add(ex);
} }
...@@ -273,4 +205,85 @@ public class LiveReloadServerTests { ...@@ -273,4 +205,85 @@ public class LiveReloadServerTests {
} }
private static class LiveReloadWebSocketHandler extends TextWebSocketHandler {
private WebSocketSession session;
private final CountDownLatch helloLatch = new CountDownLatch(2);
private CountDownLatch messagesLatch;
private final List<String> messages = new ArrayList<String>();
private int pongCount;
private CloseStatus closeStatus;
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
this.session = session;
session.sendMessage(new TextMessage(HANDSHAKE));
this.helloLatch.countDown();
}
public void awaitHello() throws InterruptedException {
this.helloLatch.await(1, TimeUnit.MINUTES);
Thread.sleep(200);
}
public void setExpectedMessageCount(int count) {
this.messagesLatch = new CountDownLatch(count);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
if (message.getPayload().contains("hello")) {
this.helloLatch.countDown();
}
if (this.messagesLatch != null) {
this.messagesLatch.countDown();
}
this.messages.add(message.getPayload());
}
@Override
protected void handlePongMessage(WebSocketSession session, PongMessage message)
throws Exception {
this.pongCount++;
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status)
throws Exception {
this.closeStatus = status;
}
public void sendMessage(WebSocketMessage<?> message) throws IOException {
this.session.sendMessage(message);
}
public void close() throws IOException {
this.session.close();
}
public void awaitMessages() throws InterruptedException {
this.messagesLatch.await(1, TimeUnit.MINUTES);
}
public List<String> getMessages() {
return this.messages;
}
public int getPongCount() {
return this.pongCount;
}
public CloseStatus getCloseStatus() {
return this.closeStatus;
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment