Search code examples
spring-bootwebsocketsockjsconnection-refused

Spring Boot Websocket Throws "Connection Refused" in SockJS Client Test


I am working on a Spring Boot Server Project which offered simple REST resources until now. In order to push notifications to the client I want to add a websocket connection. To test this connection I have written a Integration Test using a SockJS Client based on this tutorial :

http://rafaelhz.github.io/testing-websockets/

Problem is that the Connection is refused with the following error:

org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:9090/websocket/info": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)

My Websocket Configuration is as follows:

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry
                .addEndpoint("/websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    }

}

I can see in the that the socket endpoint is mapped int the log:

2017-07-14 15:22:59.561  INFO 13765 --- [           main] o.s.w.s.s.s.WebSocketHandlerMapping      : Mapped URL path [/websocket/**] onto handler of type [class org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler]

The Server Port is set to 9090 in the application.yml file:

server:
 port: 9090

The following unit test is not able to connect to the socket:

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;

import java.lang.reflect.Type;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;

import static java.util.Arrays.asList;
import static java.util.concurrent.TimeUnit.SECONDS;

@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("test")
//@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebSocketConnectionTest {

    static final String WEBSOCKET_URI = "ws://localhost:9090/websocket";
    static final String WEBSOCKET_TOPIC = "/topic";

    BlockingQueue<String> blockingQueue;
    WebSocketStompClient stompClient;

    @Before
    public void setup() {
        blockingQueue = new LinkedBlockingDeque<>();
        stompClient = new WebSocketStompClient(new SockJsClient(
                asList(new WebSocketTransport(new StandardWebSocketClient()))));

        System.out.println(WEBSOCKET_URI);
    }

    @Test
    public void shouldReceiveAMessageFromTheServer() throws Exception {
        StompSession session = stompClient
                .connect(WEBSOCKET_URI, new StompSessionHandlerAdapter() {})
                .get(1, SECONDS);
        session.subscribe(WEBSOCKET_TOPIC, new DefaultStompFrameHandler());

        String message = "MESSAGE TEST";
        session.send(WEBSOCKET_TOPIC, message.getBytes());

        Assert.assertEquals(message, blockingQueue.poll(1, SECONDS));
    }

    class DefaultStompFrameHandler implements StompFrameHandler {
        @Override
        public Type getPayloadType(StompHeaders stompHeaders) {
            return byte[].class;
        }

        @Override
        public void handleFrame(StompHeaders stompHeaders, Object o) {
            blockingQueue.offer(new String((byte[]) o));
        }
    }
}

The connection is refused. Im fairly certain that this happens because the URI endpoint does not exist, but I don't know why. Does somebody know if there is a error in the URI or if something else leads to the refused connection ?


Solution

  • I found out the cause of the problem. The endpoint did not exist on PORT 9090. That is because the @SpringBootTest Annotation sets the WebEnvironment to WebEnvironment.MOCK by default. In this configuration No Embedded Servlet is started and therefor and no port exists, only MockMvc-based testing is possible. In order to start an Embedded servlet the Environment has to be set to WebEnvironment.RANDOM_PORT or WebEnvironment.DEFINED_PORT. I set it to DEFINED_PORT so that the port 9090 from my application.yml is used. By Setting the Environment the test runs correctly.

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)//!!!!!
    @ActiveProfiles("test")
    @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
    public class WebSocketConnectionTest {
    
    String WEBSOCKET_URI = "ws://localhost:9090/websocket";
    String WEBSOCKET_TOPIC = "/topic";
    .
    . 
    .