1

Title: Spring Boot WebSocket Test: HTTP 400 Error on WebSocket Upgrade Request

Question:

I'm trying to test a WebSocket endpoint in a Spring Boot application, but I keep getting an HTTP 400 error when attempting to upgrade the HTTP request to WebSocket. The WebSocket connection works when I run the application normally, so I'm not sure what’s causing the issue in the test environment.

WebSocket Controller Here’s my WebSocket controller, which retrieves a list of public game lobbies and sends it to subscribers:

package es.us.dp1.l3_04_24_25.pandemic.model.game;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import java.util.List;

@Controller
public class WebSocketGameController {
    private final GameService gameService;
    private final SimpMessagingTemplate messagingTemplate;

    @Autowired
    public WebSocketGameController(GameService gameService, SimpMessagingTemplate messagingTemplate) {
        this.gameService = gameService;
        this.messagingTemplate = messagingTemplate;
    }

    @MessageMapping("/lobbies")
    @SendTo("/topic/lobbies")
    public List<Game> findPublicLobbies() {
        return gameService.findPublicLobbies();
    }

    @MessageMapping("/lobbies/find")
    public void findLobby(@Payload Integer gameId) {
        Game lobby = gameService.findPublicLobbyById(gameId);
        messagingTemplate.convertAndSend("/topic/lobby/" + gameId, lobby);
    }
}

Test Class Here’s the test class I’m using to verify the WebSocket connection and message handling:

package es.us.dp1.l3_04_24_25.pandemic.game;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

import java.util.List;
import java.util.concurrent.TimeUnit;

import es.us.dp1.l3_04_24_25.pandemic.model.game.Game;
import es.us.dp1.l3_04_24_25.pandemic.model.game.GameService;
import es.us.dp1.l3_04_24_25.pandemic.model.game.WebSocketGameController;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebSocketGameControllerTest {

    @MockBean
    private GameService gameService;

    @MockBean
    private SimpMessagingTemplate messagingTemplate;

    private WebSocketStompClient stompClient;
    private StompSession stompSession;

    @LocalServerPort
    private int port;

    @BeforeEach
    void setUp() throws Exception {
        stompClient = new WebSocketStompClient(new StandardWebSocketClient());
        stompSession = stompClient.connect("ws://localhost:" + port + "/ws", new StompSessionHandlerAdapter() {}).get(5, TimeUnit.SECONDS);
    }

    @Test
    void shouldFindPublicLobbies() throws Exception {
        Game game = new Game();
        game.setId(1);
        game.setName("Test Game");
        List<Game> games = List.of(game);
        when(gameService.findPublicLobbies()).thenReturn(games);

        stompSession.subscribe("/topic/lobbies", new StompSessionHandlerAdapter() {});
        stompSession.send("/app/lobbies", null);

        ArgumentCaptor<List<Game>> captor = ArgumentCaptor.forClass(List.class);
        verify(messagingTemplate, times(1)).convertAndSend(eq("/topic/lobbies"), captor.capture());

        List<Game> capturedGames = captor.getValue();
        assertEquals(1, capturedGames.size());
        assertEquals("Test Game", capturedGames.get(0).getName());
    }
}

Error When I run the test, it throws this exception:

`java.util.concurrent.ExecutionException: jakarta.websocket.DeploymentException: The HTTP response from the server [400] did not permit the HTTP upgrade to WebSocket

at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2096)
at org.springframework.util.concurrent.CompletableToListenableFutureAdapter.get(CompletableToListenableFutureAdapter.java:106)
at es.us.dp1.l3_04_24_25.pandemic.game.WebSocketGameControllerTest.setUp(WebSocketGameControllerTest.java:50)

Caused by: jakarta.websocket.DeploymentException: The HTTP response from the server [400] did not permit the HTTP upgrade to WebSocket at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServerRecursive(WsWebSocketContainer.java:384) at org.apache.tomcat.websocket.WsWebSocketContainer.connectToServer(WsWebSocketContainer.java:179) ... 

Additional Details The WebSocket configuration should be set to accept all origins. The backend runs on port 8080. I've confirmed the WebSocket works when accessing it through the front end, so it appears to be a test setup issue. Question Why is this error happening, and how can I correctly set up the test to establish a WebSocket connection?

I’ve tried increasing the timeout and verifying the "/app" and "/topic" prefixes, but since this is my first time with WebSockets in tests, I’m not sure what else to try. Any guidance or suggestions would be much appreciated. Thanks!

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.