From 11000f3f3d9ba126a308f390836b725f65c6e049 Mon Sep 17 00:00:00 2001 From: pricelees Date: Fri, 3 Oct 2025 15:25:35 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=EC=8A=A4=EC=BC=80=EC=A5=B4=EB=A7=81=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=B4=20?= =?UTF-8?q?=EB=B0=9C=EC=83=9D=20=EA=B0=80=EB=8A=A5=ED=95=9C=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=8B=9C=EB=82=98=EB=A6=AC=EC=98=A4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/ReservationConcurrencyTest.kt | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationConcurrencyTest.kt diff --git a/service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationConcurrencyTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationConcurrencyTest.kt new file mode 100644 index 00000000..111c14e1 --- /dev/null +++ b/service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationConcurrencyTest.kt @@ -0,0 +1,83 @@ +package com.sangdol.roomescape.reservation + +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.reservation.business.ReservationService +import com.sangdol.roomescape.reservation.business.scheduler.IncompletedReservationScheduler +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationRepository +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus +import com.sangdol.roomescape.reservation.web.PendingReservationCreateRequest +import com.sangdol.roomescape.reservation.web.PendingReservationCreateResponse +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import io.kotest.assertions.assertSoftly +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.withContext +import org.springframework.data.repository.findByIdOrNull +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.transaction.support.TransactionTemplate +import java.time.LocalDateTime + +class ReservationConcurrencyTest( + private val transactionManager: PlatformTransactionManager, + private val incompletedReservationScheduler: IncompletedReservationScheduler, + private val reservationService: ReservationService, + private val reservationRepository: ReservationRepository, + private val scheduleRepository: ScheduleRepository +) : FunSpecSpringbootTest() { + + init { + test("Pending 예약 생성시, Schedule 상태 검증 이후부터 커밋 이전 사이에 시작된 schedule 처리 배치 작업은 반영되지 않는다.") { + val user = testAuthUtil.defaultUserLogin().first + val schedule = dummyInitializer.createSchedule().also { + it.status = ScheduleStatus.HOLD + it.holdExpiredAt = LocalDateTime.now().minusMinutes(1) + scheduleRepository.save(it) + } + lateinit var response: PendingReservationCreateResponse + + withContext(Dispatchers.IO) { + val createPendingReservationJob = async { + response = TransactionTemplate(transactionManager).execute { + val response = reservationService.createPendingReservation( + user = CurrentUserContext(id = user.id, name = user.name), + request = PendingReservationCreateRequest( + scheduleId = schedule.id, + reserverName = user.name, + reserverContact = user.phone, + participantCount = 3, + requirement = "없어요!" + ) + ) + + Thread.sleep(200) + response + }!! + } + + val updateScheduleJob = async { + TransactionTemplate(transactionManager).execute { + incompletedReservationScheduler.processExpiredHoldSchedule() + } + } + + listOf(createPendingReservationJob, updateScheduleJob).awaitAll() + } + + + assertSoftly(scheduleRepository.findByIdOrNull(schedule.id)!!) { + this.status shouldBe ScheduleStatus.HOLD + this.holdExpiredAt.shouldNotBeNull() + } + + assertSoftly(reservationRepository.findByIdOrNull(response.id)) { + this.shouldNotBeNull() + this.status shouldBe ReservationStatus.PENDING + } + } + } +}