diff --git a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt b/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt index 59b06fe9..ae156ecb 100644 --- a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt +++ b/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt @@ -1,6 +1,7 @@ package roomescape.reservation import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod @@ -9,7 +10,6 @@ import roomescape.auth.exception.AuthErrorCode import roomescape.common.config.next import roomescape.common.exception.CommonErrorCode import roomescape.common.util.DateUtils -import roomescape.user.infrastructure.persistence.UserEntity import roomescape.payment.infrastructure.common.BankCode import roomescape.payment.infrastructure.common.CardIssuerCode import roomescape.payment.infrastructure.common.EasyPayCompanyCode @@ -21,6 +21,7 @@ import roomescape.reservation.infrastructure.persistence.ReservationRepository import roomescape.reservation.infrastructure.persistence.ReservationStatus import roomescape.reservation.web.MostReservedThemeIdListResponse import roomescape.reservation.web.ReservationCancelRequest +import roomescape.reservation.web.ReservationSummaryResponse import roomescape.schedule.infrastructure.persistence.ScheduleEntity import roomescape.schedule.infrastructure.persistence.ScheduleRepository import roomescape.schedule.infrastructure.persistence.ScheduleStatus @@ -28,6 +29,7 @@ import roomescape.supports.* import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeRepository import roomescape.theme.web.toEntity +import roomescape.user.infrastructure.persistence.UserEntity import java.time.LocalDate import java.time.LocalTime @@ -55,7 +57,7 @@ class ReservationApiTest( test("관리자") { runExceptionTest( - token = testAuthUtil.defaultHqAdminLogin(), + token = testAuthUtil.defaultHqAdminLogin().second, method = HttpMethod.POST, endpoint = endpoint, expectedErrorCode = AuthErrorCode.ACCESS_DENIED @@ -66,13 +68,12 @@ class ReservationApiTest( test("정상 생성") { val schedule: ScheduleEntity = dummyInitializer.createSchedule( - adminToken = testAuthUtil.defaultHqAdminLogin(), request = ScheduleFixture.createRequest, status = ScheduleStatus.HOLD ) runTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, using = { body(commonRequest.copy(scheduleId = schedule.id)) }, @@ -84,8 +85,7 @@ class ReservationApiTest( } ).also { val reservation: ReservationEntity = - reservationRepository.findByIdOrNull(it.extract().path("data.id")) - ?: throw AssertionError("Unexpected Exception Occurred.") + reservationRepository.findByIdOrNull(it.extract().path("data.id"))!! reservation.status shouldBe ReservationStatus.PENDING reservation.scheduleId shouldBe schedule.id @@ -94,14 +94,10 @@ class ReservationApiTest( } test("예약을 생성할 때 해당 일정이 ${ScheduleStatus.HOLD} 상태가 아니면 실패한다.") { - val schedule: ScheduleEntity = dummyInitializer.createSchedule( - adminToken = testAuthUtil.defaultHqAdminLogin(), - request = ScheduleFixture.createRequest, - status = ScheduleStatus.AVAILABLE - ) + val schedule: ScheduleEntity = dummyInitializer.createSchedule(status = ScheduleStatus.AVAILABLE) runTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, using = { body(commonRequest.copy(scheduleId = schedule.id)) }, @@ -116,22 +112,16 @@ class ReservationApiTest( } test("예약 인원이 테마의 최소 인원보다 작거나 최대 인원보다 많으면 실패한다.") { - val adminToken = testAuthUtil.defaultHqAdminLogin() - val theme: ThemeEntity = dummyInitializer.createTheme( - adminToken = adminToken, - request = ThemeFixture.createRequest - ) - + val theme: ThemeEntity = dummyInitializer.createTheme() val schedule: ScheduleEntity = dummyInitializer.createSchedule( - adminToken = adminToken, request = ScheduleFixture.createRequest.copy(themeId = theme.id), status = ScheduleStatus.HOLD ) - val userToken = testAuthUtil.defaultUserLogin() + val token = testAuthUtil.defaultUserLogin().second runExceptionTest( - token = userToken, + token = token, method = HttpMethod.POST, endpoint = endpoint, requestBody = commonRequest.copy( @@ -142,7 +132,7 @@ class ReservationApiTest( ) runExceptionTest( - token = userToken, + token = token, method = HttpMethod.POST, endpoint = endpoint, requestBody = commonRequest.copy( @@ -156,7 +146,7 @@ class ReservationApiTest( context("필수 입력값이 입력되지 않으면 실패한다.") { test("예약자명") { runExceptionTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, method = HttpMethod.POST, endpoint = endpoint, requestBody = commonRequest.copy(reserverName = ""), @@ -166,7 +156,7 @@ class ReservationApiTest( test("예약자 연락처") { runExceptionTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, method = HttpMethod.POST, endpoint = endpoint, requestBody = commonRequest.copy(reserverContact = ""), @@ -190,7 +180,7 @@ class ReservationApiTest( test("관리자") { runExceptionTest( - token = testAuthUtil.defaultHqAdminLogin(), + token = testAuthUtil.defaultHqAdminLogin().second, method = HttpMethod.POST, endpoint = endpoint, expectedErrorCode = AuthErrorCode.ACCESS_DENIED @@ -199,15 +189,11 @@ class ReservationApiTest( } test("정상 응답") { - val userToken = testAuthUtil.defaultUserLogin() - - val reservation: ReservationEntity = dummyInitializer.createPendingReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = userToken, - ) + val (user, token) = testAuthUtil.defaultUserLogin() + val reservation: ReservationEntity = dummyInitializer.createPendingReservation(user = user) runTest( - token = userToken, + token = token, on = { post("/reservations/${reservation.id}/confirm") }, @@ -215,11 +201,8 @@ class ReservationApiTest( statusCode(HttpStatus.OK.value()) } ).also { - val updatedReservation = reservationRepository.findByIdOrNull(reservation.id) - ?: throw AssertionError("Unexpected Exception Occurred.") - - val updatedSchedule = scheduleRepository.findByIdOrNull(updatedReservation.scheduleId) - ?: throw AssertionError("Unexpected Exception Occurred.") + val updatedReservation = reservationRepository.findByIdOrNull(reservation.id)!! + val updatedSchedule = scheduleRepository.findByIdOrNull(updatedReservation.scheduleId)!! updatedSchedule.status shouldBe ScheduleStatus.RESERVED updatedReservation.status shouldBe ReservationStatus.CONFIRMED @@ -228,7 +211,7 @@ class ReservationApiTest( test("예약이 없으면 실패한다.") { runExceptionTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, method = HttpMethod.POST, endpoint = "/reservations/$INVALID_PK/confirm", expectedErrorCode = ReservationErrorCode.RESERVATION_NOT_FOUND @@ -250,7 +233,7 @@ class ReservationApiTest( test("관리자") { runExceptionTest( - token = testAuthUtil.defaultHqAdminLogin(), + token = testAuthUtil.defaultHqAdminLogin().second, method = HttpMethod.POST, endpoint = endpoint, expectedErrorCode = AuthErrorCode.ACCESS_DENIED @@ -259,15 +242,12 @@ class ReservationApiTest( } test("정상 응답") { - val userToken = testAuthUtil.defaultUserLogin() + val (user, token) = testAuthUtil.defaultUserLogin() - val reservation: ReservationEntity = dummyInitializer.createConfirmReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = userToken, - ) + val reservation: ReservationEntity = dummyInitializer.createConfirmReservation(user = user) runTest( - token = userToken, + token = token, using = { body(ReservationCancelRequest(cancelReason = "test")) }, @@ -278,10 +258,8 @@ class ReservationApiTest( statusCode(HttpStatus.OK.value()) } ).also { - val updatedReservation = reservationRepository.findByIdOrNull(reservation.id) - ?: throw AssertionError("Unexpected Exception Occurred.") - val updatedSchedule = scheduleRepository.findByIdOrNull(updatedReservation.scheduleId) - ?: throw AssertionError("Unexpected Exception Occurred.") + val updatedReservation = reservationRepository.findByIdOrNull(reservation.id)!! + val updatedSchedule = scheduleRepository.findByIdOrNull(updatedReservation.scheduleId)!! updatedReservation.status shouldBe ReservationStatus.CANCELED updatedSchedule.status shouldBe ScheduleStatus.AVAILABLE @@ -291,7 +269,7 @@ class ReservationApiTest( test("예약이 없으면 실패한다.") { runExceptionTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, method = HttpMethod.POST, endpoint = "/reservations/$INVALID_PK/cancel", requestBody = ReservationCancelRequest(cancelReason = "test"), @@ -300,13 +278,13 @@ class ReservationApiTest( } test("다른 회원의 예약을 취소할 수 없다.") { - val reservation: ReservationEntity = dummyInitializer.createConfirmReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = testAuthUtil.defaultUserLogin(), - ) + val (user, token) = testAuthUtil.defaultUserLogin() - val otherUserToken = + val reservation: ReservationEntity = dummyInitializer.createConfirmReservation(user = user) + + val (otherUser, otherUserToken) = testAuthUtil.userLogin(UserFixture.createUser(email = "test@test.com", phone = "01011111111")) + .also { it.first.email shouldNotBe user.email } runExceptionTest( token = otherUserToken, @@ -332,7 +310,7 @@ class ReservationApiTest( test("관리자") { runExceptionTest( - token = testAuthUtil.defaultHqAdminLogin(), + token = testAuthUtil.defaultHqAdminLogin().second, method = HttpMethod.POST, endpoint = endpoint, expectedErrorCode = AuthErrorCode.ACCESS_DENIED @@ -341,32 +319,22 @@ class ReservationApiTest( } test("정상 응답") { - val userToken = testAuthUtil.defaultUserLogin() - val adminToken = testAuthUtil.defaultHqAdminLogin() + val (user, userToken) = testAuthUtil.defaultUserLogin() - for (i in 1..3) { - dummyInitializer.createConfirmReservation( - adminToken = adminToken, - reserverToken = userToken, - themeRequest = ThemeFixture.createRequest.copy(name = "theme-$i"), - scheduleRequest = ScheduleFixture.createRequest.copy( - date = LocalDate.now().plusDays(i.toLong()), - time = LocalTime.now().plusHours(i.toLong()) + initialize("테스트를 위한 3개의 ${ReservationStatus.CONFIRMED} 예약과 1개의 ${ReservationStatus.PENDING} 예약 생성") { + (1..3).forEach { i -> + dummyInitializer.createConfirmReservation( + user = user, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = LocalDate.now().plusDays(i.toLong()), + time = LocalTime.now().plusHours(i.toLong()) + ) ) - ) + }.also { + dummyInitializer.createPendingReservation(user = user) + } } - // PENDING 예약은 조회되지 않음. - dummyInitializer.createPendingReservation( - adminToken = adminToken, - reserverToken = userToken, - themeRequest = ThemeFixture.createRequest.copy(name = "theme-$4"), - scheduleRequest = ScheduleFixture.createRequest.copy( - date = LocalDate.now().plusDays(1), - time = LocalTime.now() - ) - ) - runTest( token = userToken, on = { @@ -380,7 +348,13 @@ class ReservationApiTest( propsNameIfList = "reservations" ) } - ) + ).also { response -> + ResponseParser.parseListResponse( + response.extract().path("data.reservations") + ).forEach { + it.status shouldBe ReservationStatus.CONFIRMED + } + } } } @@ -398,7 +372,7 @@ class ReservationApiTest( test("관리자") { runExceptionTest( - token = testAuthUtil.defaultHqAdminLogin(), + token = testAuthUtil.defaultHqAdminLogin().second, method = HttpMethod.POST, endpoint = endpoint, expectedErrorCode = AuthErrorCode.ACCESS_DENIED @@ -412,10 +386,8 @@ class ReservationApiTest( lateinit var reservation: ReservationEntity beforeTest { - reservation = dummyInitializer.createConfirmReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = testAuthUtil.defaultUserLogin(), - ) + val user = testAuthUtil.defaultUserLogin().first + reservation = dummyInitializer.createConfirmReservation(user = user) } test("카드 결제") { @@ -547,7 +519,7 @@ class ReservationApiTest( test("예약이 없으면 실패한다.") { runExceptionTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, method = HttpMethod.GET, endpoint = "/reservations/$INVALID_PK/detail", expectedErrorCode = ReservationErrorCode.RESERVATION_NOT_FOUND @@ -555,13 +527,12 @@ class ReservationApiTest( } test("예약은 있지만, 결제 정보를 찾을 수 없으면 null로 지정한다.") { - val reservation = dummyInitializer.createConfirmReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = testAuthUtil.defaultUserLogin(), - ) + val (user, token) = testAuthUtil.defaultUserLogin() + + val reservation = dummyInitializer.createConfirmReservation(user = user) runTest( - token = testAuthUtil.defaultUserLogin(), + token = token, on = { get("/reservations/${reservation.id}/detail") }, @@ -573,10 +544,8 @@ class ReservationApiTest( } test("예약과 결제는 있지만, 결제 세부 내역이 없으면 세부 내역만 null로 지정한다..") { - val reservation = dummyInitializer.createConfirmReservation( - adminToken = testAuthUtil.defaultHqAdminLogin(), - reserverToken = testAuthUtil.defaultUserLogin(), - ) + val (user, token) = testAuthUtil.defaultUserLogin() + val reservation = dummyInitializer.createConfirmReservation(user = user) dummyInitializer.createPayment( reservationId = reservation.id, @@ -586,7 +555,7 @@ class ReservationApiTest( } runTest( - token = testAuthUtil.defaultUserLogin(), + token = token, on = { get("/reservations/${reservation.id}/detail") }, @@ -621,7 +590,7 @@ class ReservationApiTest( reservation: ReservationEntity ): LinkedHashMap { return runTest( - token = testAuthUtil.defaultUserLogin(), + token = testAuthUtil.defaultUserLogin().second, on = { get("/reservations/${reservation.id}/detail") }, @@ -639,87 +608,71 @@ class ReservationApiTest( val user: UserEntity = testAuthUtil.defaultUser() val themeIds: List = (1..5).map { - themeRepository.save( - ThemeFixture.createRequest.copy(name = "theme-$it").toEntity(id = tsidFactory.next()) - ).id + themeRepository.save(ThemeFixture.createRequest.copy().toEntity(id = tsidFactory.next())).id } + val store = dummyInitializer.createStore() + // 첫 번째 테마: 유효한 2개 예약 (1L..2L).forEach { - createScheduleAndReservation( - date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), - themeId = themeIds[0], - userId = user.id, + dummyInitializer.createConfirmReservation( + user = user, + storeId = store.id, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[0], + ) ) } // 두 번째 테마: 유효한 1개 예약 - createScheduleAndReservation( - date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()), - themeId = themeIds[1], - userId = user.id, + dummyInitializer.createConfirmReservation( + user = user, + storeId = store.id, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()), + themeId = themeIds[1], + ) ) // 세 번째 테마: 유효한 3개 예약 (1L..3L).forEach { - createScheduleAndReservation( - date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), - themeId = themeIds[2], - userId = user.id, + dummyInitializer.createConfirmReservation( + user = user, + storeId = store.id, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[2], + ) ) } // 네 번째 테마: Pending 상태인 3개 예약 -> 집계되지 않음. (1L..3L).forEach { - createScheduleAndReservation( - date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), - themeId = themeIds[3], - userId = user.id, - isPending = true + dummyInitializer.createPendingReservation( + user = user, + storeId = store.id, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[3], + ) ) } // 다섯 번째 테마: 이번주의 확정 예약 -> 집계되지 않음. (1L..3L).forEach { i -> val thisMonday = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(8) - createScheduleAndReservation( - date = thisMonday.plusDays(i), - themeId = themeIds[4], - userId = user.id, + dummyInitializer.createConfirmReservation( + user = user, + storeId = store.id, + scheduleRequest = ScheduleFixture.createRequest.copy( + date = thisMonday.plusDays(i), + themeId = themeIds[4], + ) ) } // 조회 예상 결과: 세번째, 첫번째, 두번째 테마 순서 return MostReservedThemeIdListResponse(listOf(themeIds[2], themeIds[0], themeIds[1])) } - - private fun createScheduleAndReservation( - date: LocalDate, - themeId: Long, - userId: Long, - isPending: Boolean = false - ) { - val schedule = ScheduleEntity( - id = tsidFactory.next(), - date = date, - time = LocalTime.now(), - themeId = themeId, - status = if (isPending) ScheduleStatus.HOLD else ScheduleStatus.RESERVED - ).also { - scheduleRepository.save(it) - } - - ReservationEntity( - id = tsidFactory.next(), - userId = userId, - scheduleId = schedule.id, - reserverName = "이상돌", - reserverContact = "01012345678", - participantCount = 4, - requirement = "잘부탁드려요!", - status = if (isPending) ReservationStatus.PENDING else ReservationStatus.CONFIRMED, - ).also { - reservationRepository.save(it) - } - } }