generated from pricelees/issue-pr-template
[#52] 만료 예약 / 일정 스케쥴링 작업 추가 및 동시성 처리를 위한 일부 코드 수정 #53
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user