public class WebSocketIntegrationTest {
@LocalServerPort
private int port;
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
private String url;
private WebSocketStompClient stompClient;
private WebSocketHandler webSocketHandler;
private CompletableFuture<NotificationDto> completableFuture = new CompletableFuture<>();
@Autowired
private NotificationService notificationService;
@BeforeEach
public void setUp() {
this.stompClient = new WebSocketStompClient(
new SockJsClient(
List.of(new WebSocketTransport(new StandardWebSocketClient()))
)
);
var messageConverter = new MappingJackson2MessageConverter();
messageConverter.setObjectMapper(objectMapper);
this.stompClient.setMessageConverter(messageConverter);
this.url = "ws://localhost:" + port + "/ws";
this.webSocketHandler = new WebSocketHandler(new CompletableFuture<NotificationDto>());
}
@Test
@Transactional
public void likeArticle_shouldSendNotification() throws Exception {
StompSession session = stompClient.connectAsync(url, new StompSessionHandlerAdapter() {
@Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
session.subscribe("/user/testId/topic/notification",
new StompFrameHandler() {
@Override
public Type getPayloadType(StompHeaders headers) {
logger.info("Received STOMP Headers: {}", headers);
return NotificationDto.class;
}
@Override
public void handleFrame(StompHeaders headers, Object o) {
logger.info("Received notification: {}", o);
if (o instanceof NotificationDto) {
completableFuture.complete((NotificationDto) o);
} else {
logger.error("Unexpected payload type: {}", o.getClass());
}
}
}
);
}
}
).get(5, TimeUnit.SECONDS);
//when
notificationService.sendNotification(
Notification.builder().message("test").user(user).build(), user);
TimeUnit.SECONDS.sleep(1);
//then
var notificationDto = completableFuture.get(20, TimeUnit.SECONDS);
assertThat(notificationDto).isNotNull();
}
}
this is my test code for testing websocket message send and transfer server to client but I got always TimeoutException on var notificationDto = completableFuture.get(20, TimeUnit.SECONDS);
According to chatGPT4o mini,
- check the path. so I checked the
Config.class
, andNotificationService.sendNotification()
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/queue");
config.setApplicationDestinationPrefixes("/app");
config.setUserDestinationPrefix("/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.addInterceptors(new HttpSessionHandshakeInterceptor())
.setAllowedOrigins("*")
.withSockJS();
}
@Service
@RequiredArgsConstructor
@Slf4j
public class NotificationService {
private final NotificationRepository notificationRepository;
private final SimpMessagingTemplate messagingTemplate;
@Transactional
public void createNotification(Notification notification) {
notificationRepository.save(notification);
}
public void sendNotification(Notification notification, User receiver) {
NotificationDto notificationDto = NotificationDto.from(notification);
messagingTemplate.
convertAndSendToUser(
receiver.getLoginId(),
"/topic/notification",
notificationDto
);
log.info("Notification sent to /user/{}{}", receiver.getLoginId(), "/topic/notification");
}
I subscribe the end-point thru session.subscribe("/user/testId/topic/notification", new StompFrameHandler()...
I checked so many times but I’m sure the path is great. log.info("Notification sent to /user/{}{}", receiver.getLoginId(), "/topic/notification");
prints out the same destination with session.subscribe("/user/testId/topic/notification",...
-
check port number -> no problem
-
make longer the timeout of
var notificationDto = completableFuture.get(20, TimeUnit.SECONDS);
-> no work (only longer time to wait to get failure)
I really want to know how to work it. and I guess the subscribe() method is something wrong bcs the new StompFrameHandler()
has 2 override method and I log the two but not working. that means the getPayloadType()
and handleFrame()
is not computed
everything I can do. I’m sure for 2 days