diff --git a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt b/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt index 626b54b5..ca8d073b 100644 --- a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt +++ b/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt @@ -6,7 +6,10 @@ import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod import org.springframework.http.HttpStatus import roomescape.auth.exception.AuthErrorCode +import roomescape.common.config.next import roomescape.common.exception.CommonErrorCode +import roomescape.common.util.DateUtils +import roomescape.member.infrastructure.persistence.UserEntity import roomescape.payment.exception.PaymentErrorCode import roomescape.payment.infrastructure.common.BankCode import roomescape.payment.infrastructure.common.CardIssuerCode @@ -17,18 +20,22 @@ import roomescape.reservation.infrastructure.persistence.CanceledReservationRepo import roomescape.reservation.infrastructure.persistence.ReservationEntity import roomescape.reservation.infrastructure.persistence.ReservationRepository import roomescape.reservation.infrastructure.persistence.ReservationStatus +import roomescape.reservation.web.MostReservedThemeIdListResponse import roomescape.reservation.web.ReservationCancelRequest import roomescape.schedule.infrastructure.persistence.ScheduleEntity import roomescape.schedule.infrastructure.persistence.ScheduleRepository import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.supports.* +import roomescape.theme.infrastructure.persistence.ThemeEntity +import roomescape.theme.infrastructure.persistence.ThemeRepository +import roomescape.theme.web.toEntity import java.time.LocalDate import java.time.LocalTime class ReservationApiTest( private val reservationRepository: ReservationRepository, private val canceledReservationRepository: CanceledReservationRepository, + private val themeRepository: ThemeRepository, private val scheduleRepository: ScheduleRepository, private val paymentDetailRepository: PaymentDetailRepository, ) : FunSpecSpringbootTest() { @@ -299,7 +306,8 @@ class ReservationApiTest( reserverToken = authUtil.defaultUserLogin(), ) - val otherUserToken = authUtil.userLogin(UserFixture.createUser(email = "test@test.com", phone="01011111111")) + val otherUserToken = + authUtil.userLogin(UserFixture.createUser(email = "test@test.com", phone = "01011111111")) runExceptionTest( token = otherUserToken, @@ -602,6 +610,24 @@ class ReservationApiTest( ) } } + + context("가장 많이 예약된 테마 ID를 조회한다.") { + test("정상 응답") { + val expectedResult: MostReservedThemeIdListResponse = initializeForPopularThemeTest() + + runTest( + on = { + get("/reservations/popular-themes?count=10") + }, + expect = { + statusCode(HttpStatus.OK.value()) + } + ).also { + val result: List = it.extract().path("data.themeIds") + result shouldBe expectedResult.themeIds + } + } + } } fun runDetailRetrieveTest( @@ -621,4 +647,92 @@ class ReservationApiTest( it.extract().path("data.user.id") shouldBe reservation.userId }.extract().path("data.payment") } + + private fun initializeForPopularThemeTest(): MostReservedThemeIdListResponse { + val user: UserEntity = authUtil.defaultUser() + + val themeIds: List = (1..5).map { + themeRepository.save( + ThemeFixture.createRequest.copy(name = "theme-$it").toEntity(id = tsidFactory.next()) + ).id + } + + // 첫 번째 테마: 유효한 2개 예약 + (1L..2L).forEach { + createScheduleAndReservation( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[0], + userId = user.id, + ) + } + + // 두 번째 테마: 유효한 1개 예약 + createScheduleAndReservation( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()), + themeId = themeIds[1], + userId = user.id, + ) + + // 세 번째 테마: 유효한 3개 예약 + (1L..3L).forEach { + createScheduleAndReservation( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[2], + userId = user.id, + ) + } + + // 네 번째 테마: Pending 상태인 3개 예약 -> 집계되지 않음. + (1L..3L).forEach { + createScheduleAndReservation( + date = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(it), + themeId = themeIds[3], + userId = user.id, + isPending = true + ) + } + + // 다섯 번째 테마: 이번주의 확정 예약 -> 집계되지 않음. + (1L..3L).forEach { i -> + val thisMonday = DateUtils.getSundayOfPreviousWeek(LocalDate.now()).plusDays(8) + createScheduleAndReservation( + date = thisMonday.plusDays(i), + themeId = themeIds[4], + userId = user.id, + ) + } + + // 조회 예상 결과: 세번째, 첫번째, 두번째 테마 순서 + 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) + } + } }