'StompFrameHandler.handleFrame not called in integration tests in Maven only

I'm using Springboot with Java 8 and I have some integration tests to test my websocket endpoints + callback. The integration tests work on my Windows machine through both IntelliJ and Maven build (verify phase) without any issues and on my Ubuntu IntelliJ, but fails on my Ubuntu Maven build.

My integration test looks like this:

@Test
void loggedInUserSendsMessageToNewUser_newUserAddedAndReceivesMessage() throws Exception {
    StompSession loggedInUserSession = getUserSession(LOGGED_IN_USER_EMAIL);
    StompSession interlocutor1Session = getUserSession(INTERLOCUTOR_EMAIL);
    StompSession interlocutor2Session = getUserSession(INTERLOCUTOR_2_EMAIL);

    BlockingQueue<MessageDTO> loggedInUserQueue = new ArrayBlockingQueue<>(1);
    loggedInUserSession.subscribe(USER_QUEUE_MESSAGE, createStompFrameHandler(loggedInUserQueue));
    BlockingQueue<MessageDTO> interlocutor1Queue = new ArrayBlockingQueue<>(1);
    interlocutor1Session.subscribe(USER_QUEUE_MESSAGE, createStompFrameHandler(interlocutor1Queue));
    BlockingQueue<MessageDTO> interlocutor2Queue = new ArrayBlockingQueue<>(1);
    interlocutor2Session.subscribe(USER_QUEUE_MESSAGE, createStompFrameHandler(interlocutor2Queue));

    String newMessage = "new message";
    String payload = objectMapper.writeValueAsString(new NewMessageDTO(newMessage, "verification id"));
    loggedInUserSession.send(String.format("/app/message/%s", INTERLOCUTOR_2_EMAIL), payload);

    assertThat(loggedInUserQueue.poll(POLLING_TIMEOUT_IN_SECONDS, SECONDS))
            .isNotNull(); // --> On my Ubuntu Maven build this is null
    ...
}

private StompSession getUserSession(String username) throws Exception {
    HttpHeaders headers = new HttpHeaders();
    headers.setBasicAuth(username, PASSWORD);
    WebSocketHttpHeaders webSocketHttpHeaders = new WebSocketHttpHeaders(headers);
    return webSocketStompClient
            .connect(String.format("ws://localhost:%d/socket/chat", serverPort), webSocketHttpHeaders, new StompSessionHandlerAdapter() {
            })
            .get(POLLING_TIMEOUT_IN_SECONDS, SECONDS);
}

private StompFrameHandler createStompFrameHandler(BlockingQueue<MessageDTO> userQueue) {
    return new StompFrameHandler() {
        @NotNull
        @Override
        public Type getPayloadType(@NotNull StompHeaders headers) {
            return LinkedHashMap.class;
        }

        @Override
        public void handleFrame(@NotNull StompHeaders headers, Object payload) {
            MessageDTO messageDTO = objectMapper.convertValue(payload, MessageDTO.class);
            userQueue.add(messageDTO);
        }
    };
}

Production code that sends the response:

private final SimpMessagingTemplate messagingTemplate;

private void sendMessageToWebsocket(){
    MessageDTO outgoingMessageDTO = messageMapper.mapTo(...);
    messagingTemplate.convertAndSendToUser(destination, "/queue/message", outgoingMessageDTO);
}

So I test that I can send a message to my websocket endpoints in the backend and I expect a response through websocket as well, on my user queue. Each user session has a blocking queue that stores incoming messages for me to poll and validate in my test.

This test has been running reliably every single time on Windows IntelliJ, Windows Maven and Ubuntu Intellij, and fails reliably on Ubuntu Maven. Since it's only during Maven that the tests fail, it is hard to debug as I can only get so far with printing console messages. What I can verify is that the backend does receive the websocket message, processes it without fail and reaches the code that is supposed to sent the response back. But the StompFrameHandler is never triggered. It is supposed to call the getPayloadType() method before handleFrame() but even getPayloadType() is not being called.

These are the things I've thought of and tried:

  • Java version: They are all running on Java 8, but I tried switching to Java 11 in all scenarios and they continue to work for Windows and Ubuntu IntelliJ, but fail on Ubuntu Maven
  • Maven version: I am using 3.8.1 on both Windows and Ubuntu
  • race condition: The subscription happens before I call the send, but just in case I added a sleep of 5 seconds before calling loggedInUserSession.send(), with the same result. It should typically be done in milliseconds, and I tried adding generous timers of 5 seconds and 60 seconds to POLLING_TIMEOUT_IN_SECONDS with no change in result. This is also the only test that tests the websocket endpoints. (I disabled the other ones to exclude interference between tests, just to be sure.)
  • thread count: The call is asynchronous, so this might be the source of it? I rather expect the backend endpoint not to be triggered then if this was the issue. I verified that both the backend is being called and processing and that the polling is happening, so I doubt this is it.

Maybe I am looking at it the wrong way. I tried to debug with print statements, but I get stuck between the sending of the response from the backend (which is being called) and the StompFrameHandler not picking up the response. Everything in between is handled by spring-messaging framework. I think it's likely an environment issue, but I am not seeing it.

Update: I still had my suspicions that the threadpool had something to do with it after debugging a bit more with IntelliJ (I saw that another thread is being spawned by the messagingTemplate). So I tried to run the integration test by itself: mvn -D it.test=mypackage.WebsocketIntegrationTest verify and now it works...

It appears it does have something to do with the threads running out, but I don't understand why it fails so consistently and why the other threads aren't released when they're done. If I set a blocking wait of 60 seconds that should be enough time for a thread to become available again I'd think.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source