feat(user-creator-chat): WebSocket 퇴장과 heartbeat를 처리한다
This commit is contained in:
@@ -133,6 +133,86 @@ class UserCreatorChatWebSocketHandlerTest {
|
||||
assertEquals(emptyList<WebSocketSession>(), sessionRegistry.findSessions(roomId = 10L, memberId = 1L))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LEAVE_ROOM은 local session과 Redis presence를 제거한다")
|
||||
fun shouldRemoveLocalSessionAndPresenceWhenLeaveRoomReceived() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
handler.handleMessage(session, textMessage("JOIN_ROOM", "join-1", 10L, "{}"))
|
||||
Mockito.clearInvocations(session, presenceService)
|
||||
|
||||
handler.handleMessage(session, textMessage("LEAVE_ROOM", "leave-1", 10L, "{}"))
|
||||
|
||||
Mockito.verify(presenceService).markLeft(roomId = 10L, memberId = 1L, sessionId = "session-1")
|
||||
assertEquals(emptyList<WebSocketSession>(), sessionRegistry.findSessions(roomId = 10L, memberId = 1L))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LEAVE_ROOM은 joined room과 요청 roomId가 다르면 presence를 제거하지 않고 ERROR를 응답한다")
|
||||
fun shouldRejectLeaveRoomWhenRequestRoomDoesNotMatchJoinedRoom() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
handler.handleMessage(session, textMessage("JOIN_ROOM", "join-1", 10L, "{}"))
|
||||
Mockito.clearInvocations(session, presenceService)
|
||||
|
||||
handler.handleMessage(session, textMessage("LEAVE_ROOM", "leave-1", 20L, "{}"))
|
||||
|
||||
Mockito.verify(presenceService, Mockito.never()).markLeft(
|
||||
roomId = 10L,
|
||||
memberId = 1L,
|
||||
sessionId = "session-1"
|
||||
)
|
||||
assertEquals(listOf(session), sessionRegistry.findSessions(roomId = 10L, memberId = 1L))
|
||||
val response = sentJson(session)
|
||||
assertEquals("ERROR", response["type"].asText())
|
||||
assertEquals("leave-1", response["requestId"].asText())
|
||||
assertEquals(20L, response["roomId"].asLong())
|
||||
assertEquals("chat.room.join_required", response["payload"]["messageKey"].asText())
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("PING은 joined room의 presence TTL을 갱신하고 PONG을 응답한다")
|
||||
fun shouldRefreshPresenceAndSendPongWhenPingReceived() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
handler.handleMessage(session, textMessage("JOIN_ROOM", "join-1", 10L, "{}"))
|
||||
Mockito.clearInvocations(session, presenceService)
|
||||
|
||||
handler.handleMessage(session, textMessage("PING", "ping-1", 10L, "{}"))
|
||||
|
||||
Mockito.verify(presenceService).refresh(roomId = 10L, memberId = 1L, sessionId = "session-1")
|
||||
val response = sentJson(session)
|
||||
assertEquals("PONG", response["type"].asText())
|
||||
assertEquals("ping-1", response["requestId"].asText())
|
||||
assertEquals(10L, response["roomId"].asLong())
|
||||
assertTrue(response["payload"].isObject)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("잘못된 JSON 메시지는 handler 밖으로 예외를 전파하지 않고 ERROR를 응답한다")
|
||||
fun shouldSendErrorWhenMessagePayloadIsMalformedJson() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
|
||||
handler.handleMessage(session, TextMessage("{"))
|
||||
|
||||
val response = sentJson(session)
|
||||
assertEquals("ERROR", response["type"].asText())
|
||||
assertTrue(response["requestId"].isNull)
|
||||
assertEquals(0L, response["roomId"].asLong())
|
||||
assertEquals("common.error.invalid_request", response["payload"]["messageKey"].asText())
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("알 수 없는 type 메시지는 handler 밖으로 예외를 전파하지 않고 ERROR를 응답한다")
|
||||
fun shouldSendErrorWhenMessageTypeIsUnknown() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
|
||||
handler.handleMessage(session, textMessage("UNKNOWN", "unknown-1", 10L, "{}"))
|
||||
|
||||
val response = sentJson(session)
|
||||
assertEquals("ERROR", response["type"].asText())
|
||||
assertTrue(response["requestId"].isNull)
|
||||
assertEquals(0L, response["roomId"].asLong())
|
||||
assertEquals("common.error.invalid_request", response["payload"]["messageKey"].asText())
|
||||
}
|
||||
|
||||
private fun textMessage(type: String, requestId: String, roomId: Long, payload: String): TextMessage {
|
||||
return TextMessage(
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user