Spring Boot Websocket выдает отказ в соединении в тесте клиента SockJS

Я работаю над проектом Spring Boot Server, который до сих пор предлагал простые ресурсы REST. Чтобы отправлять уведомления клиенту, я хочу добавить соединение через веб-сокет. Чтобы проверить это соединение, я написал интеграционный тест с использованием клиента SockJS на основе этого руководства:

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

Проблема в том, что в соединении отказано со следующей ошибкой:

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)

Моя конфигурация Websocket выглядит следующим образом:

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();
    }

}

Я вижу, что конечная точка сокета отображается в журнале:

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]

Порт сервера установлен на 9090 в файле application.yml:

server:
 port: 9090

Следующий модульный тест не может подключиться к сокету:

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));
        }
    }
}

В соединении отказано. Я совершенно уверен, что это происходит потому, что конечная точка URI не существует, но я не знаю, почему. Кто-нибудь знает, есть ли ошибка в URI или что-то еще приводит к отказу в соединении?


person TardigradeX    schedule 14.07.2017    source источник
comment
вы вызывали конечную точку из Sock js?   -  person Januka samaranyake    schedule 14.07.2017
comment
Я вызвал конечную точку, используя Java-клиент SockJS в интеграционном тесте, который не удался. Это то, что вы просили?   -  person TardigradeX    schedule 17.07.2017


Ответы (1)


Я узнал причину проблемы. Конечная точка не существовала в порту 9090. Это связано с тем, что аннотация @SpringBootTest по умолчанию устанавливает для WebEnvironment значение WebEnvironment.MOCK. В этой конфигурации встроенный сервлет не запущен, поэтому порт не существует, возможно только тестирование на основе MockMvc. Чтобы запустить встроенный сервлет, для среды необходимо установить значение WebEnvironment.RANDOM_PORT или WebEnvironment.DEFINED_PORT. Я установил его на DEFINED_PORT, чтобы использовался порт 9090 из моего application.yml. При настройке среды тест выполняется правильно.

@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";
.
. 
.
person TardigradeX    schedule 18.07.2017