Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[KAN-107] common 패키지 테스트코드 #84

Merged
merged 7 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
package com.restaurant.be.common.config

import com.fasterxml.jackson.databind.ObjectMapper
import com.restaurant.be.common.jwt.JwtFilter
import com.restaurant.be.common.jwt.JwtUserRepository
import com.restaurant.be.common.jwt.TokenProvider
import com.restaurant.be.common.redis.RedisRepository
import org.springframework.security.config.annotation.SecurityConfigurerAdapter
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.DefaultSecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

class JwtSecurityConfig(
private val tokenProvider: TokenProvider,
private val jwtUserRepository: JwtUserRepository,
private val redisRepository: RedisRepository,
private val objectMapper: ObjectMapper
private val jwtUserRepository: JwtUserRepository
) : SecurityConfigurerAdapter<DefaultSecurityFilterChain?, HttpSecurity>() {

override fun configure(http: HttpSecurity) {
val customFilter =
JwtFilter(tokenProvider, jwtUserRepository, redisRepository, objectMapper)
JwtFilter(tokenProvider, jwtUserRepository)
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter::class.java)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ class SecurityConfig(
.apply(
JwtSecurityConfig(
tokenProvider,
jwtUserRepository,
redisRepository,
objectMapper
jwtUserRepository
)
)
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ class GlobalExceptionHandler(
e: ServerWebInputException,
request: HttpServletRequest
): CommonResponse<String?> {
val data = if (e.cause?.cause is MissingKotlinParameterException) {
val param = (e.cause?.cause as MissingKotlinParameterException).parameter.name
val data = if (e.cause is MissingKotlinParameterException) {
val param = (e.cause as MissingKotlinParameterException).parameter.name
"항목 ${param}을 확인해주세요"
} else if (e.cause?.cause is MismatchedInputException) {
e.message
} else if (e.cause is MismatchedInputException) {
"Mismatched input"
} else {
null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ data class NotFoundUserEmailException(
override val message: String = "존재 하지 않는 유저 이메일 입니다."
) : ServerException(400, message)

data class NotFoundUserIdException(
override val message: String = "유저 고유 ID가 존재하지 않습니다"
) : ServerException(500, message)

data class WithdrawalUserException(
override val message: String = "탈퇴한 유저 입니다."
) : ServerException(400, message)
Expand Down
8 changes: 2 additions & 6 deletions src/main/kotlin/com/restaurant/be/common/jwt/JwtFilter.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.restaurant.be.common.jwt

import com.fasterxml.jackson.databind.ObjectMapper
import com.restaurant.be.common.redis.RedisRepository
import mu.KotlinLogging
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContextHolder
Expand All @@ -14,13 +12,11 @@ import javax.servlet.http.HttpServletResponse

class JwtFilter(
private val tokenProvider: TokenProvider,
private val jwtUserRepository: JwtUserRepository,
private val redisRepository: RedisRepository,
private val objectMapper: ObjectMapper
private val jwtUserRepository: JwtUserRepository
) : OncePerRequestFilter() {

private val log = KotlinLogging.logger {}
override fun doFilterInternal(
public override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
Expand Down
6 changes: 3 additions & 3 deletions src/main/kotlin/com/restaurant/be/common/jwt/TokenProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ class TokenProvider(
private final val tokenValidityInMilliseconds: Long
private final val accessTokenValidityInMilliseconds: Long
final val refreshTokenValidityInMilliseconds: Long
private var key: Key? = null
var key: Key? = null

init {
accessTokenValidityInMilliseconds = accessTokenValidityInSeconds * 1000
refreshTokenValidityInMilliseconds = refreshTokenValidityInSeconds * 1000
this.tokenValidityInMilliseconds = tokenValidityInMilliseconds
}

private val log = KotlinLogging.logger {}
val log = KotlinLogging.logger {}

fun createTokens(email: String, roles: List<String>): Token {
val claims: MutableMap<String, Any?> = HashMap()
Expand Down Expand Up @@ -116,7 +116,7 @@ class TokenProvider(
): Token {
val createdDate = Date()
val email = getEmailFromToken(accessToken)
val refreshTokenInDBMS = redisRepository.getValue(redisRepository.REFRESH_PREFIX + email)
val refreshTokenInDBMS = redisRepository.getValue("RT:$email")
if (!refreshTokenInDBMS.equals(refreshToken)) {
throw InvalidTokenException()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ class RedisRepository(
private const val RECOMMENDATION_PREFIX = "RECOMMENDATION:"
}

val REFRESH_PREFIX: String = "RT:"

// 사용자별 추천 식당을 조회하는 메서드
fun getRecommendation(userId: Long): List<Long> {
val values = redisTemplate.opsForValue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@ data class CommonResponse<T>(
) {

companion object {
// status 200 + success (message가 있을 경우)
fun <T> success(data: T, message: String): CommonResponse<T> {
return CommonResponse(
result = Result.SUCCESS,
data = data,
message = message,
errorCode = null
)
}

// status 200 + success (message가 없을 경우)
fun <T> success(data: T): CommonResponse<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,11 @@ enum class ErrorCode(
val errorMsg: String
) {
// 500
COMMON_SYSTEM_ERROR("일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요."),

// 400
COMMON_NULL_PARAMETER("빠뜨린 값이 없는지 확인 해주세요."),

COMMON_INVALID_PARAMETER("요청한 값이 올바르지 않습니다.")

;

fun getErrorMsg(vararg arg: Any?): String {
return String.format(errorMsg, *arg)
}
}
11 changes: 1 addition & 10 deletions src/main/kotlin/com/restaurant/be/common/response/Token.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,4 @@ data class Token(
val tokenType: String,
val expiresIn: Long,
val issuedAt: Date
) {

constructor() : this(
accessToken = "",
refreshToken = "",
tokenType = "",
expiresIn = 0,
issuedAt = Date()
)
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class SignInUserService(
val token = tokenProvider.createTokens(email, user.roles)

redisRepository.setValue(
redisRepository.REFRESH_PREFIX + email,
"RT:$email",
token.refreshToken,
tokenProvider.refreshTokenValidityInMilliseconds,
TimeUnit.MILLISECONDS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class SignUpUserService(
val token = tokenProvider.createTokens(email, newUser.roles)

redisRepository.setValue(
redisRepository.REFRESH_PREFIX + email,
"RT:$email",
token.refreshToken,
tokenProvider.refreshTokenValidityInMilliseconds,
TimeUnit.MILLISECONDS
Expand Down
32 changes: 32 additions & 0 deletions src/test/kotlin/com/restaurant/be/BeApplicationTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.restaurant.be

import com.restaurant.be.common.CustomDescribeSpec
import com.restaurant.be.common.IntegrationTest
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
import org.springframework.context.ApplicationContextException

@IntegrationTest
class BeApplicationTest(
context: org.springframework.context.ApplicationContext
) : CustomDescribeSpec() {

init {
describe("BeApplication") {
it("should load Spring context successfully") {
context shouldNotBe null
}

it("should have BeApplication bean") {
context.containsBean("beApplication") shouldBe true
}

it("test") {
shouldThrow<ApplicationContextException> {
main(arrayOf())
}
}
}
}
}
11 changes: 0 additions & 11 deletions src/test/kotlin/com/restaurant/be/BeApplicationTests.kt

This file was deleted.

37 changes: 37 additions & 0 deletions src/test/kotlin/com/restaurant/be/WebRestControllerTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.restaurant.be

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.shouldBe
import io.mockk.every
import io.mockk.mockk
import org.springframework.core.env.Environment

class WebRestControllerTest : DescribeSpec({

val environment = mockk<Environment>()
val controller = WebRestController(environment)

describe("WebRestController") {

context("when there is an active profile") {
it("should return the active profile") {
val activeProfile = "test-profile"
every { environment.activeProfiles } returns arrayOf(activeProfile)

val result = controller.getProfile()

result shouldBe activeProfile
}
}

context("when there is no active profile") {
it("should return 'No Active Profile'") {
every { environment.activeProfiles } returns arrayOf()

val result = controller.getProfile()

result shouldBe "No Active Profile"
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.restaurant.be.common.config

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.shouldBe
import org.springframework.test.context.ContextConfiguration

@ContextConfiguration(classes = [DiscordClientConfig::class])
class DiscordClientConfigTest : DescribeSpec({

describe("DiscordClientConfig") {
val validMonitorUrl = "https://discord.com/api/v9/webhooks/123456789012345678/abcdefg12345"
val invalidMonitorUrl = "http://invalid.url"
val dummyUrl = "https://discord.com/api/v9/webhooks/99999990000000/213aWRR5sEeY5UhOk7twvFSDFVC-Feqw"

describe("monitorReportClient") {
it("should return WebhookClient with monitorUrl when it is valid") {
// Given
val config = DiscordClientConfig(validMonitorUrl)

// When
val webhookClient = config.monitorReportClient()

// Then
webhookClient.url shouldBe validMonitorUrl
}

it("should return WebhookClient with dummyUrl when monitorUrl is invalid") {
// Given
val config = DiscordClientConfig(invalidMonitorUrl)

// When
val webhookClient = config.monitorReportClient()

// Then
webhookClient.url shouldBe dummyUrl
}
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.restaurant.be.common.config

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.shouldBe
import io.swagger.annotations.ApiModelProperty

class SwaggerConfigTest : DescribeSpec({
describe("PageModel") {

it("should have default values set correctly") {
// When
val pageModel = SwaggerConfig.PageModel()

// Then
pageModel.page shouldBe 0
pageModel.size shouldBe 0
pageModel.sort shouldBe listOf<String>()
}

it("should have correct ApiModelProperty annotations") {
// Given
val pageField = SwaggerConfig.PageModel::class.java.getDeclaredField("page")
val sizeField = SwaggerConfig.PageModel::class.java.getDeclaredField("size")
val sortField = SwaggerConfig.PageModel::class.java.getDeclaredField("sort")

// When
val pageAnnotation = pageField.getAnnotation(ApiModelProperty::class.java)
val sizeAnnotation = sizeField.getAnnotation(ApiModelProperty::class.java)
val sortAnnotation = sortField.getAnnotation(ApiModelProperty::class.java)

// Then
pageAnnotation.value shouldBe "페이지 번호(0..N)"
pageAnnotation.example shouldBe "0"

sizeAnnotation.value shouldBe "페이지 크기"
sizeAnnotation.allowableValues shouldBe "range[0, 100]"
sizeAnnotation.example shouldBe "0"

sortAnnotation.value shouldBe "정렬(사용법: 컬럼명,ASC|DESC)"
}
}
})
Loading
Loading