test #440
@@ -1,15 +1,26 @@
|
||||
package kr.co.vividnext.sodalive.live.reservation
|
||||
|
||||
import kr.co.vividnext.sodalive.can.charge.Charge
|
||||
import kr.co.vividnext.sodalive.can.charge.ChargeRepository
|
||||
import kr.co.vividnext.sodalive.can.payment.Payment
|
||||
import kr.co.vividnext.sodalive.can.payment.PaymentGateway
|
||||
import kr.co.vividnext.sodalive.can.payment.PaymentStatus
|
||||
import kr.co.vividnext.sodalive.can.use.UseCanRepository
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoom
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.mock.mockito.SpyBean
|
||||
import org.springframework.dao.DataIntegrityViolationException
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
@@ -34,9 +45,15 @@ import javax.persistence.EntityManager
|
||||
class LiveReservationServiceIntegrationTest @Autowired constructor(
|
||||
private val service: LiveReservationService,
|
||||
private val repository: LiveReservationRepository,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val chargeRepository: ChargeRepository,
|
||||
private val useCanRepository: UseCanRepository,
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
private val entityManager: EntityManager
|
||||
) {
|
||||
@SpyBean
|
||||
private lateinit var repositorySpy: LiveReservationRepository
|
||||
|
||||
@BeforeEach
|
||||
fun setUpRequestContext() {
|
||||
RequestContextHolder.setRequestAttributes(ServletRequestAttributes(MockHttpServletRequest()))
|
||||
@@ -73,7 +90,49 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
|
||||
assertEquals(fixture.memberId, savedReservation.memberId)
|
||||
}
|
||||
|
||||
private fun createFixture(): Fixture {
|
||||
@Test
|
||||
@DisplayName("유료 예약 저장이 실패하면 결제와 예약을 함께 롤백한다")
|
||||
fun shouldRollbackPaymentAndReservationWhenPaidReservationSaveFails() {
|
||||
val fixture = createFixture(price = 100)
|
||||
val useCanCountBefore = useCanRepository.count()
|
||||
|
||||
Mockito.doAnswer {
|
||||
assertEquals(useCanCountBefore + 1, useCanRepository.count())
|
||||
throw DataIntegrityViolationException("reservation save failed")
|
||||
}
|
||||
.`when`(repositorySpy)
|
||||
.save(Mockito.any(LiveReservation::class.java))
|
||||
|
||||
val exception = assertThrows(DataIntegrityViolationException::class.java) {
|
||||
service.makeReservation(
|
||||
request = MakeLiveReservationRequest(
|
||||
roomId = fixture.roomId,
|
||||
container = "web",
|
||||
timezone = "Asia/Seoul"
|
||||
),
|
||||
memberId = fixture.memberId
|
||||
)
|
||||
}
|
||||
|
||||
val rollbackState = transactionTemplate.execute {
|
||||
val member = memberRepository.findById(fixture.memberId).orElseThrow()
|
||||
val charge = chargeRepository.findById(fixture.chargeId!!).orElseThrow()
|
||||
RollbackState(
|
||||
memberCan = member.getChargeCan("web") + member.getRewardCan("web"),
|
||||
chargeCan = charge.chargeCan + charge.rewardCan,
|
||||
useCanCount = useCanRepository.count(),
|
||||
reservationExists = repository.isExistsReservation(fixture.roomId, fixture.memberId)
|
||||
)
|
||||
}!!
|
||||
|
||||
assertEquals("reservation save failed", exception.message)
|
||||
assertEquals(fixture.price, rollbackState.memberCan)
|
||||
assertEquals(fixture.price, rollbackState.chargeCan)
|
||||
assertEquals(useCanCountBefore, rollbackState.useCanCount)
|
||||
assertEquals(false, rollbackState.reservationExists)
|
||||
}
|
||||
|
||||
private fun createFixture(price: Int = 0): Fixture {
|
||||
return transactionTemplate.execute {
|
||||
val creator = Member(
|
||||
email = "live-reservation-creator@test.com",
|
||||
@@ -87,14 +146,29 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
|
||||
password = "password",
|
||||
nickname = "live-reservation-member"
|
||||
)
|
||||
member.pgChargeCan = price
|
||||
entityManager.persist(member)
|
||||
|
||||
val charge = if (price > 0) {
|
||||
Charge(chargeCan = price, rewardCan = 0).also {
|
||||
it.member = member
|
||||
it.payment = Payment(
|
||||
status = PaymentStatus.COMPLETE,
|
||||
paymentGateway = PaymentGateway.PG
|
||||
)
|
||||
entityManager.persist(it)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val room = LiveRoom(
|
||||
title = "예약 라이브",
|
||||
notice = "예약 라이브 안내",
|
||||
beginDateTime = LocalDateTime.now().plusDays(1),
|
||||
numberOfPeople = 10,
|
||||
isAdult = false
|
||||
isAdult = false,
|
||||
price = price
|
||||
)
|
||||
room.member = creator
|
||||
entityManager.persist(room)
|
||||
@@ -102,7 +176,9 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
|
||||
entityManager.flush()
|
||||
val fixture = Fixture(
|
||||
roomId = room.id!!,
|
||||
memberId = member.id!!
|
||||
memberId = member.id!!,
|
||||
chargeId = charge?.id,
|
||||
price = price
|
||||
)
|
||||
entityManager.clear()
|
||||
fixture
|
||||
@@ -111,11 +187,20 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
|
||||
|
||||
private data class Fixture(
|
||||
val roomId: Long,
|
||||
val memberId: Long
|
||||
val memberId: Long,
|
||||
val chargeId: Long?,
|
||||
val price: Int
|
||||
)
|
||||
|
||||
private data class SavedReservation(
|
||||
val roomId: Long,
|
||||
val memberId: Long
|
||||
)
|
||||
|
||||
private data class RollbackState(
|
||||
val memberCan: Int,
|
||||
val chargeCan: Int,
|
||||
val useCanCount: Long,
|
||||
val reservationExists: Boolean
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user