generated from pricelees/issue-pr-template
286 lines
10 KiB
Kotlin
286 lines
10 KiB
Kotlin
package roomescape.reservation.business
|
|
|
|
import io.kotest.assertions.throwables.shouldThrow
|
|
import io.kotest.core.spec.style.FunSpec
|
|
import io.kotest.matchers.shouldBe
|
|
import io.mockk.every
|
|
import io.mockk.mockk
|
|
import org.springframework.data.repository.findByIdOrNull
|
|
import roomescape.member.business.MemberService
|
|
import roomescape.member.infrastructure.persistence.Role
|
|
import roomescape.reservation.exception.ReservationErrorCode
|
|
import roomescape.reservation.exception.ReservationException
|
|
import roomescape.reservation.infrastructure.persistence.ReservationRepository
|
|
import roomescape.reservation.infrastructure.persistence.ReservationStatus
|
|
import roomescape.theme.business.ThemeService
|
|
import roomescape.time.business.TimeService
|
|
import roomescape.util.MemberFixture
|
|
import roomescape.util.ReservationFixture
|
|
import roomescape.util.TimeFixture
|
|
import java.time.LocalDate
|
|
import java.time.LocalTime
|
|
|
|
class ReservationServiceTest : FunSpec({
|
|
|
|
val reservationRepository: ReservationRepository = mockk()
|
|
val timeService: TimeService = mockk()
|
|
val memberService: MemberService = mockk()
|
|
val themeService: ThemeService = mockk()
|
|
val reservationService = ReservationService(
|
|
reservationRepository,
|
|
timeService,
|
|
memberService,
|
|
themeService
|
|
)
|
|
|
|
context("예약을 추가할 때") {
|
|
test("이미 예약이 있으면 예외를 던진다.") {
|
|
every {
|
|
reservationRepository.exists(any())
|
|
} returns true
|
|
|
|
val reservationRequest = ReservationFixture.createRequest()
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.createConfirmedReservation(reservationRequest, 1L)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.RESERVATION_DUPLICATED
|
|
}
|
|
}
|
|
|
|
context("날짜, 시간이 잘못 입력되면 예외를 던진다.") {
|
|
every {
|
|
reservationRepository.exists(any())
|
|
} returns false
|
|
|
|
every {
|
|
themeService.findById(any())
|
|
} returns mockk()
|
|
|
|
every {
|
|
memberService.findById(any())
|
|
} returns mockk()
|
|
|
|
|
|
test("지난 날짜이면 예외를 던진다.") {
|
|
val reservationRequest = ReservationFixture.createRequest().copy(
|
|
date = LocalDate.now().minusDays(1)
|
|
)
|
|
|
|
every {
|
|
timeService.findById(any())
|
|
} returns TimeFixture.create()
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.createConfirmedReservation(reservationRequest, 1L)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.PAST_REQUEST_DATETIME
|
|
}
|
|
}
|
|
|
|
test("지난 시간이면 예외를 던진다.") {
|
|
val reservationRequest = ReservationFixture.createRequest().copy(
|
|
date = LocalDate.now(),
|
|
)
|
|
|
|
every {
|
|
timeService.findById(reservationRequest.timeId)
|
|
} returns TimeFixture.create(
|
|
startAt = LocalTime.now().minusMinutes(1)
|
|
)
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.createConfirmedReservation(reservationRequest, 1L)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.PAST_REQUEST_DATETIME
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
context("예약 대기를 걸 때") {
|
|
test("이미 예약한 회원이 같은 날짜와 테마로 대기를 걸면 예외를 던진다.") {
|
|
val reservationRequest = ReservationFixture.createRequest().copy(
|
|
date = LocalDate.now(),
|
|
themeId = 1L,
|
|
timeId = 1L,
|
|
)
|
|
|
|
every {
|
|
reservationRepository.exists(any())
|
|
} returns true
|
|
|
|
shouldThrow<ReservationException> {
|
|
val waitingRequest = ReservationFixture.createWaitingRequest(
|
|
date = reservationRequest.date,
|
|
themeId = reservationRequest.themeId,
|
|
timeId = reservationRequest.timeId
|
|
)
|
|
reservationService.createWaiting(waitingRequest, 1L)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.ALREADY_RESERVE
|
|
}
|
|
}
|
|
}
|
|
|
|
context("예약 대기를 취소할 때") {
|
|
val reservationId = 1L
|
|
val member = MemberFixture.create(id = 1L, role = Role.MEMBER)
|
|
test("예약을 찾을 수 없으면 예외를 던진다.") {
|
|
every {
|
|
reservationRepository.findByIdOrNull(reservationId)
|
|
} returns null
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.deleteWaiting(reservationId, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.RESERVATION_NOT_FOUND
|
|
}
|
|
}
|
|
|
|
test("대기중인 해당 예약이 이미 확정된 상태라면 예외를 던진다.") {
|
|
val alreadyConfirmed = ReservationFixture.create(
|
|
id = reservationId,
|
|
status = ReservationStatus.CONFIRMED
|
|
)
|
|
every {
|
|
reservationRepository.findByIdOrNull(reservationId)
|
|
} returns alreadyConfirmed
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.deleteWaiting(reservationId, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.ALREADY_CONFIRMED
|
|
}
|
|
}
|
|
|
|
test("타인의 대기를 취소하려고 하면 예외를 던진다.") {
|
|
val otherMembersWaiting = ReservationFixture.create(
|
|
id = reservationId,
|
|
member = MemberFixture.create(id = member.id!! + 1L),
|
|
status = ReservationStatus.WAITING
|
|
)
|
|
|
|
every {
|
|
reservationRepository.findByIdOrNull(reservationId)
|
|
} returns otherMembersWaiting
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.deleteWaiting(reservationId, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.NOT_RESERVATION_OWNER
|
|
}
|
|
}
|
|
}
|
|
|
|
context("예약을 조회할 때") {
|
|
test("종료 날짜가 시작 날짜보다 이전이면 예외를 던진다.") {
|
|
val startFrom = LocalDate.now()
|
|
val endAt = startFrom.minusDays(1)
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.searchReservations(
|
|
null,
|
|
null,
|
|
startFrom,
|
|
endAt
|
|
)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.INVALID_SEARCH_DATE_RANGE
|
|
}
|
|
}
|
|
}
|
|
|
|
context("대기중인 예약을 승인할 때") {
|
|
test("관리자가 아니면 예외를 던진다.") {
|
|
val member = MemberFixture.create(id = 1L, role = Role.MEMBER)
|
|
|
|
every {
|
|
memberService.findById(any())
|
|
} returns member
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.confirmWaiting(1L, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.NO_PERMISSION
|
|
}
|
|
}
|
|
|
|
test("이미 확정된 예약이 있으면 예외를 던진다.") {
|
|
val member = MemberFixture.create(id = 1L, role = Role.ADMIN)
|
|
val reservationId = 1L
|
|
|
|
every {
|
|
memberService.findById(any())
|
|
} returns member
|
|
|
|
every {
|
|
reservationRepository.isExistConfirmedReservation(reservationId)
|
|
} returns true
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.confirmWaiting(reservationId, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS
|
|
}
|
|
}
|
|
}
|
|
|
|
context("대기중인 예약을 거절할 때") {
|
|
test("관리자가 아니면 예외를 던진다.") {
|
|
val member = MemberFixture.create(id = 1L, role = Role.MEMBER)
|
|
|
|
every {
|
|
memberService.findById(any())
|
|
} returns member
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.rejectWaiting(1L, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.NO_PERMISSION
|
|
}
|
|
}
|
|
|
|
test("예약을 찾을 수 없으면 예외를 던진다.") {
|
|
val member = MemberFixture.create(id = 1L, role = Role.ADMIN)
|
|
val reservationId = 1L
|
|
|
|
every {
|
|
memberService.findById(member.id!!)
|
|
} returns member
|
|
|
|
every {
|
|
reservationRepository.findByIdOrNull(reservationId)
|
|
} returns null
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.rejectWaiting(reservationId, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.RESERVATION_NOT_FOUND
|
|
}
|
|
}
|
|
|
|
test("이미 확정된 예약이면 예외를 던진다.") {
|
|
val member = MemberFixture.create(id = 1L, role = Role.ADMIN)
|
|
val reservation = ReservationFixture.create(
|
|
id = 1L,
|
|
status = ReservationStatus.CONFIRMED
|
|
)
|
|
|
|
every {
|
|
memberService.findById(member.id!!)
|
|
} returns member
|
|
|
|
every {
|
|
reservationRepository.findByIdOrNull(reservation.id!!)
|
|
} returns reservation
|
|
|
|
shouldThrow<ReservationException> {
|
|
reservationService.rejectWaiting(reservation.id!!, member.id!!)
|
|
}.also {
|
|
it.errorCode shouldBe ReservationErrorCode.ALREADY_CONFIRMED
|
|
}
|
|
}
|
|
}
|
|
})
|