Skip to content

Commit fee3148

Browse files
committed
Add Tomcat WebSocket integration tests
1 parent e21bbdd commit fee3148

12 files changed

Lines changed: 349 additions & 76 deletions

File tree

build.gradle

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,14 @@ project("spring-messaging") {
322322
optional("org.projectreactor:reactor-core:1.0.0.M2")
323323
optional("org.projectreactor:reactor-tcp:1.0.0.M2")
324324
optional("com.lmax:disruptor:3.1.1")
325+
optional("org.eclipse.jetty.websocket:websocket-server:9.0.5.v20130815")
326+
optional("org.eclipse.jetty.websocket:websocket-client:9.0.5.v20130815")
325327
testCompile(project(":spring-test"))
326328
testCompile("com.thoughtworks.xstream:xstream:1.4.4")
327329
testCompile("commons-dbcp:commons-dbcp:1.2.2")
328330
testCompile("javax.inject:javax.inject-tck:1")
331+
testCompile("javax.servlet:javax.servlet-api:3.1.0")
332+
testCompile("log4j:log4j:1.2.17")
329333
testCompile("org.apache.activemq:activemq-broker:5.8.0")
330334
testCompile("org.apache.activemq:activemq-kahadb-store:5.8.0") {
331335
exclude group: "org.springframework", module: "spring-context"
@@ -334,16 +338,14 @@ project("spring-messaging") {
334338
testCompile("org.eclipse.jetty:jetty-webapp:9.0.5.v20130815") {
335339
exclude group: "org.eclipse.jetty.orbit", module: "javax.servlet"
336340
}
337-
optional("org.eclipse.jetty.websocket:websocket-server:9.0.5.v20130815")
338-
optional("org.eclipse.jetty.websocket:websocket-client:9.0.5.v20130815")
339-
testCompile("javax.servlet:javax.servlet-api:3.0.1")
341+
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0-SNAPSHOT")
342+
testCompile("org.apache.tomcat.embed:tomcat-embed-logging-juli:8.0-SNAPSHOT")
340343
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
341-
testCompile("log4j:log4j:1.2.17")
342344
}
343345

344346
repositories {
347+
maven { url "https://repository.apache.org/content/repositories/snapshots" } // tomcat-websocket-* snapshots
345348
maven { url 'http://repo.springsource.org/libs-milestone' } // reactor
346-
maven { url 'http://repo.springsource.org/libs-snapshot' } // reactor
347349
}
348350
}
349351

@@ -528,6 +530,7 @@ project("spring-websocket") {
528530
optional("org.eclipse.jetty.websocket:websocket-client:9.0.5.v20130815")
529531
optional("com.fasterxml.jackson.core:jackson-databind:2.2.0")
530532
optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12")
533+
testCompile("org.apache.tomcat.embed:tomcat-embed-core:8.0-SNAPSHOT")
531534
testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}")
532535
testCompile("log4j:log4j:1.2.17")
533536
}

spring-messaging/src/test/java/org/springframework/messaging/simp/AbstractWebSocketIntegrationTests.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.HashMap;
2020
import java.util.Map;
2121

22+
import org.apache.commons.logging.Log;
23+
import org.apache.commons.logging.LogFactory;
2224
import org.junit.After;
2325
import org.junit.Before;
2426
import org.junit.runners.Parameterized.Parameter;
@@ -31,7 +33,9 @@
3133
import org.springframework.web.socket.server.HandshakeHandler;
3234
import org.springframework.web.socket.server.RequestUpgradeStrategy;
3335
import org.springframework.web.socket.server.support.JettyRequestUpgradeStrategy;
36+
import org.springframework.web.socket.server.support.TomcatRequestUpgradeStrategy;
3437

38+
import reactor.util.Assert;
3539

3640

3741
/**
@@ -41,10 +45,13 @@
4145
*/
4246
public abstract class AbstractWebSocketIntegrationTests {
4347

48+
protected Log logger = LogFactory.getLog(getClass());
49+
4450
private static Map<Class<?>, Class<?>> upgradeStrategyConfigTypes = new HashMap<Class<?>, Class<?>>();
4551

4652
static {
4753
upgradeStrategyConfigTypes.put(JettyTestServer.class, JettyUpgradeStrategyConfig.class);
54+
upgradeStrategyConfigTypes.put(TomcatTestServer.class, TomcatUpgradeStrategyConfig.class);
4855
}
4956

5057
@Parameter(0)
@@ -59,15 +66,19 @@ public abstract class AbstractWebSocketIntegrationTests {
5966
@Before
6067
public void setup() throws Exception {
6168

69+
Class<?> upgradeStrategyConfigClass = upgradeStrategyConfigTypes.get(this.server.getClass());
70+
Assert.notNull(upgradeStrategyConfigClass, "No UpgradeStrategyConfig class");
71+
6272
this.wac = new AnnotationConfigWebApplicationContext();
6373
this.wac.register(getAnnotatedConfigClasses());
64-
this.wac.register(upgradeStrategyConfigTypes.get(this.server.getClass()));
74+
this.wac.register(upgradeStrategyConfigClass);
75+
this.wac.refresh();
6576

6677
if (this.webSocketClient instanceof Lifecycle) {
6778
((Lifecycle) this.webSocketClient).start();
6879
}
6980

70-
this.server.init(this.wac);
81+
this.server.deployConfig(this.wac);
7182
this.server.start();
7283
}
7384

@@ -80,9 +91,23 @@ public void teardown() throws Exception {
8091
((Lifecycle) this.webSocketClient).stop();
8192
}
8293
}
83-
finally {
94+
catch (Throwable t) {
95+
logger.error("Failed to stop WebSocket client", t);
96+
}
97+
98+
try {
99+
this.server.undeployConfig();
100+
}
101+
catch (Throwable t) {
102+
logger.error("Failed to undeploy application config", t);
103+
}
104+
105+
try {
84106
this.server.stop();
85107
}
108+
catch (Throwable t) {
109+
logger.error("Failed to stop server", t);
110+
}
86111
}
87112

88113
protected String getWsBaseUrl() {
@@ -110,4 +135,13 @@ public RequestUpgradeStrategy requestUpgradeStrategy() {
110135
}
111136
}
112137

138+
@Configuration
139+
static class TomcatUpgradeStrategyConfig extends AbstractRequestUpgradeStrategyConfig {
140+
141+
@Bean
142+
public RequestUpgradeStrategy requestUpgradeStrategy() {
143+
return new TomcatRequestUpgradeStrategy();
144+
}
145+
}
146+
113147
}

spring-messaging/src/test/java/org/springframework/messaging/simp/JettyTestServer.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ public int getPort() {
4747
}
4848

4949
@Override
50-
public void init(WebApplicationContext cxt) {
51-
ServletContextHandler handler = new ServletContextHandler();
52-
handler.addServlet(new ServletHolder(new DispatcherServlet(cxt)), "/");
53-
this.jettyServer.setHandler(handler);
50+
public void deployConfig(WebApplicationContext cxt) {
51+
ServletContextHandler contextHandler = new ServletContextHandler();
52+
ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(cxt));
53+
contextHandler.addServlet(servletHolder, "/");
54+
this.jettyServer.setHandler(contextHandler);
55+
}
56+
57+
@Override
58+
public void undeployConfig() {
59+
// Stopping jetty will undeploy the servlet
5460
}
5561

5662
@Override

spring-messaging/src/test/java/org/springframework/messaging/simp/TestServer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ public interface TestServer {
2727

2828
int getPort();
2929

30-
void init(WebApplicationContext cxt);
30+
void deployConfig(WebApplicationContext cxt);
31+
32+
void undeployConfig();
3133

3234
void start() throws Exception;
3335

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2002-2013 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.messaging.simp;
18+
19+
import java.io.File;
20+
import java.io.IOException;
21+
22+
import org.apache.catalina.Context;
23+
import org.apache.catalina.connector.Connector;
24+
import org.apache.catalina.startup.Tomcat;
25+
import org.apache.coyote.http11.Http11NioProtocol;
26+
import org.apache.tomcat.util.descriptor.web.ApplicationListener;
27+
import org.apache.tomcat.websocket.server.WsListener;
28+
import org.springframework.core.NestedRuntimeException;
29+
import org.springframework.util.SocketUtils;
30+
import org.springframework.web.context.WebApplicationContext;
31+
import org.springframework.web.servlet.DispatcherServlet;
32+
33+
34+
/**
35+
* Tomcat based {@link TestServer}.
36+
*
37+
* @author Rossen Stoyanchev
38+
*/
39+
public class TomcatTestServer implements TestServer {
40+
41+
private static final ApplicationListener WS_APPLICATION_LISTENER =
42+
new ApplicationListener(WsListener.class.getName(), false);
43+
44+
private final Tomcat tomcatServer;
45+
46+
private final int port;
47+
48+
private Context context;
49+
50+
51+
public TomcatTestServer() {
52+
53+
this.port = SocketUtils.findAvailableTcpPort();
54+
55+
Connector connector = new Connector(Http11NioProtocol.class.getName());
56+
connector.setPort(this.port);
57+
58+
File baseDir = createTempDir("tomcat");
59+
String baseDirPath = baseDir.getAbsolutePath();
60+
61+
this.tomcatServer = new Tomcat();
62+
this.tomcatServer.setBaseDir(baseDirPath);
63+
this.tomcatServer.setPort(this.port);
64+
this.tomcatServer.getService().addConnector(connector);
65+
this.tomcatServer.setConnector(connector);
66+
}
67+
68+
private File createTempDir(String prefix) {
69+
try {
70+
File tempFolder = File.createTempFile(prefix + ".", "." + getPort());
71+
tempFolder.delete();
72+
tempFolder.mkdir();
73+
tempFolder.deleteOnExit();
74+
return tempFolder;
75+
}
76+
catch (IOException ex) {
77+
throw new NestedRuntimeException("Unable to create temp directory", ex) {};
78+
}
79+
}
80+
81+
@Override
82+
public int getPort() {
83+
return this.port;
84+
}
85+
86+
@Override
87+
public void deployConfig(WebApplicationContext wac) {
88+
this.context = this.tomcatServer.addContext("", System.getProperty("java.io.tmpdir"));
89+
this.context.addApplicationListener(WS_APPLICATION_LISTENER);
90+
Tomcat.addServlet(context, "dispatcherServlet", new DispatcherServlet(wac));
91+
this.context.addServletMapping("/", "dispatcherServlet");
92+
}
93+
94+
@Override
95+
public void undeployConfig() {
96+
if (this.context != null) {
97+
this.context.removeServletMapping("/");
98+
this.tomcatServer.getHost().removeChild(this.context);
99+
}
100+
}
101+
102+
@Override
103+
public void start() throws Exception {
104+
this.tomcatServer.start();
105+
}
106+
107+
@Override
108+
public void stop() throws Exception {
109+
this.tomcatServer.stop();
110+
}
111+
112+
}

spring-messaging/src/test/java/org/springframework/messaging/simp/config/WebSocketMessageBrokerConfigurationTests.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.springframework.messaging.handler.annotation.MessageMapping;
3232
import org.springframework.messaging.simp.AbstractWebSocketIntegrationTests;
3333
import org.springframework.messaging.simp.JettyTestServer;
34+
import org.springframework.messaging.simp.TomcatTestServer;
3435
import org.springframework.messaging.simp.stomp.StompCommand;
3536
import org.springframework.messaging.simp.stomp.StompTextMessageBuilder;
3637
import org.springframework.messaging.support.channel.ExecutorSubscribableChannel;
@@ -39,6 +40,7 @@
3940
import org.springframework.web.socket.WebSocketHandler;
4041
import org.springframework.web.socket.WebSocketSession;
4142
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;
43+
import org.springframework.web.socket.client.endpoint.StandardWebSocketClient;
4244
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
4345
import org.springframework.web.socket.server.HandshakeHandler;
4446
import org.springframework.web.socket.server.config.WebSocketConfigurationSupport;
@@ -58,7 +60,9 @@ public class WebSocketMessageBrokerConfigurationTests extends AbstractWebSocketI
5860
@Parameters
5961
public static Iterable<Object[]> arguments() {
6062
return Arrays.asList(new Object[][] {
61-
{ new JettyTestServer(), new JettyWebSocketClient()} });
63+
{new JettyTestServer(), new JettyWebSocketClient()},
64+
{new TomcatTestServer(), new StandardWebSocketClient()}
65+
});
6266
};
6367

6468

@@ -82,12 +86,14 @@ public void afterConnectionEstablished(WebSocketSession session) throws Exceptio
8286

8387
TestController testController = this.wac.getBean(TestController.class);
8488

85-
this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/ws");
89+
WebSocketSession session = this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/ws");
8690
assertTrue(testController.latch.await(2, TimeUnit.SECONDS));
91+
session.close();
8792

8893
testController.latch = new CountDownLatch(1);
89-
this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/sockjs/websocket");
94+
session = this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/sockjs/websocket");
9095
assertTrue(testController.latch.await(2, TimeUnit.SECONDS));
96+
session.close();
9197
}
9298

9399

0 commit comments

Comments
 (0)