From 44005fbdd71e95de900b7e641cf3f8ba75e5d9ca Mon Sep 17 00:00:00 2001 From: pricelees Date: Sun, 13 Jul 2025 20:52:37 +0900 Subject: [PATCH] =?UTF-8?q?test:=20JwtHandlerTest=20=EC=BD=94=ED=8B=80?= =?UTF-8?q?=EB=A6=B0=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/auth/jwt/JwtHandlerTest.java | 118 ------------------ .../auth/infrastructure/jwt/JwtHandlerTest.kt | 61 +++++++++ 2 files changed, 61 insertions(+), 118 deletions(-) delete mode 100644 src/test/java/roomescape/global/auth/jwt/JwtHandlerTest.java create mode 100644 src/test/java/roomescape/system/auth/infrastructure/jwt/JwtHandlerTest.kt diff --git a/src/test/java/roomescape/global/auth/jwt/JwtHandlerTest.java b/src/test/java/roomescape/global/auth/jwt/JwtHandlerTest.java deleted file mode 100644 index 4a400666..00000000 --- a/src/test/java/roomescape/global/auth/jwt/JwtHandlerTest.java +++ /dev/null @@ -1,118 +0,0 @@ -package roomescape.global.auth.jwt; - -import static roomescape.system.exception.ErrorType.*; - -import java.util.Date; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.test.context.jdbc.Sql; - -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import io.restassured.RestAssured; -import roomescape.system.auth.infrastructure.jwt.JwtHandler; -import roomescape.system.exception.ErrorType; -import roomescape.system.exception.RoomEscapeException; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@Sql(scripts = "/truncate.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) -class JwtHandlerTest { - - @Autowired - private JwtHandler jwtHandler; - - @Value("${security.jwt.token.secret-key}") - private String secretKey; - - @LocalServerPort - private int port; - - @BeforeEach - void setUp() { - RestAssured.port = port; - } - - @Test - @DisplayName("토큰이 만료되면 401 Unauthorized 를 발생시킨다.") - void jwtExpired() { - //given - Date date = new Date(); - Date expiredAt = new Date(date.getTime() - 1); - - String accessToken = Jwts.builder() - .claim("memberId", 1L) - .setIssuedAt(date) - .setExpiration(expiredAt) - .signWith(SignatureAlgorithm.HS256, secretKey.getBytes()) - .compact(); - - // when & then - Assertions.assertThatThrownBy(() -> jwtHandler.getMemberIdFromToken(accessToken)) - .isInstanceOf(RoomEscapeException.class) - .hasMessage(EXPIRED_TOKEN.getDescription()); - } - - @Test - @DisplayName("지원하지 않는 토큰이면 401 Unauthorized 를 발생시킨다.") - void jwtMalformed() { - // given - Date date = new Date(); - Date expiredAt = new Date(date.getTime() + 100000); - - String accessToken = Jwts.builder() - .claim("memberId", 1L) - .setIssuedAt(date) - .setExpiration(expiredAt) - .signWith(SignatureAlgorithm.HS256, secretKey.getBytes()) - .compact(); - - String[] splitAccessToken = accessToken.split("\\."); - String unsupportedAccessToken = splitAccessToken[0] + "." + splitAccessToken[1]; - - // when & then - Assertions.assertThatThrownBy(() -> jwtHandler.getMemberIdFromToken(unsupportedAccessToken)) - .isInstanceOf(RoomEscapeException.class) - .hasMessage(ErrorType.MALFORMED_TOKEN.getDescription()); - } - - @Test - @DisplayName("토큰의 Signature 가 잘못되었다면 401 Unauthorized 를 발생시킨다.") - void jwtInvalidSignature() { - // given - Date date = new Date(); - Date expiredAt = new Date(date.getTime() + 100000); - - String invalidSecretKey = secretKey.substring(1); - - String accessToken = Jwts.builder() - .claim("memberId", 1L) - .setIssuedAt(date) - .setExpiration(expiredAt) - .signWith(SignatureAlgorithm.HS256, invalidSecretKey.getBytes()) // 기존은 HS256 알고리즘 - .compact(); - - // when & then - Assertions.assertThatThrownBy(() -> jwtHandler.getMemberIdFromToken(accessToken)) - .isInstanceOf(RoomEscapeException.class) - .hasMessage(ErrorType.INVALID_SIGNATURE_TOKEN.getDescription()); - } - - @Test - @DisplayName("토큰이 공백값이라면 401 Unauthorized 를 발생시킨다.") - void jwtIllegal() { - // given - String accessToken = ""; - - // when & then - Assertions.assertThatThrownBy(() -> jwtHandler.getMemberIdFromToken(accessToken)) - .isInstanceOf(RoomEscapeException.class) - .hasMessage(ErrorType.ILLEGAL_TOKEN.getDescription()); - } -} diff --git a/src/test/java/roomescape/system/auth/infrastructure/jwt/JwtHandlerTest.kt b/src/test/java/roomescape/system/auth/infrastructure/jwt/JwtHandlerTest.kt new file mode 100644 index 00000000..b7565255 --- /dev/null +++ b/src/test/java/roomescape/system/auth/infrastructure/jwt/JwtHandlerTest.kt @@ -0,0 +1,61 @@ +package roomescape.system.auth.infrastructure.jwt + +import io.jsonwebtoken.Jwts +import io.jsonwebtoken.SignatureAlgorithm +import io.kotest.assertions.throwables.shouldThrow +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import roomescape.common.JwtFixture +import roomescape.system.exception.ErrorType +import roomescape.system.exception.RoomEscapeException +import java.util.* +import kotlin.random.Random + +class JwtHandlerTest : FunSpec({ + + context("JWT 토큰 조회") { + val memberId = Random.nextLong() + val jwtHandler: JwtHandler = JwtFixture.create() + + test("토큰에서 멤버 ID를 올바르게 추출한다.") { + val token = jwtHandler.createToken(memberId) + val extractedMemberId = jwtHandler.getMemberIdFromToken(token) + + extractedMemberId shouldBe memberId + } + + test("만료된 토큰이면 예외를 던진다.") { + // given + val expirationTime = 0L + val shortExpirationTimeJwtHandler: JwtHandler = JwtFixture.create(expirationTime = expirationTime) + val token = shortExpirationTimeJwtHandler.createToken(memberId) + + Thread.sleep(expirationTime) // 만료 시간 이후로 대기 + + // when & then + shouldThrow { + shortExpirationTimeJwtHandler.getMemberIdFromToken(token) + }.errorType shouldBe ErrorType.EXPIRED_TOKEN + } + + test("토큰이 빈 값이면 예외를 던진다.") { + shouldThrow { + jwtHandler.getMemberIdFromToken("") + }.errorType shouldBe ErrorType.INVALID_TOKEN + } + + test("시크릿 키가 잘못된 경우 예외를 던진다.") { + val now: Date = Date() + val invalidSignatureToken: String = Jwts.builder() + .claim("memberId", memberId) + .setIssuedAt(now) + .setExpiration(Date(now.time + JwtFixture.EXPIRATION_TIME)) + .signWith(SignatureAlgorithm.HS256, JwtFixture.SECRET_KEY.substring(1).toByteArray()) + .compact() + + shouldThrow { + jwtHandler.getMemberIdFromToken(invalidSignatureToken) + }.errorType shouldBe ErrorType.INVALID_SIGNATURE_TOKEN + } + } +})