test(user-creator-chat): WebSocket handshake slice 검증을 추가한다
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user