test(user-creator-chat): WebSocket handshake slice 검증을 추가한다

This commit is contained in:
2026-06-19 01:56:28 +09:00
parent 54c9a7d5a5
commit 9e58131167

View File

@@ -0,0 +1,132 @@
package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
import com.fasterxml.jackson.databind.ObjectMapper
import kr.co.vividnext.sodalive.jwt.TokenProvider
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberAdapter
import kr.co.vividnext.sodalive.v2.usercreatorchat.service.UserCreatorChatService
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertSame
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.context.ApplicationContext
import org.springframework.http.HttpHeaders
import org.springframework.http.server.ServerHttpResponse
import org.springframework.http.server.ServletServerHttpRequest
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
import org.springframework.web.socket.WebSocketHandler
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler
@SpringBootTest(
classes = [
UserCreatorChatWebSocketConfig::class,
UserCreatorChatWebSocketHandler::class,
UserCreatorChatWebSocketAuthInterceptor::class
]
)
class UserCreatorChatWebSocketHandshakeIntegrationTest @Autowired constructor(
private val applicationContext: ApplicationContext
) {
@MockBean
private lateinit var tokenProvider: TokenProvider
@MockBean
private lateinit var service: UserCreatorChatService
@MockBean
private lateinit var presenceService: UserCreatorChatPresenceService
@MockBean
private lateinit var sessionRegistry: UserCreatorChatWebSocketSessionRegistry
@MockBean
private lateinit var objectMapper: ObjectMapper
private val response = Mockito.mock(ServerHttpResponse::class.java)
private val wsHandler = Mockito.mock(WebSocketHandler::class.java)
@Test
@DisplayName("유효한 Bearer token이 있으면 등록된 WebSocket auth interceptor가 handshake를 허용한다")
fun shouldAcceptHandshakeWithValidBearerToken() {
val member = Member(email = "ws-handshake@test.com", password = "pw", nickname = "ws-handshake")
.apply { id = 10L }
val authentication = UsernamePasswordAuthenticationToken(MemberAdapter(member), "valid-token")
Mockito.`when`(tokenProvider.validateToken("valid-token")).thenReturn(true)
Mockito.`when`(tokenProvider.getAuthentication("valid-token")).thenReturn(authentication)
val attributes = mutableMapOf<String, Any>()
val result = authInterceptor().beforeHandshake(
requestWithAuthorization("Bearer valid-token"),
response,
wsHandler,
attributes
)
assertTrue(result)
assertSame(authentication, attributes[UserCreatorChatWebSocketAuthInterceptor.AUTHENTICATION_ATTRIBUTE])
}
@Test
@DisplayName("Authorization header가 없으면 등록된 WebSocket auth interceptor가 handshake를 거부한다")
fun shouldRejectHandshakeWithoutAuthorizationHeader() {
val attributes = mutableMapOf<String, Any>()
val result = authInterceptor().beforeHandshake(
requestWithAuthorization(null),
response,
wsHandler,
attributes
)
assertFalse(result)
assertTrue(attributes.isEmpty())
}
@Test
@DisplayName("유효하지 않은 token이면 등록된 WebSocket auth interceptor가 handshake를 거부한다")
fun shouldRejectHandshakeWithInvalidBearerToken() {
Mockito.`when`(tokenProvider.validateToken("invalid-token")).thenReturn(false)
val attributes = mutableMapOf<String, Any>()
val result = authInterceptor().beforeHandshake(
requestWithAuthorization("Bearer invalid-token"),
response,
wsHandler,
attributes
)
assertFalse(result)
assertTrue(attributes.isEmpty())
}
private fun authInterceptor(): UserCreatorChatWebSocketAuthInterceptor {
val handler = registeredWebSocketHandler()
return handler.handshakeInterceptors.filterIsInstance<UserCreatorChatWebSocketAuthInterceptor>().single()
}
private fun registeredWebSocketHandler(): WebSocketHttpRequestHandler {
val handlerMappings = applicationContext.getBeansOfType(SimpleUrlHandlerMapping::class.java).values
val urlMap = handlerMappings.flatMap { mapping -> mapping.urlMap.entries }
val handler = urlMap.firstNotNullOfOrNull { (path, handler) ->
if (path == UserCreatorChatWebSocketConfig.ENDPOINT) handler as? WebSocketHttpRequestHandler else null
}
assertNotNull(handler, "Expected /ws/v2/user-creator-chat to be registered")
return handler!!
}
private fun requestWithAuthorization(authorization: String?): ServletServerHttpRequest {
val request = MockHttpServletRequest()
if (authorization != null) {
request.addHeader(HttpHeaders.AUTHORIZATION, authorization)
}
return ServletServerHttpRequest(request)
}
}