HandlersBeanDefinitionParserTests.java 14.4 KB
Newer Older
1
/*
2
 * Copyright 2002-2015 the original author or authors.
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * 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
 *
 *      http://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.
 */

17
package org.springframework.web.socket.config;
18

19 20
import java.io.IOException;
import java.io.InputStream;
21
import java.util.Arrays;
22 23 24 25 26
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;

27
import static org.junit.Assert.assertEquals;
28 29
import org.junit.Before;
import org.junit.Test;
30

31 32 33 34
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
35
import org.springframework.messaging.support.ChannelInterceptorAdapter;
36 37 38 39 40 41 42 43 44 45
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
R
Rossen Stoyanchev 已提交
46
import org.springframework.web.socket.handler.WebSocketHandlerDecorator;
47 48
import org.springframework.web.socket.server.HandshakeHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;
49
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;
50
import org.springframework.web.socket.server.support.OriginHandshakeInterceptor;
51 52
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
import org.springframework.web.socket.sockjs.SockJsService;
53
import org.springframework.web.socket.sockjs.frame.SockJsMessageCodec;
54
import org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler;
55
import org.springframework.web.socket.sockjs.transport.TransportHandler;
56
import org.springframework.web.socket.sockjs.transport.TransportHandlingSockJsService;
57
import org.springframework.web.socket.sockjs.transport.TransportType;
58 59 60 61 62 63 64 65 66 67
import org.springframework.web.socket.sockjs.transport.handler.DefaultSockJsService;
import org.springframework.web.socket.sockjs.transport.handler.EventSourceTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.HtmlFileTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.JsonpPollingTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.JsonpReceivingTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.WebSocketTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.XhrPollingTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.XhrReceivingTransportHandler;
import org.springframework.web.socket.sockjs.transport.handler.XhrStreamingTransportHandler;

R
Rossen Stoyanchev 已提交
68
import static org.hamcrest.Matchers.*;
69
import static org.junit.Assert.*;
70 71 72

/**
 * Test fixture for HandlersBeanDefinitionParser.
R
Rossen Stoyanchev 已提交
73
 * See test configuration files websocket-config-handlers-*.xml.
74 75
 *
 * @author Brian Clozel
R
Rossen Stoyanchev 已提交
76
 * @author Rossen Stoyanchev
77 78 79 80 81
 */
public class HandlersBeanDefinitionParserTests {

	private GenericWebApplicationContext appContext;

R
Rossen Stoyanchev 已提交
82

83 84
	@Before
	public void setup() {
R
Rossen Stoyanchev 已提交
85
		this.appContext = new GenericWebApplicationContext();
86 87
	}

R
Rossen Stoyanchev 已提交
88

89
	@Test
90 91
	public void webSocketHandlers() {
		loadBeanDefinitions("websocket-config-handlers.xml");
R
Rossen Stoyanchev 已提交
92 93

		Map<String, HandlerMapping> handlersMap = this.appContext.getBeansOfType(HandlerMapping.class);
94
		assertNotNull(handlersMap);
R
Rossen Stoyanchev 已提交
95
		assertThat(handlersMap.values(), hasSize(2));
96

R
Rossen Stoyanchev 已提交
97 98 99
		for (HandlerMapping hm : handlersMap.values()) {
			assertTrue(hm instanceof SimpleUrlHandlerMapping);
			SimpleUrlHandlerMapping shm = (SimpleUrlHandlerMapping) hm;
100

R
Rossen Stoyanchev 已提交
101 102 103
			if (shm.getUrlMap().keySet().contains("/foo")) {
				assertThat(shm.getUrlMap().keySet(), contains("/foo", "/bar"));
				WebSocketHttpRequestHandler handler = (WebSocketHttpRequestHandler) shm.getUrlMap().get("/foo");
104
				assertNotNull(handler);
R
Rossen Stoyanchev 已提交
105 106
				unwrapAndCheckDecoratedHandlerType(handler.getWebSocketHandler(), FooWebSocketHandler.class);
				HandshakeHandler handshakeHandler = handler.getHandshakeHandler();
107 108
				assertNotNull(handshakeHandler);
				assertTrue(handshakeHandler instanceof DefaultHandshakeHandler);
109 110
				assertFalse(handler.getHandshakeInterceptors().isEmpty());
				assertTrue(handler.getHandshakeInterceptors().get(0) instanceof OriginHandshakeInterceptor);
111 112
			}
			else {
R
Rossen Stoyanchev 已提交
113 114
				assertThat(shm.getUrlMap().keySet(), contains("/test"));
				WebSocketHttpRequestHandler handler = (WebSocketHttpRequestHandler) shm.getUrlMap().get("/test");
115
				assertNotNull(handler);
R
Rossen Stoyanchev 已提交
116 117
				unwrapAndCheckDecoratedHandlerType(handler.getWebSocketHandler(), TestWebSocketHandler.class);
				HandshakeHandler handshakeHandler = handler.getHandshakeHandler();
118 119
				assertNotNull(handshakeHandler);
				assertTrue(handshakeHandler instanceof DefaultHandshakeHandler);
120 121
				assertFalse(handler.getHandshakeInterceptors().isEmpty());
				assertTrue(handler.getHandshakeInterceptors().get(0) instanceof OriginHandshakeInterceptor);
122 123 124 125 126
			}
		}
	}

	@Test
127
	@SuppressWarnings("unchecked")
R
Rossen Stoyanchev 已提交
128
	public void webSocketHandlersAttributes() {
129
		loadBeanDefinitions("websocket-config-handlers-attributes.xml");
R
Rossen Stoyanchev 已提交
130 131

		HandlerMapping handlerMapping = this.appContext.getBean(HandlerMapping.class);
132 133 134 135 136 137 138 139
		assertNotNull(handlerMapping);
		assertTrue(handlerMapping instanceof SimpleUrlHandlerMapping);

		SimpleUrlHandlerMapping urlHandlerMapping = (SimpleUrlHandlerMapping) handlerMapping;
		assertEquals(2, urlHandlerMapping.getOrder());

		WebSocketHttpRequestHandler handler = (WebSocketHttpRequestHandler) urlHandlerMapping.getUrlMap().get("/foo");
		assertNotNull(handler);
R
Rossen Stoyanchev 已提交
140 141
		unwrapAndCheckDecoratedHandlerType(handler.getWebSocketHandler(), FooWebSocketHandler.class);
		HandshakeHandler handshakeHandler = handler.getHandshakeHandler();
142 143
		assertNotNull(handshakeHandler);
		assertTrue(handshakeHandler instanceof TestHandshakeHandler);
R
Rossen Stoyanchev 已提交
144
		List<HandshakeInterceptor> interceptors = handler.getHandshakeInterceptors();
145 146
		assertThat(interceptors, contains(instanceOf(FooTestInterceptor.class),
				instanceOf(BarTestInterceptor.class), instanceOf(OriginHandshakeInterceptor.class)));
147 148 149

		handler = (WebSocketHttpRequestHandler) urlHandlerMapping.getUrlMap().get("/test");
		assertNotNull(handler);
R
Rossen Stoyanchev 已提交
150 151
		unwrapAndCheckDecoratedHandlerType(handler.getWebSocketHandler(), TestWebSocketHandler.class);
		handshakeHandler = handler.getHandshakeHandler();
152 153
		assertNotNull(handshakeHandler);
		assertTrue(handshakeHandler instanceof TestHandshakeHandler);
R
Rossen Stoyanchev 已提交
154
		interceptors = handler.getHandshakeInterceptors();
155 156
		assertThat(interceptors, contains(instanceOf(FooTestInterceptor.class),
				instanceOf(BarTestInterceptor.class), instanceOf(OriginHandshakeInterceptor.class)));
157 158 159
	}

	@Test
160
	@SuppressWarnings("unchecked")
R
Rossen Stoyanchev 已提交
161
	public void sockJs() {
162
		loadBeanDefinitions("websocket-config-handlers-sockjs.xml");
R
Rossen Stoyanchev 已提交
163 164

		SimpleUrlHandlerMapping handlerMapping = this.appContext.getBean(SimpleUrlHandlerMapping.class);
165
		assertNotNull(handlerMapping);
R
Rossen Stoyanchev 已提交
166

167 168
		SockJsHttpRequestHandler testHandler = (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/test/**");
		assertNotNull(testHandler);
R
Rossen Stoyanchev 已提交
169
		unwrapAndCheckDecoratedHandlerType(testHandler.getWebSocketHandler(), TestWebSocketHandler.class);
170
		SockJsService testSockJsService = testHandler.getSockJsService();
R
Rossen Stoyanchev 已提交
171

172 173
		SockJsHttpRequestHandler fooHandler = (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/foo/**");
		assertNotNull(fooHandler);
R
Rossen Stoyanchev 已提交
174
		unwrapAndCheckDecoratedHandlerType(fooHandler.getWebSocketHandler(), FooWebSocketHandler.class);
175 176 177
		SockJsService sockJsService = fooHandler.getSockJsService();
		assertNotNull(sockJsService);

R
Rossen Stoyanchev 已提交
178
		assertSame(testSockJsService, sockJsService);
179

R
Rossen Stoyanchev 已提交
180 181 182
		assertThat(sockJsService, instanceOf(DefaultSockJsService.class));
		DefaultSockJsService defaultSockJsService = (DefaultSockJsService) sockJsService;
		assertThat(defaultSockJsService.getTaskScheduler(), instanceOf(ThreadPoolTaskScheduler.class));
183
		assertFalse(defaultSockJsService.shouldSuppressCors());
184 185 186

		Map<TransportType, TransportHandler> transportHandlers = defaultSockJsService.getTransportHandlers();
		assertThat(transportHandlers.values(),
R
Rossen Stoyanchev 已提交
187 188 189 190 191 192 193 194 195
				containsInAnyOrder(
						instanceOf(XhrPollingTransportHandler.class),
						instanceOf(XhrReceivingTransportHandler.class),
						instanceOf(JsonpPollingTransportHandler.class),
						instanceOf(JsonpReceivingTransportHandler.class),
						instanceOf(XhrStreamingTransportHandler.class),
						instanceOf(EventSourceTransportHandler.class),
						instanceOf(HtmlFileTransportHandler.class),
						instanceOf(WebSocketTransportHandler.class)));
196 197 198 199 200

		WebSocketTransportHandler handler = (WebSocketTransportHandler) transportHandlers.get(TransportType.WEBSOCKET);
		assertEquals(TestHandshakeHandler.class, handler.getHandshakeHandler().getClass());

		List<HandshakeInterceptor> interceptors = defaultSockJsService.getHandshakeInterceptors();
201
		assertThat(interceptors, contains(instanceOf(FooTestInterceptor.class), instanceOf(BarTestInterceptor.class), instanceOf(OriginHandshakeInterceptor.class)));
202 203 204
	}

	@Test
205
	@SuppressWarnings("unchecked")
R
Rossen Stoyanchev 已提交
206
	public void sockJsAttributes() {
207
		loadBeanDefinitions("websocket-config-handlers-sockjs-attributes.xml");
R
Rossen Stoyanchev 已提交
208

209 210
		SimpleUrlHandlerMapping handlerMapping = appContext.getBean(SimpleUrlHandlerMapping.class);
		assertNotNull(handlerMapping);
R
Rossen Stoyanchev 已提交
211

212 213
		SockJsHttpRequestHandler handler = (SockJsHttpRequestHandler) handlerMapping.getUrlMap().get("/test/**");
		assertNotNull(handler);
R
Rossen Stoyanchev 已提交
214 215
		unwrapAndCheckDecoratedHandlerType(handler.getWebSocketHandler(), TestWebSocketHandler.class);

216 217
		SockJsService sockJsService = handler.getSockJsService();
		assertNotNull(sockJsService);
R
Rossen Stoyanchev 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		assertThat(sockJsService, instanceOf(TransportHandlingSockJsService.class));
		TransportHandlingSockJsService transportService = (TransportHandlingSockJsService) sockJsService;
		assertThat(transportService.getTaskScheduler(), instanceOf(TestTaskScheduler.class));
		assertThat(transportService.getTransportHandlers().values(),
				containsInAnyOrder(
						instanceOf(XhrPollingTransportHandler.class),
						instanceOf(XhrStreamingTransportHandler.class)));

		assertEquals("testSockJsService", transportService.getName());
		assertFalse(transportService.isWebSocketEnabled());
		assertFalse(transportService.isSessionCookieNeeded());
		assertEquals(2048, transportService.getStreamBytesLimit());
		assertEquals(256, transportService.getDisconnectDelay());
		assertEquals(1024, transportService.getHttpMessageCacheSize());
		assertEquals(20, transportService.getHeartbeatTime());
233
		assertEquals(TestMessageCodec.class, transportService.getMessageCodec().getClass());
234 235 236 237

		List<HandshakeInterceptor> interceptors = transportService.getHandshakeInterceptors();
		assertThat(interceptors, contains(instanceOf(OriginHandshakeInterceptor.class)));
		assertEquals(Arrays.asList("http://mydomain1.com", "http://mydomain2.com"), transportService.getAllowedOrigins());
238
		assertTrue(transportService.shouldSuppressCors());
239 240 241
	}

	private void loadBeanDefinitions(String fileName) {
R
Rossen Stoyanchev 已提交
242
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.appContext);
243 244
		ClassPathResource resource = new ClassPathResource(fileName, HandlersBeanDefinitionParserTests.class);
		reader.loadBeanDefinitions(resource);
R
Rossen Stoyanchev 已提交
245
		this.appContext.refresh();
246 247
	}

R
Rossen Stoyanchev 已提交
248 249 250
	private static void unwrapAndCheckDecoratedHandlerType(WebSocketHandler handler, Class<?> handlerClass) {
		if (handler instanceof WebSocketHandlerDecorator) {
			handler = ((WebSocketHandlerDecorator) handler).getLastHandler();
251 252 253 254 255
		}
		assertTrue(handlerClass.isInstance(handler));
	}
}

R
Rossen Stoyanchev 已提交
256

257
class TestWebSocketHandler implements WebSocketHandler {
R
Rossen Stoyanchev 已提交
258

259
	@Override
R
Rossen Stoyanchev 已提交
260 261
	public void afterConnectionEstablished(WebSocketSession session) {
	}
262 263

	@Override
R
Rossen Stoyanchev 已提交
264 265
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
	}
266 267

	@Override
R
Rossen Stoyanchev 已提交
268 269
	public void handleTransportError(WebSocketSession session, Throwable exception) {
	}
270 271

	@Override
R
Rossen Stoyanchev 已提交
272 273
	public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
	}
274 275

	@Override
R
Rossen Stoyanchev 已提交
276 277 278
	public boolean supportsPartialMessages() {
		return false;
	}
279 280
}

R
Rossen Stoyanchev 已提交
281 282
class FooWebSocketHandler extends TestWebSocketHandler {
}
283 284

class TestHandshakeHandler implements HandshakeHandler {
R
Rossen Stoyanchev 已提交
285

286 287
	@Override
	public boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response,
R
Rossen Stoyanchev 已提交
288 289
			WebSocketHandler wsHandler, Map<String, Object> attributes) {

290 291 292 293
		return false;
	}
}

R
Rossen Stoyanchev 已提交
294 295
class TestChannelInterceptor extends ChannelInterceptorAdapter {
}
296

297
class FooTestInterceptor implements HandshakeInterceptor {
R
Rossen Stoyanchev 已提交
298

299 300
	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
R
Rossen Stoyanchev 已提交
301 302
			WebSocketHandler wsHandler, Map<String, Object> attributes) {

303 304 305 306 307
		return false;
	}

	@Override
	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
308
			WebSocketHandler wsHandler, Exception exception) {
309 310 311
	}
}

R
Rossen Stoyanchev 已提交
312 313
class BarTestInterceptor extends FooTestInterceptor {
}
314

315
@SuppressWarnings({ "unchecked", "rawtypes" })
316
class TestTaskScheduler implements TaskScheduler {
R
Rossen Stoyanchev 已提交
317

318
	@Override
R
Rossen Stoyanchev 已提交
319 320 321
	public ScheduledFuture schedule(Runnable task, Trigger trigger) {
		return null;
	}
322 323

	@Override
R
Rossen Stoyanchev 已提交
324 325 326
	public ScheduledFuture schedule(Runnable task, Date startTime) {
		return null;
	}
327 328

	@Override
R
Rossen Stoyanchev 已提交
329 330 331
	public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period) {
		return null;
	}
332 333

	@Override
R
Rossen Stoyanchev 已提交
334 335 336
	public ScheduledFuture scheduleAtFixedRate(Runnable task, long period) {
		return null;
	}
337 338

	@Override
R
Rossen Stoyanchev 已提交
339 340 341
	public ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay) {
		return null;
	}
342 343

	@Override
R
Rossen Stoyanchev 已提交
344 345 346 347
	public ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay) {
		return null;
	}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
}

class TestMessageCodec implements SockJsMessageCodec {

	@Override
	public String encode(String... messages) {
		return null;
	}

	@Override
	public String[] decode(String content) throws IOException {
		return new String[0];
	}

	@Override
	public String[] decodeInputStream(InputStream content) throws IOException {
		return new String[0];
	}
366
}