I have absolutely simple SpringBoot project with simple configuration and simple integration test to test WebSockets.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sandbox.websocket</groupId>
<artifactId>websocket</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SpringBootApplication:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Message broker configuration
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/greeting")
.withSockJS();
}
}
Integration Test to simply connect to server, subscribe to message broker and send message.
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketIntegrationTest {
@LocalServerPort
private int localServerPort;
private BlockingQueue<String> blockingQueue;
@Before
public void setup() {
blockingQueue = new LinkedBlockingDeque<>();
}
@Test
public void shouldReceiveAMessageFromTheServer() throws Exception {
String uri = "ws://localhost:" + localServerPort + "/greeting";
WebSocketStompClient stompClient = new WebSocketStompClient(
new SockJsClient(Collections.singletonList(
new WebSocketTransport(
new StandardWebSocketClient()))));
String message = "MESSAGE TEST";
ListenableFuture<StompSession> connect = stompClient.connect(uri, new StompSessionHandlerAdapter() {});
StompSession session = connect.get(1, SECONDS);
session.subscribe("/topic", new DefaultStompFrameHandler());
session.send("/topic", message.getBytes());
Assert.assertEquals(message, blockingQueue.poll(10, SECONDS));
}
class DefaultStompFrameHandler implements StompFrameHandler {
@Override
public Type getPayloadType(StompHeaders stompHeaders) {
return byte[].class;
}
@Override
public void handleFrame(StompHeaders stompHeaders, Object o) {
System.out.println("=============================================================");
System.out.println(new String((byte[]) o));
System.out.println("=============================================================");
blockingQueue.offer(new String((byte[]) o));
}
}
}
If I run it and test it from javascript client it works like a charm. If I run the integration test it works only sometimes. The problem is that sometimes DefaultStompFrameHandler.handleFrame() method is not called, therefore nothing is saved to the queue and assert fails.
I wrote an InboundChannel interceptor to intercept frames and print commands to the console and all four commands are allways printed (CONNECT, SUBSCRIBE, SEND, DISCONNECT).
So, all commands go to the server including SEND, but sometimes (60-70%) StompFrameHandler is not being used no matter how long the queue.poll timeout is set.
Any help, please?