261 lines
11 KiB
Kotlin

package roomescape.reservation.implement
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 roomescape.member.exception.MemberErrorCode
import roomescape.member.exception.MemberException
import roomescape.member.implement.MemberFinder
import roomescape.reservation.exception.ReservationErrorCode
import roomescape.reservation.exception.ReservationException
import roomescape.reservation.infrastructure.persistence.ReservationEntity
import roomescape.reservation.infrastructure.persistence.ReservationRepository
import roomescape.reservation.infrastructure.persistence.ReservationStatus
import roomescape.theme.exception.ThemeErrorCode
import roomescape.theme.exception.ThemeException
import roomescape.theme.implement.ThemeFinder
import roomescape.time.exception.TimeErrorCode
import roomescape.time.exception.TimeException
import roomescape.time.implement.TimeFinder
import roomescape.util.MemberFixture
import roomescape.util.ThemeFixture
import roomescape.util.TimeFixture
import roomescape.util.TsidFactory
import java.time.LocalDate
import java.time.LocalTime
class ReservationWriterTest : FunSpec({
val reservationValidator: ReservationValidator = mockk()
val reservationRepository: ReservationRepository = mockk()
val memberFinder: MemberFinder = mockk()
val timeFinder: TimeFinder = mockk()
val themeFinder: ThemeFinder = mockk()
val reservationWriter = ReservationWriter(
reservationValidator, reservationRepository, memberFinder, timeFinder, themeFinder, TsidFactory
)
context("create") {
val today = LocalDate.now()
val timeId = 1L
val themeId = 1L
val memberId = 1L
val status = ReservationStatus.CONFIRMED
val requesterId = 1L
test("시간을 찾을 수 없으면 실패한다.") {
every {
timeFinder.findById(any())
} throws TimeException(TimeErrorCode.TIME_NOT_FOUND)
shouldThrow<TimeException> {
reservationWriter.create(today, timeId, themeId, memberId, status, requesterId)
}.also {
it.errorCode shouldBe TimeErrorCode.TIME_NOT_FOUND
}
}
test("이전 날짜이면 실패한다.") {
every {
timeFinder.findById(timeId)
} returns TimeFixture.create(id = timeId, startAt = LocalTime.now().plusHours(1))
every {
reservationValidator.validateIsPast(any(), any())
} throws ReservationException(ReservationErrorCode.PAST_REQUEST_DATETIME)
shouldThrow<ReservationException> {
reservationWriter.create(today.minusDays(1), timeId, themeId, memberId, status, requesterId)
}.also {
it.errorCode shouldBe ReservationErrorCode.PAST_REQUEST_DATETIME
}
}
test("테마를 찾을 수 없으면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every {
themeFinder.findById(themeId)
} throws ThemeException(ThemeErrorCode.THEME_NOT_FOUND)
shouldThrow<ThemeException> {
reservationWriter.create(today.plusDays(1), timeId, themeId, memberId, status, requesterId)
}.also {
it.errorCode shouldBe ThemeErrorCode.THEME_NOT_FOUND
}
}
test("회원을 찾을 수 없으면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every { themeFinder.findById(themeId) } returns ThemeFixture.create(id = themeId)
every {
memberFinder.findById(memberId)
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
shouldThrow<MemberException> {
reservationWriter.create(today.plusDays(1), timeId, themeId, memberId, status, requesterId)
}.also {
it.errorCode shouldBe MemberErrorCode.MEMBER_NOT_FOUND
}
}
test("이미 예약이 있는 회원이 대기를 추가하면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every { themeFinder.findById(themeId) } returns ThemeFixture.create(id = themeId)
every { memberFinder.findById(memberId) } returns MemberFixture.create(id = memberId)
every {
reservationValidator.validateMemberAlreadyReserve(themeId, timeId, today, memberId)
} throws ReservationException(ReservationErrorCode.ALREADY_RESERVE)
shouldThrow<ReservationException> {
reservationWriter.create(today, timeId, themeId, memberId, status = ReservationStatus.WAITING, memberId)
}.also {
it.errorCode shouldBe ReservationErrorCode.ALREADY_RESERVE
}
}
test("동일한 날짜, 시간, 테마인 예약이 이미 있으면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every { themeFinder.findById(themeId) } returns ThemeFixture.create(id = themeId)
every { memberFinder.findById(memberId) } returns MemberFixture.create(id = memberId)
every {
reservationValidator.validateIsAlreadyExists(today, any(), any())
} throws ReservationException(ReservationErrorCode.RESERVATION_DUPLICATED)
shouldThrow<ReservationException> {
reservationWriter.create(today, timeId, themeId, memberId, status, memberId)
}.also {
it.errorCode shouldBe ReservationErrorCode.RESERVATION_DUPLICATED
}
}
test("예약하려는 회원과 신청한 회원이 다를 때, 신청한 회원을 찾을 수 없으면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every { themeFinder.findById(themeId) } returns ThemeFixture.create(id = themeId)
every { memberFinder.findById(memberId) } returns MemberFixture.create(id = memberId)
every { reservationValidator.validateIsAlreadyExists(today, any(), any()) } returns Unit
every {
memberFinder.findById(memberId + 1)
} throws MemberException(MemberErrorCode.MEMBER_NOT_FOUND)
shouldThrow<MemberException> {
reservationWriter.create(
today,
timeId,
themeId,
memberId = memberId,
status,
requesterId = (memberId + 1)
)
}.also {
it.errorCode shouldBe MemberErrorCode.MEMBER_NOT_FOUND
}
}
test("예약하려는 회원과 신청한 회원이 다를 때, 신청한 회원이 관리자가 아니면 실패한다.") {
every { timeFinder.findById(timeId) } returns TimeFixture.create(id = timeId)
every { reservationValidator.validateIsPast(any(), any()) } returns Unit
every { themeFinder.findById(themeId) } returns ThemeFixture.create(id = themeId)
every { memberFinder.findById(memberId) } returns MemberFixture.create(id = memberId)
every { reservationValidator.validateIsAlreadyExists(today, any(), any()) } returns Unit
every {
memberFinder.findById(memberId + 1)
} returns MemberFixture.create(id = memberId + 1)
every {
reservationValidator.validateCreateAuthority(any())
} throws ReservationException(ReservationErrorCode.NO_PERMISSION)
shouldThrow<ReservationException> {
reservationWriter.create(
today,
timeId,
themeId,
memberId = memberId,
status,
requesterId = (memberId + 1)
)
}.also {
it.errorCode shouldBe ReservationErrorCode.NO_PERMISSION
}
}
}
context("deleteWaiting") {
val reservation: ReservationEntity = mockk()
val requesterId = 1L
test("대기 상태가 아니면 실패한다.") {
every {
reservationValidator.validateIsWaiting(any())
} throws ReservationException(ReservationErrorCode.ALREADY_CONFIRMED)
shouldThrow<ReservationException> {
reservationWriter.deleteWaiting(reservation, requesterId)
}.also {
it.errorCode shouldBe ReservationErrorCode.ALREADY_CONFIRMED
}
}
test("삭제하려는 회원이 관리자가 아니고, 예약한 회원과 다르면 실패한다.") {
every { reservationValidator.validateIsWaiting(any()) } returns Unit
every {
reservationValidator.validateDeleteAuthority(any(), any())
} throws ReservationException(ReservationErrorCode.NOT_RESERVATION_OWNER)
shouldThrow<ReservationException> {
reservationWriter.deleteWaiting(reservation, requesterId)
}.also {
it.errorCode shouldBe ReservationErrorCode.NOT_RESERVATION_OWNER
}
}
}
context("deleteConfirm") {
val reservation: ReservationEntity = mockk()
val requesterId = 1L
test("삭제하려는 회원이 관리자가 아니고, 예약한 회원과 다르면 실패한다.") {
every { reservationValidator.validateIsWaiting(any()) } returns Unit
every {
reservationValidator.validateDeleteAuthority(any(), any())
} throws ReservationException(ReservationErrorCode.NOT_RESERVATION_OWNER)
shouldThrow<ReservationException> {
reservationWriter.deleteConfirmed(reservation, requesterId)
}.also {
it.errorCode shouldBe ReservationErrorCode.NOT_RESERVATION_OWNER
}
}
}
context("confirm") {
val reservationId = 1L
test("승인하려는 대기와 같은 날짜,시간,테마를 가진 확정 예약이 있으면 실패한다.") {
every {
reservationValidator.validateAlreadyConfirmed(reservationId)
} throws ReservationException(ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS)
shouldThrow<ReservationException> {
reservationWriter.confirm(reservationId)
}.also {
it.errorCode shouldBe ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS
}
}
}
})