generated from pricelees/issue-pr-template
[#22] 프론트엔드 React 전환 및 인증 API 수정 #23
@ -13,8 +13,8 @@ import roomescape.member.infrastructure.persistence.MemberEntity
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
class AuthInterceptor(
|
class AuthInterceptor(
|
||||||
private val memberService: MemberService,
|
private val memberService: MemberService,
|
||||||
private val jwtHandler: JwtHandler
|
private val jwtHandler: JwtHandler
|
||||||
) : HandlerInterceptor {
|
) : HandlerInterceptor {
|
||||||
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
|
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
|
||||||
if (handler !is HandlerMethod) {
|
if (handler !is HandlerMethod) {
|
||||||
@ -31,7 +31,6 @@ class AuthInterceptor(
|
|||||||
val member: MemberEntity = findMember(request, response)
|
val member: MemberEntity = findMember(request, response)
|
||||||
|
|
||||||
if (admin != null && !member.isAdmin()) {
|
if (admin != null && !member.isAdmin()) {
|
||||||
response.sendRedirect("/login")
|
|
||||||
throw AuthException(AuthErrorCode.ACCESS_DENIED)
|
throw AuthException(AuthErrorCode.ACCESS_DENIED)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +44,6 @@ class AuthInterceptor(
|
|||||||
|
|
||||||
return memberService.findById(memberId)
|
return memberService.findById(memberId)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
response.sendRedirect("/login")
|
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ import roomescape.util.RoomescapeApiTest
|
|||||||
|
|
||||||
@WebMvcTest(controllers = [AuthController::class])
|
@WebMvcTest(controllers = [AuthController::class])
|
||||||
class AuthControllerTest(
|
class AuthControllerTest(
|
||||||
val mockMvc: MockMvc
|
val mockMvc: MockMvc
|
||||||
) : RoomescapeApiTest() {
|
) : RoomescapeApiTest() {
|
||||||
|
|
||||||
@SpykBean
|
@SpykBean
|
||||||
@ -41,9 +41,9 @@ class AuthControllerTest(
|
|||||||
|
|
||||||
Then("토큰을 쿠키에 담아 응답한다") {
|
Then("토큰을 쿠키에 담아 응답한다") {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = userRequest,
|
body = userRequest,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
header {
|
header {
|
||||||
@ -61,12 +61,12 @@ class AuthControllerTest(
|
|||||||
memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
|
memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
|
||||||
} returns null
|
} returns null
|
||||||
|
|
||||||
Then("에러 응답") {
|
Then("에러 응답을 받는다.") {
|
||||||
val expectedError = AuthErrorCode.LOGIN_FAILED
|
val expectedError = AuthErrorCode.LOGIN_FAILED
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = userRequest,
|
body = userRequest,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code", equalTo(expectedError.errorCode))
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
@ -78,14 +78,14 @@ class AuthControllerTest(
|
|||||||
|
|
||||||
Then("400 에러를 응답한다") {
|
Then("400 에러를 응답한다") {
|
||||||
listOf(
|
listOf(
|
||||||
userRequest.copy(email = "invalid"),
|
userRequest.copy(email = "invalid"),
|
||||||
userRequest.copy(password = " "),
|
userRequest.copy(password = " "),
|
||||||
"{\"email\": \"null\", \"password\": \"null\"}"
|
"{\"email\": \"null\", \"password\": \"null\"}"
|
||||||
).forEach {
|
).forEach {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = it,
|
body = it,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedErrorCode.httpStatus.value()) }
|
status { isEqualTo(expectedErrorCode.httpStatus.value()) }
|
||||||
jsonPath("$.code", equalTo(expectedErrorCode.errorCode))
|
jsonPath("$.code", equalTo(expectedErrorCode.errorCode))
|
||||||
@ -103,8 +103,8 @@ class AuthControllerTest(
|
|||||||
|
|
||||||
Then("회원의 이름을 응답한다") {
|
Then("회원의 이름을 응답한다") {
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
jsonPath("$.data.name", equalTo(user.name))
|
jsonPath("$.data.name", equalTo(user.name))
|
||||||
@ -118,11 +118,11 @@ class AuthControllerTest(
|
|||||||
every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId
|
every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId
|
||||||
every { memberRepository.findByIdOrNull(invalidMemberId) } returns null
|
every { memberRepository.findByIdOrNull(invalidMemberId) } returns null
|
||||||
|
|
||||||
Then("에러 응답.") {
|
Then("에러 응답을 받는다.") {
|
||||||
val expectedError = AuthErrorCode.UNIDENTIFIABLE_MEMBER
|
val expectedError = AuthErrorCode.UNIDENTIFIABLE_MEMBER
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code", equalTo(expectedError.errorCode))
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
@ -137,15 +137,14 @@ class AuthControllerTest(
|
|||||||
When("로그인 상태가 아니라면") {
|
When("로그인 상태가 아니라면") {
|
||||||
doNotLogin()
|
doNotLogin()
|
||||||
|
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.INVALID_TOKEN
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
string("Location", "/login")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,8 +154,8 @@ class AuthControllerTest(
|
|||||||
|
|
||||||
Then("토큰의 존재 여부와 무관하게 토큰을 만료시킨다.") {
|
Then("토큰의 존재 여부와 무관하게 토큰을 만료시킨다.") {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
header {
|
header {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import io.mockk.every
|
|||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
import roomescape.member.web.MemberController
|
import roomescape.member.web.MemberController
|
||||||
import roomescape.member.web.MemberRetrieveListResponse
|
import roomescape.member.web.MemberRetrieveListResponse
|
||||||
import roomescape.util.MemberFixture
|
import roomescape.util.MemberFixture
|
||||||
@ -15,7 +16,7 @@ import kotlin.random.Random
|
|||||||
|
|
||||||
@WebMvcTest(controllers = [MemberController::class])
|
@WebMvcTest(controllers = [MemberController::class])
|
||||||
class MemberControllerTest(
|
class MemberControllerTest(
|
||||||
@Autowired private val mockMvc: MockMvc
|
@Autowired private val mockMvc: MockMvc
|
||||||
) : RoomescapeApiTest() {
|
) : RoomescapeApiTest() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -23,9 +24,9 @@ class MemberControllerTest(
|
|||||||
val endpoint = "/members"
|
val endpoint = "/members"
|
||||||
|
|
||||||
every { memberRepository.findAll() } returns listOf(
|
every { memberRepository.findAll() } returns listOf(
|
||||||
MemberFixture.create(id = Random.nextLong(), name = "name1"),
|
MemberFixture.create(id = Random.nextLong(), name = "name1"),
|
||||||
MemberFixture.create(id = Random.nextLong(), name = "name2"),
|
MemberFixture.create(id = Random.nextLong(), name = "name2"),
|
||||||
MemberFixture.create(id = Random.nextLong(), name = "name3"),
|
MemberFixture.create(id = Random.nextLong(), name = "name3"),
|
||||||
)
|
)
|
||||||
|
|
||||||
`when`("관리자가 보내면") {
|
`when`("관리자가 보내면") {
|
||||||
@ -33,15 +34,15 @@ class MemberControllerTest(
|
|||||||
|
|
||||||
then("성공한다.") {
|
then("성공한다.") {
|
||||||
val result: String = runGetTest(
|
val result: String = runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
}.andReturn().response.contentAsString
|
}.andReturn().response.contentAsString
|
||||||
|
|
||||||
val response: MemberRetrieveListResponse = readValue(
|
val response: MemberRetrieveListResponse = readValue(
|
||||||
responseJson = result,
|
responseJson = result,
|
||||||
valueType = MemberRetrieveListResponse::class.java
|
valueType = MemberRetrieveListResponse::class.java
|
||||||
)
|
)
|
||||||
|
|
||||||
assertSoftly(response.members) {
|
assertSoftly(response.members) {
|
||||||
@ -51,32 +52,32 @@ class MemberControllerTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
`when`("관리자가 아니면 로그인 페이지로 이동한다.") {
|
`when`("관리자가 아니면 에러 응답을 받는다.") {
|
||||||
then("비회원") {
|
then("비회원") {
|
||||||
doNotLogin()
|
doNotLogin()
|
||||||
|
val expectedError = AuthErrorCode.INVALID_TOKEN
|
||||||
|
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
}.andExpect {
|
||||||
string("Location", "/login")
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
then("일반 회원") {
|
then("일반 회원") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
}.andExpect {
|
||||||
string("Location", "/login")
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,14 +9,13 @@ import io.restassured.module.kotlin.extensions.Given
|
|||||||
import io.restassured.module.kotlin.extensions.Then
|
import io.restassured.module.kotlin.extensions.Then
|
||||||
import io.restassured.module.kotlin.extensions.When
|
import io.restassured.module.kotlin.extensions.When
|
||||||
import jakarta.persistence.EntityManager
|
import jakarta.persistence.EntityManager
|
||||||
import org.hamcrest.Matchers.containsString
|
|
||||||
import org.hamcrest.Matchers.equalTo
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.springframework.boot.test.context.SpringBootTest
|
import org.springframework.boot.test.context.SpringBootTest
|
||||||
import org.springframework.boot.test.web.server.LocalServerPort
|
import org.springframework.boot.test.web.server.LocalServerPort
|
||||||
import org.springframework.http.HttpHeaders
|
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.transaction.support.TransactionTemplate
|
import org.springframework.transaction.support.TransactionTemplate
|
||||||
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
import roomescape.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.auth.web.support.MemberIdResolver
|
import roomescape.auth.web.support.MemberIdResolver
|
||||||
import roomescape.member.business.MemberService
|
import roomescape.member.business.MemberService
|
||||||
@ -38,9 +37,9 @@ import java.time.LocalTime
|
|||||||
|
|
||||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
class ReservationControllerTest(
|
class ReservationControllerTest(
|
||||||
@LocalServerPort val port: Int,
|
@LocalServerPort val port: Int,
|
||||||
val entityManager: EntityManager,
|
val entityManager: EntityManager,
|
||||||
val transactionTemplate: TransactionTemplate
|
val transactionTemplate: TransactionTemplate
|
||||||
) : FunSpec({
|
) : FunSpec({
|
||||||
extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_EACH_TEST))
|
extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_EACH_TEST))
|
||||||
}) {
|
}) {
|
||||||
@ -66,9 +65,9 @@ class ReservationControllerTest(
|
|||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val reservationRequest = createRequest()
|
val reservationRequest = createRequest()
|
||||||
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
||||||
paymentKey = reservationRequest.paymentKey,
|
paymentKey = reservationRequest.paymentKey,
|
||||||
orderId = reservationRequest.orderId,
|
orderId = reservationRequest.orderId,
|
||||||
totalAmount = reservationRequest.amount,
|
totalAmount = reservationRequest.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every {
|
||||||
@ -108,12 +107,12 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("결제 완료 후 예약 / 결제 정보 저장 과정에서 에러 발생시 결제 취소 후 에러 응답") {
|
test("결제 완료 후 예약 / 결제 정보 저장 과정에서 에러 발생시 결제 취소 후 에러 응답을 받는다.") {
|
||||||
val reservationRequest = createRequest()
|
val reservationRequest = createRequest()
|
||||||
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
||||||
paymentKey = reservationRequest.paymentKey,
|
paymentKey = reservationRequest.paymentKey,
|
||||||
orderId = reservationRequest.orderId,
|
orderId = reservationRequest.orderId,
|
||||||
totalAmount = reservationRequest.amount,
|
totalAmount = reservationRequest.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every {
|
||||||
@ -129,8 +128,8 @@ class ReservationControllerTest(
|
|||||||
} returns PaymentFixture.createCancelResponse()
|
} returns PaymentFixture.createCancelResponse()
|
||||||
|
|
||||||
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
Long::class.java
|
Long::class.java
|
||||||
).singleResult
|
).singleResult
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -145,8 +144,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
Long::class.java
|
Long::class.java
|
||||||
).singleResult
|
).singleResult
|
||||||
|
|
||||||
canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L
|
canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L
|
||||||
@ -203,6 +202,7 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
test("관리자만 검색할 수 있다.") {
|
test("관리자만 검색할 수 있다.") {
|
||||||
login(reservations.keys.first())
|
login(reservations.keys.first())
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -210,7 +210,8 @@ class ReservationControllerTest(
|
|||||||
}.When {
|
}.When {
|
||||||
get("/reservations/search")
|
get("/reservations/search")
|
||||||
}.Then {
|
}.Then {
|
||||||
header(HttpHeaders.CONTENT_TYPE, containsString(MediaType.TEXT_HTML_VALUE))
|
statusCode(expectedError.httpStatus.value())
|
||||||
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,14 +310,15 @@ class ReservationControllerTest(
|
|||||||
test("관리자만 예약을 삭제할 수 있다.") {
|
test("관리자만 예약을 삭제할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(MemberFixture.create(role = Role.MEMBER))
|
||||||
val reservation: ReservationEntity = reservations.values.flatten().first()
|
val reservation: ReservationEntity = reservations.values.flatten().first()
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
}.When {
|
}.When {
|
||||||
delete("/reservations/${reservation.id}")
|
delete("/reservations/${reservation.id}")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(302)
|
statusCode(expectedError.httpStatus.value())
|
||||||
header(HttpHeaders.LOCATION, containsString("/login"))
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,8 +328,8 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
transactionTemplate.execute {
|
transactionTemplate.execute {
|
||||||
val reservation: ReservationEntity = entityManager.find(
|
val reservation: ReservationEntity = entityManager.find(
|
||||||
ReservationEntity::class.java,
|
ReservationEntity::class.java,
|
||||||
reservationId
|
reservationId
|
||||||
)
|
)
|
||||||
reservation.reservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
reservation.reservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
entityManager.persist(reservation)
|
entityManager.persist(reservation)
|
||||||
@ -346,8 +348,8 @@ class ReservationControllerTest(
|
|||||||
// 예약이 삭제되었는지 확인
|
// 예약이 삭제되었는지 확인
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
val deletedReservation = entityManager.find(
|
val deletedReservation = entityManager.find(
|
||||||
ReservationEntity::class.java,
|
ReservationEntity::class.java,
|
||||||
reservationId
|
reservationId
|
||||||
)
|
)
|
||||||
deletedReservation shouldBe null
|
deletedReservation shouldBe null
|
||||||
}
|
}
|
||||||
@ -371,8 +373,8 @@ class ReservationControllerTest(
|
|||||||
} returns PaymentFixture.createCancelResponse()
|
} returns PaymentFixture.createCancelResponse()
|
||||||
|
|
||||||
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
Long::class.java
|
Long::class.java
|
||||||
).singleResult
|
).singleResult
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -384,8 +386,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeAfterApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
Long::class.java
|
Long::class.java
|
||||||
).singleResult
|
).singleResult
|
||||||
|
|
||||||
canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L
|
canceledPaymentSizeAfterApiCall shouldBe canceledPaymentSizeBeforeApiCall + 1L
|
||||||
@ -397,10 +399,10 @@ class ReservationControllerTest(
|
|||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
val member = login(MemberFixture.create(role = Role.ADMIN))
|
||||||
val adminRequest: AdminReservationCreateRequest = createRequest().let {
|
val adminRequest: AdminReservationCreateRequest = createRequest().let {
|
||||||
AdminReservationCreateRequest(
|
AdminReservationCreateRequest(
|
||||||
date = it.date,
|
date = it.date,
|
||||||
themeId = it.themeId,
|
themeId = it.themeId,
|
||||||
timeId = it.timeId,
|
timeId = it.timeId,
|
||||||
memberId = member.id!!,
|
memberId = member.id!!,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,6 +427,7 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
test("관리자가 아니면 조회할 수 없다.") {
|
test("관리자가 아니면 조회할 수 없다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(MemberFixture.create(role = Role.MEMBER))
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -432,14 +435,15 @@ class ReservationControllerTest(
|
|||||||
}.When {
|
}.When {
|
||||||
get("/reservations/waiting")
|
get("/reservations/waiting")
|
||||||
}.Then {
|
}.Then {
|
||||||
header(HttpHeaders.CONTENT_TYPE, containsString(MediaType.TEXT_HTML_VALUE))
|
statusCode(expectedError.httpStatus.value())
|
||||||
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("대기 중인 예약 목록을 조회한다.") {
|
test("대기 중인 예약 목록을 조회한다.") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(MemberFixture.create(role = Role.ADMIN))
|
||||||
val expected = reservations.values.flatten()
|
val expected = reservations.values.flatten()
|
||||||
.count { it.reservationStatus == ReservationStatus.WAITING }
|
.count { it.reservationStatus == ReservationStatus.WAITING }
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -458,9 +462,9 @@ class ReservationControllerTest(
|
|||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = login(MemberFixture.create(role = Role.MEMBER))
|
||||||
val waitingCreateRequest: WaitingCreateRequest = createRequest().let {
|
val waitingCreateRequest: WaitingCreateRequest = createRequest().let {
|
||||||
WaitingCreateRequest(
|
WaitingCreateRequest(
|
||||||
date = it.date,
|
date = it.date,
|
||||||
themeId = it.themeId,
|
themeId = it.themeId,
|
||||||
timeId = it.timeId
|
timeId = it.timeId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,11 +487,11 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
val reservation = ReservationFixture.create(
|
val reservation = ReservationFixture.create(
|
||||||
date = reservationRequest.date,
|
date = reservationRequest.date,
|
||||||
theme = entityManager.find(ThemeEntity::class.java, reservationRequest.themeId),
|
theme = entityManager.find(ThemeEntity::class.java, reservationRequest.themeId),
|
||||||
time = entityManager.find(TimeEntity::class.java, reservationRequest.timeId),
|
time = entityManager.find(TimeEntity::class.java, reservationRequest.timeId),
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
entityManager.persist(reservation)
|
entityManager.persist(reservation)
|
||||||
entityManager.flush()
|
entityManager.flush()
|
||||||
@ -496,9 +500,9 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
// 이미 예약된 시간, 테마로 대기 예약 요청
|
// 이미 예약된 시간, 테마로 대기 예약 요청
|
||||||
val waitingCreateRequest = WaitingCreateRequest(
|
val waitingCreateRequest = WaitingCreateRequest(
|
||||||
date = reservationRequest.date,
|
date = reservationRequest.date,
|
||||||
themeId = reservationRequest.themeId,
|
themeId = reservationRequest.themeId,
|
||||||
timeId = reservationRequest.timeId
|
timeId = reservationRequest.timeId
|
||||||
)
|
)
|
||||||
val expectedError = ReservationErrorCode.ALREADY_RESERVE
|
val expectedError = ReservationErrorCode.ALREADY_RESERVE
|
||||||
|
|
||||||
@ -524,8 +528,8 @@ class ReservationControllerTest(
|
|||||||
test("대기 중인 예약을 취소한다.") {
|
test("대기 중인 예약을 취소한다.") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = login(MemberFixture.create(role = Role.MEMBER))
|
||||||
val waiting: ReservationEntity = createSingleReservation(
|
val waiting: ReservationEntity = createSingleReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -538,8 +542,8 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
transactionTemplate.executeWithoutResult { _ ->
|
||||||
entityManager.find(
|
entityManager.find(
|
||||||
ReservationEntity::class.java,
|
ReservationEntity::class.java,
|
||||||
waiting.id
|
waiting.id
|
||||||
) shouldBe null
|
) shouldBe null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -547,8 +551,8 @@ class ReservationControllerTest(
|
|||||||
test("이미 확정된 예약을 삭제하면 예외 응답") {
|
test("이미 확정된 예약을 삭제하면 예외 응답") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = login(MemberFixture.create(role = Role.MEMBER))
|
||||||
val reservation: ReservationEntity = createSingleReservation(
|
val reservation: ReservationEntity = createSingleReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
)
|
)
|
||||||
|
|
||||||
val expectedError = ReservationErrorCode.ALREADY_CONFIRMED
|
val expectedError = ReservationErrorCode.ALREADY_CONFIRMED
|
||||||
@ -566,22 +570,22 @@ class ReservationControllerTest(
|
|||||||
context("POST /reservations/waiting/{id}/confirm") {
|
context("POST /reservations/waiting/{id}/confirm") {
|
||||||
test("관리자만 승인할 수 있다.") {
|
test("관리자만 승인할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(MemberFixture.create(role = Role.MEMBER))
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
}.When {
|
}.When {
|
||||||
post("/reservations/waiting/1/confirm")
|
post("/reservations/waiting/1/confirm")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(302)
|
statusCode(expectedError.httpStatus.value())
|
||||||
header(HttpHeaders.LOCATION, containsString("/login"))
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("대기 예약을 승인하면 결제 대기 상태로 변경") {
|
test("대기 예약을 승인하면 결제 대기 상태로 변경") {
|
||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
val member = login(MemberFixture.create(role = Role.ADMIN))
|
||||||
val reservation = createSingleReservation(
|
val reservation = createSingleReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -594,8 +598,8 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
transactionTemplate.executeWithoutResult { _ ->
|
||||||
entityManager.find(
|
entityManager.find(
|
||||||
ReservationEntity::class.java,
|
ReservationEntity::class.java,
|
||||||
reservation.id
|
reservation.id
|
||||||
)?.also {
|
)?.also {
|
||||||
it.reservationStatus shouldBe ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
it.reservationStatus shouldBe ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
} ?: throw AssertionError("Reservation not found")
|
} ?: throw AssertionError("Reservation not found")
|
||||||
@ -605,8 +609,8 @@ class ReservationControllerTest(
|
|||||||
test("다른 확정된 예약을 승인하면 예외 응답") {
|
test("다른 확정된 예약을 승인하면 예외 응답") {
|
||||||
val admin = login(MemberFixture.create(role = Role.ADMIN))
|
val admin = login(MemberFixture.create(role = Role.ADMIN))
|
||||||
val alreadyReserved = createSingleReservation(
|
val alreadyReserved = createSingleReservation(
|
||||||
member = admin,
|
member = admin,
|
||||||
status = ReservationStatus.CONFIRMED
|
status = ReservationStatus.CONFIRMED
|
||||||
)
|
)
|
||||||
|
|
||||||
val member = MemberFixture.create(account = "account", role = Role.MEMBER).also { it ->
|
val member = MemberFixture.create(account = "account", role = Role.MEMBER).also { it ->
|
||||||
@ -615,11 +619,11 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val waiting = ReservationFixture.create(
|
val waiting = ReservationFixture.create(
|
||||||
date = alreadyReserved.date,
|
date = alreadyReserved.date,
|
||||||
time = alreadyReserved.time,
|
time = alreadyReserved.time,
|
||||||
theme = alreadyReserved.theme,
|
theme = alreadyReserved.theme,
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
).also {
|
).also {
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
transactionTemplate.executeWithoutResult { _ ->
|
||||||
entityManager.persist(it)
|
entityManager.persist(it)
|
||||||
@ -642,22 +646,23 @@ class ReservationControllerTest(
|
|||||||
context("POST /reservations/waiting/{id}/reject") {
|
context("POST /reservations/waiting/{id}/reject") {
|
||||||
test("관리자만 거절할 수 있다.") {
|
test("관리자만 거절할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(MemberFixture.create(role = Role.MEMBER))
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
}.When {
|
}.When {
|
||||||
post("/reservations/waiting/1/reject")
|
post("/reservations/waiting/1/reject")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(302)
|
statusCode(expectedError.httpStatus.value())
|
||||||
header(HttpHeaders.LOCATION, containsString("/login"))
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("거절된 예약은 삭제된다.") {
|
test("거절된 예약은 삭제된다.") {
|
||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
val member = login(MemberFixture.create(role = Role.ADMIN))
|
||||||
val reservation = createSingleReservation(
|
val reservation = createSingleReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -670,8 +675,8 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
transactionTemplate.executeWithoutResult { _ ->
|
||||||
entityManager.find(
|
entityManager.find(
|
||||||
ReservationEntity::class.java,
|
ReservationEntity::class.java,
|
||||||
reservation.id
|
reservation.id
|
||||||
) shouldBe null
|
) shouldBe null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -679,18 +684,18 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createSingleReservation(
|
fun createSingleReservation(
|
||||||
date: LocalDate = LocalDate.now().plusDays(1),
|
date: LocalDate = LocalDate.now().plusDays(1),
|
||||||
time: LocalTime = LocalTime.now(),
|
time: LocalTime = LocalTime.now(),
|
||||||
themeName: String = "Default Theme",
|
themeName: String = "Default Theme",
|
||||||
member: MemberEntity = MemberFixture.create(role = Role.MEMBER),
|
member: MemberEntity = MemberFixture.create(role = Role.MEMBER),
|
||||||
status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
): ReservationEntity {
|
): ReservationEntity {
|
||||||
return ReservationFixture.create(
|
return ReservationFixture.create(
|
||||||
date = date,
|
date = date,
|
||||||
theme = ThemeFixture.create(name = themeName),
|
theme = ThemeFixture.create(name = themeName),
|
||||||
time = TimeFixture.create(startAt = time),
|
time = TimeFixture.create(startAt = time),
|
||||||
member = member,
|
member = member,
|
||||||
status = status
|
status = status
|
||||||
).also { it ->
|
).also { it ->
|
||||||
transactionTemplate.execute { _ ->
|
transactionTemplate.execute { _ ->
|
||||||
if (member.id == null) {
|
if (member.id == null) {
|
||||||
@ -708,8 +713,8 @@ class ReservationControllerTest(
|
|||||||
fun createDummyReservations(): MutableMap<MemberEntity, MutableList<ReservationEntity>> {
|
fun createDummyReservations(): MutableMap<MemberEntity, MutableList<ReservationEntity>> {
|
||||||
val reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>> = mutableMapOf()
|
val reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>> = mutableMapOf()
|
||||||
val members: List<MemberEntity> = listOf(
|
val members: List<MemberEntity> = listOf(
|
||||||
MemberFixture.create(role = Role.MEMBER),
|
MemberFixture.create(role = Role.MEMBER),
|
||||||
MemberFixture.create(role = Role.MEMBER)
|
MemberFixture.create(role = Role.MEMBER)
|
||||||
)
|
)
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
transactionTemplate.executeWithoutResult {
|
||||||
@ -728,11 +733,11 @@ class ReservationControllerTest(
|
|||||||
entityManager.persist(time)
|
entityManager.persist(time)
|
||||||
|
|
||||||
val reservation = ReservationFixture.create(
|
val reservation = ReservationFixture.create(
|
||||||
date = LocalDate.now().plusDays(index.toLong()),
|
date = LocalDate.now().plusDays(index.toLong()),
|
||||||
theme = theme,
|
theme = theme,
|
||||||
time = time,
|
time = time,
|
||||||
member = members[index % members.size],
|
member = members[index % members.size],
|
||||||
status = ReservationStatus.CONFIRMED
|
status = ReservationStatus.CONFIRMED
|
||||||
)
|
)
|
||||||
entityManager.persist(reservation)
|
entityManager.persist(reservation)
|
||||||
reservations.getOrPut(reservation.member) { mutableListOf() }.add(reservation)
|
reservations.getOrPut(reservation.member) { mutableListOf() }.add(reservation)
|
||||||
@ -745,8 +750,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createRequest(
|
fun createRequest(
|
||||||
theme: ThemeEntity = ThemeFixture.create(),
|
theme: ThemeEntity = ThemeFixture.create(),
|
||||||
time: TimeEntity = TimeFixture.create(),
|
time: TimeEntity = TimeFixture.create(),
|
||||||
): ReservationCreateWithPaymentRequest {
|
): ReservationCreateWithPaymentRequest {
|
||||||
lateinit var reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest
|
lateinit var reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest
|
||||||
|
|
||||||
@ -755,8 +760,8 @@ class ReservationControllerTest(
|
|||||||
entityManager.persist(time)
|
entityManager.persist(time)
|
||||||
|
|
||||||
reservationCreateWithPaymentRequest = ReservationFixture.createRequest(
|
reservationCreateWithPaymentRequest = ReservationFixture.createRequest(
|
||||||
themeId = theme.id!!,
|
themeId = theme.id!!,
|
||||||
timeId = time.id!!,
|
timeId = time.id!!,
|
||||||
)
|
)
|
||||||
|
|
||||||
entityManager.flush()
|
entityManager.flush()
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import io.kotest.matchers.shouldBe
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
import io.mockk.runs
|
import io.mockk.runs
|
||||||
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
@ -34,15 +35,15 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
When("로그인 상태가 아니라면") {
|
When("로그인 상태가 아니라면") {
|
||||||
doNotLogin()
|
doNotLogin()
|
||||||
|
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.INVALID_TOKEN
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
}.andExpect {
|
||||||
string("Location", "/login")
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,14 +55,14 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
every {
|
every {
|
||||||
themeRepository.findAll()
|
themeRepository.findAll()
|
||||||
} returns listOf(
|
} returns listOf(
|
||||||
ThemeFixture.create(id = 1, name = "theme1"),
|
ThemeFixture.create(id = 1, name = "theme1"),
|
||||||
ThemeFixture.create(id = 2, name = "theme2"),
|
ThemeFixture.create(id = 2, name = "theme2"),
|
||||||
ThemeFixture.create(id = 3, name = "theme3")
|
ThemeFixture.create(id = 3, name = "theme3")
|
||||||
)
|
)
|
||||||
|
|
||||||
val response: ThemeRetrieveListResponse = runGetTest(
|
val response: ThemeRetrieveListResponse = runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
content {
|
content {
|
||||||
@ -80,37 +81,37 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
Given("테마를 추가할 때") {
|
Given("테마를 추가할 때") {
|
||||||
val endpoint = "/themes"
|
val endpoint = "/themes"
|
||||||
val request = ThemeCreateRequest(
|
val request = ThemeCreateRequest(
|
||||||
name = "theme1",
|
name = "theme1",
|
||||||
description = "description1",
|
description = "description1",
|
||||||
thumbnail = "http://example.com/thumbnail1.jpg"
|
thumbnail = "http://example.com/thumbnail1.jpg"
|
||||||
)
|
)
|
||||||
|
|
||||||
When("로그인 상태가 아니라면") {
|
When("로그인 상태가 아니라면") {
|
||||||
doNotLogin()
|
doNotLogin()
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.INVALID_TOKEN
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
string("Location", "/login")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
When("관리자가 아닌 회원은") {
|
When("관리자가 아닌 회원은") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code") { value(AuthErrorCode.ACCESS_DENIED.errorCode) }
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,15 +121,15 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
|
|
||||||
val expectedError = ThemeErrorCode.THEME_NAME_DUPLICATED
|
val expectedError = ThemeErrorCode.THEME_NAME_DUPLICATED
|
||||||
|
|
||||||
Then("에러 응답.") {
|
Then("에러 응답을 받는다.") {
|
||||||
every {
|
every {
|
||||||
themeRepository.existsByName(request.name)
|
themeRepository.existsByName(request.name)
|
||||||
} returns true
|
} returns true
|
||||||
|
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code") { value(expectedError.errorCode) }
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
@ -142,16 +143,16 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val request = ThemeCreateRequest(
|
val request = ThemeCreateRequest(
|
||||||
name = "theme1",
|
name = "theme1",
|
||||||
description = "description1",
|
description = "description1",
|
||||||
thumbnail = "http://example.com/thumbnail1.jpg"
|
thumbnail = "http://example.com/thumbnail1.jpg"
|
||||||
)
|
)
|
||||||
|
|
||||||
fun runTest(request: ThemeCreateRequest) {
|
fun runTest(request: ThemeCreateRequest) {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { isBadRequest() }
|
status { isBadRequest() }
|
||||||
}
|
}
|
||||||
@ -192,26 +193,26 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
loginAsAdmin()
|
loginAsAdmin()
|
||||||
|
|
||||||
val theme = ThemeFixture.create(
|
val theme = ThemeFixture.create(
|
||||||
id = 1,
|
id = 1,
|
||||||
name = request.name,
|
name = request.name,
|
||||||
description = request.description,
|
description = request.description,
|
||||||
thumbnail = request.thumbnail
|
thumbnail = request.thumbnail
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every {
|
||||||
themeService.createTheme(request)
|
themeService.createTheme(request)
|
||||||
} returns ThemeRetrieveResponse(
|
} returns ThemeRetrieveResponse(
|
||||||
id = theme.id!!,
|
id = theme.id!!,
|
||||||
name = theme.name,
|
name = theme.name,
|
||||||
description = theme.description,
|
description = theme.description,
|
||||||
thumbnail = theme.thumbnail
|
thumbnail = theme.thumbnail
|
||||||
)
|
)
|
||||||
|
|
||||||
Then("201 응답을 받는다.") {
|
Then("201 응답을 받는다.") {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { isCreated() }
|
status { isCreated() }
|
||||||
header {
|
header {
|
||||||
@ -232,28 +233,28 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
|
|
||||||
When("로그인 상태가 아니라면") {
|
When("로그인 상태가 아니라면") {
|
||||||
doNotLogin()
|
doNotLogin()
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.INVALID_TOKEN
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header {
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
string("Location", "/login")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
When("관리자가 아닌 회원은") {
|
When("관리자가 아닌 회원은") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
Then("로그인 페이지로 이동한다.") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code") { value(AuthErrorCode.ACCESS_DENIED.errorCode) }
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,14 +263,14 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
loginAsAdmin()
|
loginAsAdmin()
|
||||||
val expectedError = ThemeErrorCode.THEME_ALREADY_RESERVED
|
val expectedError = ThemeErrorCode.THEME_ALREADY_RESERVED
|
||||||
|
|
||||||
Then("에러 응답") {
|
Then("에러 응답을 받는다.") {
|
||||||
every {
|
every {
|
||||||
themeRepository.isReservedTheme(themeId)
|
themeRepository.isReservedTheme(themeId)
|
||||||
} returns true
|
} returns true
|
||||||
|
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
jsonPath("$.code") { value(expectedError.errorCode) }
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
@ -290,8 +291,8 @@ class ThemeControllerTest(mockMvc: MockMvc) : RoomescapeApiTest() {
|
|||||||
|
|
||||||
Then("204 응답을 받는다.") {
|
Then("204 응답을 받는다.") {
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isNoContent() }
|
status { isNoContent() }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import io.kotest.assertions.assertSoftly
|
|||||||
import io.kotest.matchers.collections.shouldHaveSize
|
import io.kotest.matchers.collections.shouldHaveSize
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
import roomescape.common.config.JacksonConfig
|
import roomescape.common.config.JacksonConfig
|
||||||
import roomescape.reservation.infrastructure.persistence.ReservationRepository
|
import roomescape.reservation.infrastructure.persistence.ReservationRepository
|
||||||
import roomescape.time.business.TimeService
|
import roomescape.time.business.TimeService
|
||||||
@ -27,7 +29,7 @@ import java.time.LocalTime
|
|||||||
@WebMvcTest(TimeController::class)
|
@WebMvcTest(TimeController::class)
|
||||||
@Import(JacksonConfig::class)
|
@Import(JacksonConfig::class)
|
||||||
class TimeControllerTest(
|
class TimeControllerTest(
|
||||||
val mockMvc: MockMvc,
|
val mockMvc: MockMvc,
|
||||||
) : RoomescapeApiTest() {
|
) : RoomescapeApiTest() {
|
||||||
|
|
||||||
@SpykBean
|
@SpykBean
|
||||||
@ -52,13 +54,13 @@ class TimeControllerTest(
|
|||||||
every {
|
every {
|
||||||
timeRepository.findAll()
|
timeRepository.findAll()
|
||||||
} returns listOf(
|
} returns listOf(
|
||||||
TimeFixture.create(id = 1L),
|
TimeFixture.create(id = 1L),
|
||||||
TimeFixture.create(id = 2L)
|
TimeFixture.create(id = 2L)
|
||||||
)
|
)
|
||||||
|
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
content {
|
content {
|
||||||
@ -72,14 +74,19 @@ class TimeControllerTest(
|
|||||||
|
|
||||||
When("관리자가 아닌 경우") {
|
When("관리자가 아닌 경우") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Then("로그인 페이지로 이동") {
|
Then("에러 응답을 받는다.") {
|
||||||
runGetTest(
|
runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header { string("Location", "/login") }
|
}.andExpect {
|
||||||
|
content {
|
||||||
|
contentType(MediaType.APPLICATION_JSON)
|
||||||
|
jsonPath("$.code") { value(expectedError.errorCode) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,13 +104,13 @@ class TimeControllerTest(
|
|||||||
|
|
||||||
Then("시간 형식이 HH:mm이 아니거나, 범위를 벗어나면 400 응답") {
|
Then("시간 형식이 HH:mm이 아니거나, 범위를 벗어나면 400 응답") {
|
||||||
listOf(
|
listOf(
|
||||||
"{\"startAt\": \"23:30:30\"}",
|
"{\"startAt\": \"23:30:30\"}",
|
||||||
"{\"startAt\": \"24:59\"}",
|
"{\"startAt\": \"24:59\"}",
|
||||||
).forEach {
|
).forEach {
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = it,
|
body = it,
|
||||||
) {
|
) {
|
||||||
status { isBadRequest() }
|
status { isBadRequest() }
|
||||||
}
|
}
|
||||||
@ -116,9 +123,9 @@ class TimeControllerTest(
|
|||||||
} returns TimeCreateResponse(id = 1, startAt = time)
|
} returns TimeCreateResponse(id = 1, startAt = time)
|
||||||
|
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { isCreated() }
|
status { isCreated() }
|
||||||
content {
|
content {
|
||||||
@ -136,9 +143,9 @@ class TimeControllerTest(
|
|||||||
} returns true
|
} returns true
|
||||||
|
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = request,
|
body = request,
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
content {
|
content {
|
||||||
@ -152,14 +159,15 @@ class TimeControllerTest(
|
|||||||
When("관리자가 아닌 경우") {
|
When("관리자가 아닌 경우") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
|
|
||||||
Then("로그인 페이지로 이동") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
runPostTest(
|
runPostTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
body = TimeFixture.create(),
|
body = TimeFixture.create(),
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header { string("Location", "/login") }
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,8 +187,8 @@ class TimeControllerTest(
|
|||||||
} returns Unit
|
} returns Unit
|
||||||
|
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { isNoContent() }
|
status { isNoContent() }
|
||||||
}
|
}
|
||||||
@ -194,8 +202,8 @@ class TimeControllerTest(
|
|||||||
} returns null
|
} returns null
|
||||||
|
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = "/times/$id",
|
endpoint = "/times/$id",
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
content {
|
content {
|
||||||
@ -217,8 +225,8 @@ class TimeControllerTest(
|
|||||||
} returns listOf(ReservationFixture.create())
|
} returns listOf(ReservationFixture.create())
|
||||||
|
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = "/times/$id",
|
endpoint = "/times/$id",
|
||||||
) {
|
) {
|
||||||
status { isEqualTo(expectedError.httpStatus.value()) }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
content {
|
content {
|
||||||
@ -232,13 +240,14 @@ class TimeControllerTest(
|
|||||||
When("관리자가 아닌 경우") {
|
When("관리자가 아닌 경우") {
|
||||||
loginAsUser()
|
loginAsUser()
|
||||||
|
|
||||||
Then("로그인 페이지로 이동") {
|
Then("에러 응답을 받는다.") {
|
||||||
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
runDeleteTest(
|
runDeleteTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = endpoint,
|
endpoint = endpoint,
|
||||||
) {
|
) {
|
||||||
status { is3xxRedirection() }
|
status { isEqualTo(expectedError.httpStatus.value()) }
|
||||||
header { string("Location", "/login") }
|
jsonPath("$.code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,8 +261,8 @@ class TimeControllerTest(
|
|||||||
|
|
||||||
When("저장된 예약 시간이 있으면") {
|
When("저장된 예약 시간이 있으면") {
|
||||||
val times: List<TimeEntity> = listOf(
|
val times: List<TimeEntity> = listOf(
|
||||||
TimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)),
|
TimeFixture.create(id = 1L, startAt = LocalTime.of(10, 0)),
|
||||||
TimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0))
|
TimeFixture.create(id = 2L, startAt = LocalTime.of(11, 0))
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every {
|
||||||
@ -265,17 +274,17 @@ class TimeControllerTest(
|
|||||||
every {
|
every {
|
||||||
reservationRepository.findByDateAndThemeId(date, themeId)
|
reservationRepository.findByDateAndThemeId(date, themeId)
|
||||||
} returns listOf(
|
} returns listOf(
|
||||||
ReservationFixture.create(
|
ReservationFixture.create(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
date = date,
|
date = date,
|
||||||
theme = ThemeFixture.create(id = themeId),
|
theme = ThemeFixture.create(id = themeId),
|
||||||
time = times[0]
|
time = times[0]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val response = runGetTest(
|
val response = runGetTest(
|
||||||
mockMvc = mockMvc,
|
mockMvc = mockMvc,
|
||||||
endpoint = "/times/search?date=$date&themeId=$themeId",
|
endpoint = "/times/search?date=$date&themeId=$themeId",
|
||||||
) {
|
) {
|
||||||
status { isOk() }
|
status { isOk() }
|
||||||
content {
|
content {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user