test: 예약 테스트에 새로 추가된 회원 및 인증 권한 테스트 추가

This commit is contained in:
이상진 2025-09-13 12:56:09 +09:00
parent 45039b8e7c
commit 97a84f1c61
2 changed files with 207 additions and 151 deletions

View File

@ -3,9 +3,10 @@ package roomescape.reservation
import io.kotest.matchers.shouldBe
import org.hamcrest.CoreMatchers.equalTo
import org.springframework.data.repository.findByIdOrNull
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import roomescape.auth.exception.AuthErrorCode
import roomescape.common.exception.CommonErrorCode
import roomescape.member.infrastructure.persistence.Role
import roomescape.payment.exception.PaymentErrorCode
import roomescape.payment.infrastructure.common.BankCode
import roomescape.payment.infrastructure.common.CardIssuerCode
@ -35,21 +36,42 @@ class ReservationApiTest(
init {
context("결제 전 임시 예약을 생성한다.") {
val commonRequest = ReservationFixture.pendingCreateRequest
val endpoint = "/reservations/pending"
context("권한이 없으면 접근할 수 없다.") {
test("비회원") {
runExceptionTest(
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("관리자") {
runExceptionTest(
token = authUtil.defaultAdminLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 생성") {
val schedule: ScheduleEntity = dummyInitializer.createSchedule(
adminToken = authUtil.loginAsAdmin(),
adminToken = authUtil.defaultAdminLogin(),
request = ScheduleFixture.createRequest,
status = ScheduleStatus.HOLD
)
runTest(
token = authUtil.loginAsUser(),
token = authUtil.defaultUserLogin(),
using = {
body(commonRequest.copy(scheduleId = schedule.id))
},
on = {
post("/reservations/pending")
post(endpoint)
},
expect = {
statusCode(HttpStatus.OK.value())
@ -67,18 +89,18 @@ class ReservationApiTest(
test("예약을 생성할 때 해당 일정이 ${ScheduleStatus.HOLD} 상태가 아니면 실패한다.") {
val schedule: ScheduleEntity = dummyInitializer.createSchedule(
adminToken = authUtil.loginAsAdmin(),
adminToken = authUtil.defaultAdminLogin(),
request = ScheduleFixture.createRequest,
status = ScheduleStatus.AVAILABLE
)
runTest(
token = authUtil.loginAsUser(),
token = authUtil.defaultUserLogin(),
using = {
body(commonRequest.copy(scheduleId = schedule.id))
},
on = {
post("/reservations/pending")
post(endpoint)
},
expect = {
statusCode(HttpStatus.BAD_REQUEST.value())
@ -88,7 +110,7 @@ class ReservationApiTest(
}
test("예약 인원이 테마의 최소 인원보다 작거나 최대 인원보다 많으면 실패한다.") {
val adminToken = authUtil.loginAsAdmin()
val adminToken = authUtil.defaultAdminLogin()
val theme: ThemeEntity = dummyInitializer.createTheme(
adminToken = adminToken,
request = ThemeFixture.createRequest
@ -100,86 +122,81 @@ class ReservationApiTest(
status = ScheduleStatus.HOLD
)
runTest(
token = authUtil.loginAsUser(),
using = {
body(
commonRequest.copy(
scheduleId = schedule.id,
val userToken = authUtil.defaultUserLogin()
runExceptionTest(
token = userToken,
method = HttpMethod.POST,
endpoint = endpoint,
requestBody = commonRequest.copy(
schedule.id,
participantCount = ((theme.minParticipants - 1).toShort())
)
)
},
on = {
post("/reservations/pending")
},
expect = {
statusCode(HttpStatus.BAD_REQUEST.value())
body("code", equalTo(ReservationErrorCode.INVALID_PARTICIPANT_COUNT.errorCode))
}
),
expectedErrorCode = ReservationErrorCode.INVALID_PARTICIPANT_COUNT
)
runTest(
token = authUtil.loginAsUser(),
using = {
body(
commonRequest.copy(
runExceptionTest(
token = userToken,
method = HttpMethod.POST,
endpoint = endpoint,
requestBody = commonRequest.copy(
scheduleId = schedule.id,
participantCount = ((theme.maxParticipants + 1).toShort())
)
)
},
on = {
post("/reservations/pending")
},
expect = {
statusCode(HttpStatus.BAD_REQUEST.value())
body("code", equalTo(ReservationErrorCode.INVALID_PARTICIPANT_COUNT.errorCode))
}
),
expectedErrorCode = ReservationErrorCode.INVALID_PARTICIPANT_COUNT
)
}
context("필수 입력값이 입력되지 않으면 실패한다.") {
test("예약자명") {
runTest(
token = authUtil.loginAsUser(),
using = {
body(commonRequest.copy(reserverName = ""))
},
on = {
post("/reservations/pending")
},
expect = {
statusCode(HttpStatus.BAD_REQUEST.value())
body("code", equalTo(CommonErrorCode.INVALID_INPUT_VALUE.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
requestBody = commonRequest.copy(reserverName = ""),
expectedErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
)
}
test("예약자 연락처") {
runTest(
token = authUtil.loginAsUser(),
using = {
body(commonRequest.copy(reserverContact = ""))
},
on = {
post("/reservations/pending")
},
expect = {
statusCode(HttpStatus.BAD_REQUEST.value())
body("code", equalTo(CommonErrorCode.INVALID_INPUT_VALUE.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
requestBody = commonRequest.copy(reserverContact = ""),
expectedErrorCode = CommonErrorCode.INVALID_INPUT_VALUE
)
}
}
}
context("예약을 확정한다.") {
context("권한이 없으면 접근할 수 없다.") {
val endpoint = "/reservations/$INVALID_PK/confirm"
test("비회원") {
runExceptionTest(
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("관리자") {
runExceptionTest(
token = authUtil.defaultAdminLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 응답") {
val userToken = authUtil.loginAsUser()
val userToken = authUtil.defaultUserLogin()
val reservation: ReservationEntity = dummyInitializer.createPendingReservation(
adminToken = authUtil.loginAsAdmin(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = userToken,
)
@ -204,25 +221,42 @@ class ReservationApiTest(
}
test("예약이 없으면 실패한다.") {
runTest(
token = authUtil.loginAsUser(),
on = {
post("/reservations/$INVALID_PK/confirm")
},
expect = {
statusCode(HttpStatus.NOT_FOUND.value())
body("code", equalTo(ReservationErrorCode.RESERVATION_NOT_FOUND.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.POST,
endpoint = "/reservations/$INVALID_PK/confirm",
expectedErrorCode = ReservationErrorCode.RESERVATION_NOT_FOUND
)
}
}
context("예약을 취소한다.") {
context("권한이 없으면 접근할 수 없다.") {
val endpoint = "/reservations/$INVALID_PK/confirm"
test("비회원") {
runExceptionTest(
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("관리자") {
runExceptionTest(
token = authUtil.defaultAdminLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 응답") {
val userToken = authUtil.loginAsUser()
val userToken = authUtil.defaultUserLogin()
val reservation: ReservationEntity = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = userToken,
)
@ -250,54 +284,42 @@ class ReservationApiTest(
}
test("예약이 없으면 실패한다.") {
runTest(
token = authUtil.loginAsUser(),
using = {
body(ReservationCancelRequest(cancelReason = "test"))
},
on = {
post("/reservations/$INVALID_PK/cancel")
},
expect = {
statusCode(HttpStatus.NOT_FOUND.value())
body("code", equalTo(ReservationErrorCode.RESERVATION_NOT_FOUND.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.POST,
endpoint = "/reservations/$INVALID_PK/cancel",
requestBody = ReservationCancelRequest(cancelReason = "test"),
expectedErrorCode = ReservationErrorCode.RESERVATION_NOT_FOUND
)
}
test("관리자가 아닌 회원은 다른 회원의 예약을 취소할 수 없다.") {
val reservation: ReservationEntity = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
reserverToken = authUtil.loginAsUser(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = authUtil.defaultUserLogin(),
)
val otherUserToken = authUtil.login("other@example.com", "other", role = Role.MEMBER)
val otherUserToken = authUtil.userLogin(UserFixture.createUser(email = "test@test.com", phone="01011111111"))
runTest(
runExceptionTest(
token = otherUserToken,
using = {
body(ReservationCancelRequest(cancelReason = "test"))
},
on = {
post("/reservations/${reservation.id}/cancel")
},
expect = {
statusCode(HttpStatus.FORBIDDEN.value())
body("code", equalTo(ReservationErrorCode.NO_PERMISSION_TO_CANCEL_RESERVATION.errorCode))
}
method = HttpMethod.POST,
endpoint = "/reservations/${reservation.id}/cancel",
requestBody = ReservationCancelRequest(cancelReason = "test"),
expectedErrorCode = ReservationErrorCode.NO_PERMISSION_TO_CANCEL_RESERVATION
)
}
test("관리자는 다른 회원의 예약을 취소할 수 있다.") {
val adminToken = authUtil.defaultAdminLogin()
val reservation: ReservationEntity = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
reserverToken = authUtil.loginAsAdmin(),
adminToken = adminToken,
reserverToken = authUtil.defaultUserLogin(),
)
val otherAdminToken = authUtil.login("admin1@example.com", "admin1", role = Role.ADMIN)
runTest(
token = otherAdminToken,
token = adminToken,
using = {
body(ReservationCancelRequest(cancelReason = "test"))
},
@ -321,9 +343,30 @@ class ReservationApiTest(
}
context("나의 예약 목록을 조회한다.") {
context("권한이 없으면 접근할 수 없다.") {
val endpoint = "/reservations/$INVALID_PK/confirm"
test("비회원") {
runExceptionTest(
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("관리자") {
runExceptionTest(
token = authUtil.defaultAdminLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
test("정상 응답") {
val userToken = authUtil.loginAsUser()
val adminToken = authUtil.loginAsAdmin()
val userToken = authUtil.defaultUserLogin()
val adminToken = authUtil.defaultAdminLogin()
for (i in 1..3) {
dummyInitializer.createConfirmReservation(
@ -355,6 +398,27 @@ class ReservationApiTest(
}
context("예약 상세 정보를 조회한다.") {
context("권한이 없으면 접근할 수 없다.") {
val endpoint = "/reservations/$INVALID_PK/confirm"
test("비회원") {
runExceptionTest(
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.TOKEN_NOT_FOUND
)
}
test("관리자") {
runExceptionTest(
token = authUtil.defaultAdminLogin(),
method = HttpMethod.POST,
endpoint = endpoint,
expectedErrorCode = AuthErrorCode.ACCESS_DENIED
)
}
}
context("정상 응답") {
val commonPaymentRequest = PaymentFixture.confirmRequest
@ -362,8 +426,8 @@ class ReservationApiTest(
beforeTest {
reservation = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
reserverToken = authUtil.loginAsUser(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = authUtil.defaultUserLogin(),
)
}
@ -428,10 +492,11 @@ class ReservationApiTest(
)
val cancelReason = "테스트입니다."
val memberId = authUtil.getUser().id!!
val user = authUtil.defaultUser()
dummyInitializer.cancelPayment(
memberId = memberId,
userId = user.id,
reservationId = reservation.id,
cancelReason = cancelReason,
)
@ -448,7 +513,7 @@ class ReservationApiTest(
with((it.get("cancel") as LinkedHashMap<*, *>)) {
this["cancelReason"] shouldBe cancelReason
this["canceledBy"] shouldBe memberId
this["canceledBy"] shouldBe user.id
}
}
}
@ -494,40 +559,32 @@ class ReservationApiTest(
}
test("예약이 없으면 실패한다.") {
runTest(
token = authUtil.loginAsUser(),
on = {
get("/reservations/$INVALID_PK/detail")
},
expect = {
statusCode(HttpStatus.NOT_FOUND.value())
body("code", equalTo(ReservationErrorCode.RESERVATION_NOT_FOUND.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.GET,
endpoint = "/reservations/$INVALID_PK/detail",
expectedErrorCode = ReservationErrorCode.RESERVATION_NOT_FOUND
)
}
test("예약은 있지만, 결제 정보가 없으면 실패한다.") {
val reservation = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
reserverToken = authUtil.loginAsUser(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = authUtil.defaultUserLogin(),
)
runTest(
token = authUtil.loginAsUser(),
on = {
get("/reservations/${reservation.id}/detail")
},
expect = {
statusCode(HttpStatus.NOT_FOUND.value())
body("code", equalTo(PaymentErrorCode.PAYMENT_NOT_FOUND.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.GET,
endpoint = "/reservations/${reservation.id}/detail",
expectedErrorCode = PaymentErrorCode.PAYMENT_NOT_FOUND
)
}
test("예약과 결제는 있지만, 결제 세부 내역이 없으면 실패한다.") {
val reservation = dummyInitializer.createConfirmReservation(
adminToken = authUtil.loginAsAdmin(),
reserverToken = authUtil.loginAsUser(),
adminToken = authUtil.defaultAdminLogin(),
reserverToken = authUtil.defaultUserLogin(),
)
dummyInitializer.createPayment(
@ -537,15 +594,11 @@ class ReservationApiTest(
paymentDetailRepository.deleteAll()
}
runTest(
token = authUtil.loginAsUser(),
on = {
get("/reservations/${reservation.id}/detail")
},
expect = {
statusCode(HttpStatus.NOT_FOUND.value())
body("code", equalTo(PaymentErrorCode.PAYMENT_DETAIL_NOT_FOUND.errorCode))
}
runExceptionTest(
token = authUtil.defaultUserLogin(),
method = HttpMethod.GET,
endpoint = "/reservations/${reservation.id}/detail",
expectedErrorCode = PaymentErrorCode.PAYMENT_DETAIL_NOT_FOUND
)
}
}
@ -555,17 +608,17 @@ class ReservationApiTest(
reservation: ReservationEntity
): LinkedHashMap<String, Any> {
return runTest(
token = authUtil.loginAsUser(),
token = authUtil.defaultUserLogin(),
on = {
get("/reservations/${reservation.id}/detail")
},
expect = {
statusCode(HttpStatus.OK.value())
assertProperties(props = setOf("id", "member", "applicationDateTime", "payment"))
assertProperties(props = setOf("id", "user", "applicationDateTime", "payment"))
}
).also {
it.extract().path<Long>("data.id") shouldBe reservation.id
it.extract().path<Long>("data.member.id") shouldBe reservation.memberId
it.extract().path<Long>("data.user.id") shouldBe reservation.userId
}.extract().path("data.payment")
}
}

View File

@ -123,6 +123,9 @@ class AuthUtil(
}
fun defaultUserLogin(): String = userLogin(UserFixture.default)
fun defaultUser(): UserEntity = userRepository.findByEmail(UserFixture.default.email)
?: throw AssertionError("Unexpected Exception Occurred.")
}
fun runTest(