pricelees d3e22888ed [#28] 쿠버네티스 환경 배포 (#29)
<!-- 제목 양식 -->
<!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) -->

## 📝 관련 이슈 및 PR

**PR과 관련된 이슈 번호**
- #28

##  작업 내용
<!-- 어떤 작업을 했는지 알려주세요! -->
- 프론트엔드, 백엔드 쿠버네티스 환경 배포(ArgoCD 이용)
- Helm 차트는 private repository에 업로드

## 🧪 테스트
<!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! -->
- 배포 환경에서 기능 정상 동작 확인

## 📚 참고 자료 및 기타
<!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! -->

Reviewed-on: #29
Co-authored-by: pricelees <priceelees@gmail.com>
Co-committed-by: pricelees <priceelees@gmail.com>
2025-08-04 05:59:38 +00:00

288 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.TsidFactory
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(
TsidFactory,
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
}
}
}
})