test #440

Merged
klaus merged 6 commits from test into main 2026-07-15 12:24:50 +00:00
Showing only changes of commit 074042270c - Show all commits

View File

@@ -1,15 +1,26 @@
package kr.co.vividnext.sodalive.live.reservation 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.live.room.LiveRoom
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRepository
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals 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.BeforeEach
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest 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.mock.web.MockHttpServletRequest
import org.springframework.test.annotation.DirtiesContext import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.ContextConfiguration
@@ -34,9 +45,15 @@ import javax.persistence.EntityManager
class LiveReservationServiceIntegrationTest @Autowired constructor( class LiveReservationServiceIntegrationTest @Autowired constructor(
private val service: LiveReservationService, private val service: LiveReservationService,
private val repository: LiveReservationRepository, private val repository: LiveReservationRepository,
private val memberRepository: MemberRepository,
private val chargeRepository: ChargeRepository,
private val useCanRepository: UseCanRepository,
private val transactionTemplate: TransactionTemplate, private val transactionTemplate: TransactionTemplate,
private val entityManager: EntityManager private val entityManager: EntityManager
) { ) {
@SpyBean
private lateinit var repositorySpy: LiveReservationRepository
@BeforeEach @BeforeEach
fun setUpRequestContext() { fun setUpRequestContext() {
RequestContextHolder.setRequestAttributes(ServletRequestAttributes(MockHttpServletRequest())) RequestContextHolder.setRequestAttributes(ServletRequestAttributes(MockHttpServletRequest()))
@@ -73,7 +90,49 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
assertEquals(fixture.memberId, savedReservation.memberId) 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 { return transactionTemplate.execute {
val creator = Member( val creator = Member(
email = "live-reservation-creator@test.com", email = "live-reservation-creator@test.com",
@@ -87,14 +146,29 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
password = "password", password = "password",
nickname = "live-reservation-member" nickname = "live-reservation-member"
) )
member.pgChargeCan = price
entityManager.persist(member) 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( val room = LiveRoom(
title = "예약 라이브", title = "예약 라이브",
notice = "예약 라이브 안내", notice = "예약 라이브 안내",
beginDateTime = LocalDateTime.now().plusDays(1), beginDateTime = LocalDateTime.now().plusDays(1),
numberOfPeople = 10, numberOfPeople = 10,
isAdult = false isAdult = false,
price = price
) )
room.member = creator room.member = creator
entityManager.persist(room) entityManager.persist(room)
@@ -102,7 +176,9 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
entityManager.flush() entityManager.flush()
val fixture = Fixture( val fixture = Fixture(
roomId = room.id!!, roomId = room.id!!,
memberId = member.id!! memberId = member.id!!,
chargeId = charge?.id,
price = price
) )
entityManager.clear() entityManager.clear()
fixture fixture
@@ -111,11 +187,20 @@ class LiveReservationServiceIntegrationTest @Autowired constructor(
private data class Fixture( private data class Fixture(
val roomId: Long, val roomId: Long,
val memberId: Long val memberId: Long,
val chargeId: Long?,
val price: Int
) )
private data class SavedReservation( private data class SavedReservation(
val roomId: Long, val roomId: Long,
val memberId: Long val memberId: Long
) )
private data class RollbackState(
val memberCan: Int,
val chargeCan: Int,
val useCanCount: Long,
val reservationExists: Boolean
)
} }