Add tests to spring-messaging
This commit is contained in:
@@ -54,7 +54,7 @@ public class AbstractStompEndpointRegistrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimal() {
|
||||
public void minimalRegistration() {
|
||||
|
||||
TestStompEndpointRegistration registration =
|
||||
new TestStompEndpointRegistration(new String[] {"/foo"}, this.wsHandler, this.scheduler);
|
||||
@@ -68,7 +68,7 @@ public class AbstractStompEndpointRegistrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handshakeHandler() {
|
||||
public void customHandshakeHandler() {
|
||||
|
||||
DefaultHandshakeHandler handshakeHandler = new DefaultHandshakeHandler();
|
||||
|
||||
@@ -86,7 +86,7 @@ public class AbstractStompEndpointRegistrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handshakeHandlerPassedToSockJsService() {
|
||||
public void customHandshakeHandlerPassedToSockJsService() {
|
||||
|
||||
DefaultHandshakeHandler handshakeHandler = new DefaultHandshakeHandler();
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.messaging.simp.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolHandler;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolWebSocketHandler;
|
||||
import org.springframework.messaging.simp.handler.MutableUserQueueSuffixResolver;
|
||||
import org.springframework.messaging.simp.handler.SimpleUserQueueSuffixResolver;
|
||||
import org.springframework.messaging.simp.stomp.StompProtocolHandler;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link ServletStompEndpointRegistry}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ServletStompEndpointRegistryTests {
|
||||
|
||||
private ServletStompEndpointRegistry registry;
|
||||
|
||||
private SubProtocolWebSocketHandler webSocketHandler;
|
||||
|
||||
private MutableUserQueueSuffixResolver queueSuffixResolver;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MessageChannel channel = Mockito.mock(MessageChannel.class);
|
||||
this.webSocketHandler = new SubProtocolWebSocketHandler(channel);
|
||||
this.queueSuffixResolver = new SimpleUserQueueSuffixResolver();
|
||||
TaskScheduler taskScheduler = Mockito.mock(TaskScheduler.class);
|
||||
this.registry = new ServletStompEndpointRegistry(webSocketHandler, queueSuffixResolver, taskScheduler);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void stompProtocolHandler() {
|
||||
|
||||
this.registry.addEndpoint("/stomp");
|
||||
|
||||
Map<String, SubProtocolHandler> protocolHandlers = webSocketHandler.getProtocolHandlers();
|
||||
assertEquals(3, protocolHandlers.size());
|
||||
assertNotNull(protocolHandlers.get("v10.stomp"));
|
||||
assertNotNull(protocolHandlers.get("v11.stomp"));
|
||||
assertNotNull(protocolHandlers.get("v12.stomp"));
|
||||
|
||||
StompProtocolHandler stompHandler = (StompProtocolHandler) protocolHandlers.get("v10.stomp");
|
||||
assertSame(this.queueSuffixResolver, stompHandler.getUserQueueSuffixResolver());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlerMapping() {
|
||||
|
||||
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
|
||||
assertEquals(0, hm.getUrlMap().size());
|
||||
|
||||
this.registry.addEndpoint("/stompOverWebSocket");
|
||||
this.registry.addEndpoint("/stompOverSockJS").withSockJS();
|
||||
|
||||
hm = (SimpleUrlHandlerMapping) this.registry.getHandlerMapping();
|
||||
assertEquals(2, hm.getUrlMap().size());
|
||||
assertNotNull(hm.getUrlMap().get("/stompOverWebSocket"));
|
||||
assertNotNull(hm.getUrlMap().get("/stompOverSockJS/**"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.messaging.simp.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.ReplyTo;
|
||||
import org.springframework.messaging.handler.websocket.SubProtocolWebSocketHandler;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeEvent;
|
||||
import org.springframework.messaging.simp.handler.AnnotationMethodMessageHandler;
|
||||
import org.springframework.messaging.simp.handler.MutableUserQueueSuffixResolver;
|
||||
import org.springframework.messaging.simp.handler.SimpleBrokerMessageHandler;
|
||||
import org.springframework.messaging.simp.handler.UserDestinationMessageHandler;
|
||||
import org.springframework.messaging.simp.stomp.StompBrokerRelayMessageHandler;
|
||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||
import org.springframework.messaging.simp.stomp.StompTextMessageBuilder;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.support.TestWebSocketSession;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link WebSocketMessageBrokerConfigurationSupport}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class WebSocketMessageBrokerConfigurationSupportTests {
|
||||
|
||||
private AnnotationConfigApplicationContext cxtSimpleBroker;
|
||||
|
||||
private AnnotationConfigApplicationContext cxtStompBroker;
|
||||
|
||||
|
||||
@Before
|
||||
public void setupOnce() {
|
||||
|
||||
this.cxtSimpleBroker = new AnnotationConfigApplicationContext();
|
||||
this.cxtSimpleBroker.register(TestWebSocketMessageBrokerConfiguration.class, TestSimpleMessageBrokerConfig.class);
|
||||
this.cxtSimpleBroker.refresh();
|
||||
|
||||
this.cxtStompBroker = new AnnotationConfigApplicationContext();
|
||||
this.cxtStompBroker.register(TestWebSocketMessageBrokerConfiguration.class, TestStompMessageBrokerConfig.class);
|
||||
this.cxtStompBroker.refresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlerMapping() {
|
||||
|
||||
SimpleUrlHandlerMapping hm = (SimpleUrlHandlerMapping) this.cxtSimpleBroker.getBean(HandlerMapping.class);
|
||||
assertEquals(1, hm.getOrder());
|
||||
|
||||
Map<String, Object> handlerMap = hm.getHandlerMap();
|
||||
assertEquals(1, handlerMap.size());
|
||||
assertNotNull(handlerMap.get("/simpleBroker"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannel() {
|
||||
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("webSocketRequestChannel", SubscribableChannel.class);
|
||||
|
||||
ArgumentCaptor<MessageHandler> captor = ArgumentCaptor.forClass(MessageHandler.class);
|
||||
verify(channel, times(3)).subscribe(captor.capture());
|
||||
|
||||
List<MessageHandler> values = captor.getAllValues();
|
||||
assertEquals(3, values.size());
|
||||
|
||||
assertTrue(values.contains(cxtSimpleBroker.getBean(AnnotationMethodMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtSimpleBroker.getBean(UserDestinationMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtSimpleBroker.getBean(SimpleBrokerMessageHandler.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannelWithStompBroker() {
|
||||
SubscribableChannel channel = this.cxtStompBroker.getBean("webSocketRequestChannel", SubscribableChannel.class);
|
||||
|
||||
ArgumentCaptor<MessageHandler> captor = ArgumentCaptor.forClass(MessageHandler.class);
|
||||
verify(channel, times(3)).subscribe(captor.capture());
|
||||
|
||||
List<MessageHandler> values = captor.getAllValues();
|
||||
assertEquals(3, values.size());
|
||||
assertTrue(values.contains(cxtStompBroker.getBean(AnnotationMethodMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtStompBroker.getBean(UserDestinationMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtStompBroker.getBean(StompBrokerRelayMessageHandler.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketRequestChannelSendMessage() throws Exception {
|
||||
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("webSocketRequestChannel", SubscribableChannel.class);
|
||||
SubProtocolWebSocketHandler webSocketHandler = this.cxtSimpleBroker.getBean(SubProtocolWebSocketHandler.class);
|
||||
|
||||
TextMessage textMessage = StompTextMessageBuilder.create(StompCommand.SEND).headers("destination:/foo").build();
|
||||
webSocketHandler.handleMessage(new TestWebSocketSession(), textMessage);
|
||||
|
||||
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).send(captor.capture());
|
||||
|
||||
Message message = captor.getValue();
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/foo", headers.getDestination());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannel() {
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", SubscribableChannel.class);
|
||||
verify(channel).subscribe(any(SubProtocolWebSocketHandler.class));
|
||||
verifyNoMoreInteractions(channel);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannelUsedByAnnotatedMethod() {
|
||||
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", SubscribableChannel.class);
|
||||
AnnotationMethodMessageHandler messageHandler = this.cxtSimpleBroker.getBean(AnnotationMethodMessageHandler.class);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
|
||||
headers.setSessionId("sess1");
|
||||
headers.setSubscriptionId("subs1");
|
||||
headers.setDestination("/foo");
|
||||
Message<?> message = MessageBuilder.withPayloadAndHeaders(new byte[0], headers).build();
|
||||
|
||||
when(channel.send(any(Message.class))).thenReturn(true);
|
||||
messageHandler.handleMessage(message);
|
||||
|
||||
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).send(captor.capture());
|
||||
message = captor.getValue();
|
||||
headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/foo", headers.getDestination());
|
||||
assertEquals("\"bar\"", new String((byte[]) message.getPayload()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void webSocketResponseChannelUsedBySimpleBroker() {
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("webSocketResponseChannel", SubscribableChannel.class);
|
||||
SimpleBrokerMessageHandler broker = this.cxtSimpleBroker.getBean(SimpleBrokerMessageHandler.class);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE);
|
||||
headers.setSessionId("sess1");
|
||||
headers.setSubscriptionId("subs1");
|
||||
headers.setDestination("/foo");
|
||||
Message<?> message = MessageBuilder.withPayloadAndHeaders(new byte[0], headers).build();
|
||||
|
||||
// subscribe
|
||||
broker.handleMessage(message);
|
||||
|
||||
headers = StompHeaderAccessor.create(StompCommand.SEND);
|
||||
headers.setSessionId("sess1");
|
||||
headers.setDestination("/foo");
|
||||
message = MessageBuilder.withPayloadAndHeaders("bar".getBytes(), headers).build();
|
||||
|
||||
// message
|
||||
when(channel.send(any(Message.class))).thenReturn(true);
|
||||
broker.handleMessage(message);
|
||||
|
||||
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).send(captor.capture());
|
||||
message = captor.getValue();
|
||||
headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/foo", headers.getDestination());
|
||||
assertEquals("bar", new String((byte[]) message.getPayload()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brokerChannel() {
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("brokerChannel", SubscribableChannel.class);
|
||||
|
||||
ArgumentCaptor<MessageHandler> captor = ArgumentCaptor.forClass(MessageHandler.class);
|
||||
verify(channel, times(2)).subscribe(captor.capture());
|
||||
|
||||
List<MessageHandler> values = captor.getAllValues();
|
||||
assertEquals(2, values.size());
|
||||
assertTrue(values.contains(cxtSimpleBroker.getBean(UserDestinationMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtSimpleBroker.getBean(SimpleBrokerMessageHandler.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brokerChannelWithStompBroker() {
|
||||
SubscribableChannel channel = this.cxtStompBroker.getBean("brokerChannel", SubscribableChannel.class);
|
||||
|
||||
ArgumentCaptor<MessageHandler> captor = ArgumentCaptor.forClass(MessageHandler.class);
|
||||
verify(channel, times(2)).subscribe(captor.capture());
|
||||
|
||||
List<MessageHandler> values = captor.getAllValues();
|
||||
assertEquals(2, values.size());
|
||||
assertTrue(values.contains(cxtStompBroker.getBean(UserDestinationMessageHandler.class)));
|
||||
assertTrue(values.contains(cxtStompBroker.getBean(StompBrokerRelayMessageHandler.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brokerChannelUsedByAnnotatedMethod() {
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("brokerChannel", SubscribableChannel.class);
|
||||
AnnotationMethodMessageHandler messageHandler = this.cxtSimpleBroker.getBean(AnnotationMethodMessageHandler.class);
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SEND);
|
||||
headers.setDestination("/foo");
|
||||
Message<?> message = MessageBuilder.withPayloadAndHeaders(new byte[0], headers).build();
|
||||
|
||||
when(channel.send(any(Message.class))).thenReturn(true);
|
||||
messageHandler.handleMessage(message);
|
||||
|
||||
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).send(captor.capture());
|
||||
message = captor.getValue();
|
||||
headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/bar", headers.getDestination());
|
||||
assertEquals("\"bar\"", new String((byte[]) message.getPayload()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brokerChannelUsedByUserDestinationMessageHandler() {
|
||||
SubscribableChannel channel = this.cxtSimpleBroker.getBean("brokerChannel", SubscribableChannel.class);
|
||||
UserDestinationMessageHandler messageHandler = this.cxtSimpleBroker.getBean(UserDestinationMessageHandler.class);
|
||||
|
||||
this.cxtSimpleBroker.getBean(MutableUserQueueSuffixResolver.class).addQueueSuffix("joe", "s1", "s1");
|
||||
|
||||
StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SEND);
|
||||
headers.setDestination("/user/joe/foo");
|
||||
Message<?> message = MessageBuilder.withPayloadAndHeaders(new byte[0], headers).build();
|
||||
|
||||
when(channel.send(any(Message.class))).thenReturn(true);
|
||||
messageHandler.handleMessage(message);
|
||||
|
||||
ArgumentCaptor<Message> captor = ArgumentCaptor.forClass(Message.class);
|
||||
verify(channel).send(captor.capture());
|
||||
message = captor.getValue();
|
||||
headers = StompHeaderAccessor.wrap(message);
|
||||
|
||||
assertEquals(SimpMessageType.MESSAGE, headers.getMessageType());
|
||||
assertEquals("/foos1", headers.getDestination());
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
static class TestController {
|
||||
|
||||
@SubscribeEvent("/foo")
|
||||
public String handleSubscribe() {
|
||||
return "bar";
|
||||
}
|
||||
|
||||
@MessageMapping("/foo")
|
||||
@ReplyTo("/bar")
|
||||
public String handleMessage() {
|
||||
return "bar";
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestSimpleMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/simpleBroker");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
// SimpleBroker used by default
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestController subscriptionController() {
|
||||
return new TestController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestStompMessageBrokerConfig implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/stompBrokerRelay");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
configurer.enableStompBrokerRelay("/topic", "/queue").setAutoStartup(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestWebSocketMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public SubscribableChannel webSocketRequestChannel() {
|
||||
return Mockito.mock(SubscribableChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public SubscribableChannel webSocketResponseChannel() {
|
||||
return Mockito.mock(SubscribableChannel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubscribableChannel brokerChannel() {
|
||||
return Mockito.mock(SubscribableChannel.class);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,9 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.messaging.simp.config;
|
||||
package org.springframework.messaging.simp.handler;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -26,36 +32,37 @@ import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.simp.config.DelegatingWebSocketMessageBrokerConfiguration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerConfigurer;
|
||||
import org.springframework.messaging.simp.config.StompEndpointRegistry;
|
||||
import org.springframework.messaging.simp.config.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.messaging.simp.stomp.StompCommand;
|
||||
import org.springframework.messaging.simp.stomp.StompTextMessageBuilder;
|
||||
import org.springframework.messaging.support.channel.ExecutorSubscribableChannel;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.socket.AbstractWebSocketIntegrationTests;
|
||||
import org.springframework.web.socket.JettyWebSocketTestServer;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.TomcatWebSocketTestServer;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.adapter.TextWebSocketHandlerAdapter;
|
||||
import org.springframework.web.socket.client.endpoint.StandardWebSocketClient;
|
||||
import org.springframework.web.socket.client.jetty.JettyWebSocketClient;
|
||||
import org.springframework.web.socket.server.HandshakeHandler;
|
||||
import org.springframework.web.socket.server.config.WebSocketConfigurationSupport;
|
||||
import org.springframework.web.socket.sockjs.transport.handler.WebSocketTransportHandler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.messaging.simp.stomp.StompTextMessageBuilder.*;
|
||||
|
||||
|
||||
/**
|
||||
* Test fixture for {@link WebSocketConfigurationSupport}.
|
||||
*
|
||||
* Integration tests with annotated message-handling methods.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class WebSocketMessageBrokerConfigurationTests extends AbstractWebSocketIntegrationTests {
|
||||
public class AnnotationMethodIntegrationTests extends AbstractWebSocketIntegrationTests {
|
||||
|
||||
@Parameters
|
||||
public static Iterable<Object[]> arguments() {
|
||||
@@ -68,37 +75,85 @@ public class WebSocketMessageBrokerConfigurationTests extends AbstractWebSocketI
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedConfigClasses() {
|
||||
return new Class<?>[] { TestWebSocketMessageBrokerConfiguration.class, SimpleBrokerConfigurer.class };
|
||||
return new Class<?>[] { TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class };
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sendMessage() throws Exception {
|
||||
public void simpleController() throws Exception {
|
||||
|
||||
final TextMessage textMessage = StompTextMessageBuilder.create(StompCommand.SEND)
|
||||
.headers("destination:/app/foo").build();
|
||||
TextMessage message = create(StompCommand.SEND).headers("destination:/app/simple").build();
|
||||
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(message, 0), "/ws");
|
||||
|
||||
WebSocketHandler clientHandler = new TextWebSocketHandlerAdapter() {
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
session.sendMessage(textMessage);
|
||||
}
|
||||
};
|
||||
SimpleController controller = this.wac.getBean(SimpleController.class);
|
||||
assertTrue(controller.latch.await(2, TimeUnit.SECONDS));
|
||||
|
||||
TestController testController = this.wac.getBean(TestController.class);
|
||||
|
||||
WebSocketSession session = this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/ws");
|
||||
assertTrue(testController.latch.await(2, TimeUnit.SECONDS));
|
||||
session.close();
|
||||
|
||||
testController.latch = new CountDownLatch(1);
|
||||
session = this.webSocketClient.doHandshake(clientHandler, getWsBaseUrl() + "/sockjs/websocket");
|
||||
assertTrue(testController.latch.await(2, TimeUnit.SECONDS));
|
||||
session.close();
|
||||
}
|
||||
|
||||
|
||||
@IntegrationTestController
|
||||
static class SimpleController {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@MessageMapping(value="/app/simple")
|
||||
public void handle() {
|
||||
this.latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestClientWebSocketHandler extends TextWebSocketHandlerAdapter {
|
||||
|
||||
private final TextMessage messageToSend;
|
||||
|
||||
private final int expected;
|
||||
|
||||
private final List<TextMessage> actual = new CopyOnWriteArrayList<TextMessage>();
|
||||
|
||||
private final CountDownLatch latch;
|
||||
|
||||
|
||||
public TestClientWebSocketHandler(TextMessage messageToSend, int expectedNumberOfMessages) {
|
||||
this.messageToSend = messageToSend;
|
||||
this.expected = expectedNumberOfMessages;
|
||||
this.latch = new CountDownLatch(this.expected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
session.sendMessage(this.messageToSend);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
this.actual.add(message);
|
||||
this.latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestWebSocketMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
|
||||
@ComponentScan(basePackageClasses=AnnotationMethodIntegrationTests.class,
|
||||
includeFilters=@ComponentScan.Filter(IntegrationTestController.class))
|
||||
static class TestMessageBrokerConfigurer implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Autowired
|
||||
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/ws").setHandshakeHandler(this.handshakeHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
configurer.setAnnotationMethodDestinationPrefixes("/app/");
|
||||
configurer.enableSimpleBroker("/topic", "/queue");
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
@@ -108,49 +163,15 @@ public class WebSocketMessageBrokerConfigurationTests extends AbstractWebSocketI
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public SubscribableChannel webSocketReplyChannel() {
|
||||
public SubscribableChannel webSocketResponseChannel() {
|
||||
return new ExecutorSubscribableChannel(); // synchronous
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestController testController() {
|
||||
return new TestController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SimpleBrokerConfigurer implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Autowired
|
||||
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
|
||||
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
|
||||
registry.addEndpoint("/ws")
|
||||
.setHandshakeHandler(this.handshakeHandler);
|
||||
|
||||
registry.addEndpoint("/sockjs").withSockJS()
|
||||
.setTransportHandlerOverrides(new WebSocketTransportHandler(this.handshakeHandler));;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerConfigurer configurer) {
|
||||
configurer.setAnnotationMethodDestinationPrefixes("/app/");
|
||||
configurer.enableSimpleBroker("/topic");
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Controller
|
||||
private static class TestController {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
@MessageMapping(value="/app/foo")
|
||||
public void handleFoo() {
|
||||
this.latch.countDown();
|
||||
}
|
||||
private @interface IntegrationTestController {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user