generated from pricelees/issue-pr-template
[#28] 쿠버네티스 환경 배포 #29
@ -15,10 +15,11 @@ import roomescape.member.infrastructure.persistence.MemberEntity
|
|||||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
import roomescape.util.JwtFixture
|
import roomescape.util.JwtFixture
|
||||||
import roomescape.util.MemberFixture
|
import roomescape.util.MemberFixture
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
|
|
||||||
class AuthServiceTest : BehaviorSpec({
|
class AuthServiceTest : BehaviorSpec({
|
||||||
val memberRepository: MemberRepository = mockk()
|
val memberRepository: MemberRepository = mockk()
|
||||||
val memberService: MemberService = MemberService(memberRepository)
|
val memberService = MemberService(TsidFactory, memberRepository)
|
||||||
val jwtHandler: JwtHandler = JwtFixture.create()
|
val jwtHandler: JwtHandler = JwtFixture.create()
|
||||||
|
|
||||||
val authService = AuthService(memberService, jwtHandler)
|
val authService = AuthService(memberService, jwtHandler)
|
||||||
|
|||||||
@ -14,13 +14,14 @@ import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository
|
|||||||
import roomescape.payment.infrastructure.persistence.PaymentRepository
|
import roomescape.payment.infrastructure.persistence.PaymentRepository
|
||||||
import roomescape.payment.web.PaymentCancelRequest
|
import roomescape.payment.web.PaymentCancelRequest
|
||||||
import roomescape.util.PaymentFixture
|
import roomescape.util.PaymentFixture
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
class PaymentServiceTest : FunSpec({
|
class PaymentServiceTest : FunSpec({
|
||||||
val paymentRepository: PaymentRepository = mockk()
|
val paymentRepository: PaymentRepository = mockk()
|
||||||
val canceledPaymentRepository: CanceledPaymentRepository = mockk()
|
val canceledPaymentRepository: CanceledPaymentRepository = mockk()
|
||||||
|
|
||||||
val paymentService = PaymentService(paymentRepository, canceledPaymentRepository)
|
val paymentService = PaymentService(TsidFactory, paymentRepository, canceledPaymentRepository)
|
||||||
|
|
||||||
context("createCanceledPaymentByReservationId") {
|
context("createCanceledPaymentByReservationId") {
|
||||||
val reservationId = 1L
|
val reservationId = 1L
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
package roomescape.payment.infrastructure.client
|
package roomescape.payment.infrastructure.client
|
||||||
|
|
||||||
|
import com.ninjasquad.springmockk.MockkBean
|
||||||
import io.kotest.assertions.assertSoftly
|
import io.kotest.assertions.assertSoftly
|
||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
|
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
|
||||||
|
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext
|
||||||
import org.springframework.http.HttpMethod
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
@ -20,6 +22,7 @@ import roomescape.payment.web.PaymentCancelRequest
|
|||||||
import roomescape.payment.web.PaymentCancelResponse
|
import roomescape.payment.web.PaymentCancelResponse
|
||||||
|
|
||||||
@RestClientTest(TossPaymentClient::class)
|
@RestClientTest(TossPaymentClient::class)
|
||||||
|
@MockkBean(JpaMetamodelMappingContext::class)
|
||||||
class TossPaymentClientTest(
|
class TossPaymentClientTest(
|
||||||
@Autowired val client: TossPaymentClient,
|
@Autowired val client: TossPaymentClient,
|
||||||
@Autowired val mockServer: MockRestServiceServer
|
@Autowired val mockServer: MockRestServiceServer
|
||||||
|
|||||||
@ -5,10 +5,12 @@ import io.kotest.core.spec.style.FunSpec
|
|||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||||
|
import roomescape.common.config.next
|
||||||
import roomescape.util.PaymentFixture
|
import roomescape.util.PaymentFixture
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class CanceledPaymentRepositoryTest(
|
class CanceledPaymentRepositoryTest(
|
||||||
@Autowired val canceledPaymentRepository: CanceledPaymentRepository,
|
@Autowired val canceledPaymentRepository: CanceledPaymentRepository,
|
||||||
) : FunSpec() {
|
) : FunSpec() {
|
||||||
@ -16,7 +18,7 @@ class CanceledPaymentRepositoryTest(
|
|||||||
context("paymentKey로 CanceledPaymentEntity 조회") {
|
context("paymentKey로 CanceledPaymentEntity 조회") {
|
||||||
val paymentKey = "test-payment-key"
|
val paymentKey = "test-payment-key"
|
||||||
beforeTest {
|
beforeTest {
|
||||||
PaymentFixture.createCanceled(paymentKey = paymentKey)
|
PaymentFixture.createCanceled(id = TsidFactory.next(), paymentKey = paymentKey)
|
||||||
.also { canceledPaymentRepository.save(it) }
|
.also { canceledPaymentRepository.save(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,11 +6,13 @@ import io.kotest.matchers.shouldBe
|
|||||||
import jakarta.persistence.EntityManager
|
import jakarta.persistence.EntityManager
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||||
|
import roomescape.common.config.next
|
||||||
import roomescape.reservation.infrastructure.persistence.ReservationEntity
|
import roomescape.reservation.infrastructure.persistence.ReservationEntity
|
||||||
import roomescape.util.PaymentFixture
|
import roomescape.util.PaymentFixture
|
||||||
import roomescape.util.ReservationFixture
|
import roomescape.util.ReservationFixture
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class PaymentRepositoryTest(
|
class PaymentRepositoryTest(
|
||||||
@Autowired val paymentRepository: PaymentRepository,
|
@Autowired val paymentRepository: PaymentRepository,
|
||||||
@Autowired val entityManager: EntityManager
|
@Autowired val entityManager: EntityManager
|
||||||
@ -91,7 +93,9 @@ class PaymentRepositoryTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupReservation(): ReservationEntity {
|
private fun setupReservation(): ReservationEntity {
|
||||||
return ReservationFixture.create().also {
|
return ReservationFixture.create(
|
||||||
|
id = TsidFactory.next()
|
||||||
|
).also {
|
||||||
entityManager.persist(it.member)
|
entityManager.persist(it.member)
|
||||||
entityManager.persist(it.theme)
|
entityManager.persist(it.theme)
|
||||||
entityManager.persist(it.time)
|
entityManager.persist(it.time)
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import roomescape.theme.business.ThemeService
|
|||||||
import roomescape.time.business.TimeService
|
import roomescape.time.business.TimeService
|
||||||
import roomescape.util.MemberFixture
|
import roomescape.util.MemberFixture
|
||||||
import roomescape.util.ReservationFixture
|
import roomescape.util.ReservationFixture
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
import roomescape.util.TimeFixture
|
import roomescape.util.TimeFixture
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
@ -27,6 +28,7 @@ class ReservationServiceTest : FunSpec({
|
|||||||
val memberService: MemberService = mockk()
|
val memberService: MemberService = mockk()
|
||||||
val themeService: ThemeService = mockk()
|
val themeService: ThemeService = mockk()
|
||||||
val reservationService = ReservationService(
|
val reservationService = ReservationService(
|
||||||
|
TsidFactory,
|
||||||
reservationRepository,
|
reservationRepository,
|
||||||
timeService,
|
timeService,
|
||||||
memberService,
|
memberService,
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import roomescape.util.ReservationFixture
|
|||||||
import roomescape.util.ThemeFixture
|
import roomescape.util.ThemeFixture
|
||||||
import roomescape.util.TimeFixture
|
import roomescape.util.TimeFixture
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class ReservationRepositoryTest(
|
class ReservationRepositoryTest(
|
||||||
val entityManager: EntityManager,
|
val entityManager: EntityManager,
|
||||||
val reservationRepository: ReservationRepository,
|
val reservationRepository: ReservationRepository,
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import roomescape.util.ThemeFixture
|
|||||||
import roomescape.util.TimeFixture
|
import roomescape.util.TimeFixture
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class ReservationSearchSpecificationTest(
|
class ReservationSearchSpecificationTest(
|
||||||
val entityManager: EntityManager,
|
val entityManager: EntityManager,
|
||||||
val reservationRepository: ReservationRepository
|
val reservationRepository: ReservationRepository
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import java.time.LocalTime
|
|||||||
class ReservationControllerTest(
|
class ReservationControllerTest(
|
||||||
@LocalServerPort val port: Int,
|
@LocalServerPort val port: Int,
|
||||||
val entityManager: EntityManager,
|
val entityManager: EntityManager,
|
||||||
val transactionTemplate: TransactionTemplate
|
val transactionTemplate: TransactionTemplate,
|
||||||
) : FunSpec({
|
) : FunSpec({
|
||||||
extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_EACH_TEST))
|
extension(DatabaseCleanerExtension(mode = CleanerMode.AFTER_EACH_TEST))
|
||||||
}) {
|
}) {
|
||||||
@ -55,24 +55,34 @@ class ReservationControllerTest(
|
|||||||
@MockkBean
|
@MockkBean
|
||||||
lateinit var jwtHandler: JwtHandler
|
lateinit var jwtHandler: JwtHandler
|
||||||
|
|
||||||
|
lateinit var testDataHelper: TestDataHelper
|
||||||
|
|
||||||
|
fun login(member: MemberEntity) {
|
||||||
|
every { jwtHandler.getMemberIdFromToken(any()) } returns member.id!!
|
||||||
|
every { memberService.findById(member.id!!) } returns member
|
||||||
|
every { memberIdResolver.resolveArgument(any(), any(), any(), any()) } returns member.id!!
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
beforeSpec {
|
||||||
|
testDataHelper = TestDataHelper(entityManager, transactionTemplate)
|
||||||
|
}
|
||||||
|
|
||||||
context("POST /reservations") {
|
context("POST /reservations") {
|
||||||
lateinit var member: MemberEntity
|
|
||||||
beforeTest {
|
beforeTest {
|
||||||
member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
|
login(member)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val reservationRequest = createRequest()
|
val reservationRequest = testDataHelper.createReservationRequest()
|
||||||
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
||||||
paymentKey = reservationRequest.paymentKey,
|
paymentKey = reservationRequest.paymentKey,
|
||||||
orderId = reservationRequest.orderId,
|
orderId = reservationRequest.orderId,
|
||||||
totalAmount = reservationRequest.amount,
|
totalAmount = reservationRequest.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every { paymentClient.confirm(any()) } returns paymentApproveResponse
|
||||||
paymentClient.confirm(any())
|
|
||||||
} returns paymentApproveResponse
|
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -88,12 +98,10 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("결제 과정에서 발생하는 에러는 그대로 응답") {
|
test("결제 과정에서 발생하는 에러는 그대로 응답") {
|
||||||
val reservationRequest = createRequest()
|
val reservationRequest = testDataHelper.createReservationRequest()
|
||||||
val paymentException = PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
val paymentException = PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR)
|
||||||
|
|
||||||
every {
|
every { paymentClient.confirm(any()) } throws paymentException
|
||||||
paymentClient.confirm(any())
|
|
||||||
} throws paymentException
|
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -108,24 +116,20 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("결제 완료 후 예약 / 결제 정보 저장 과정에서 에러 발생시 결제 취소 후 에러 응답을 받는다.") {
|
test("결제 완료 후 예약 / 결제 정보 저장 과정에서 에러 발생시 결제 취소 후 에러 응답을 받는다.") {
|
||||||
val reservationRequest = createRequest()
|
val reservationRequest = testDataHelper.createReservationRequest()
|
||||||
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
val paymentApproveResponse = PaymentFixture.createApproveResponse().copy(
|
||||||
paymentKey = reservationRequest.paymentKey,
|
paymentKey = reservationRequest.paymentKey,
|
||||||
orderId = reservationRequest.orderId,
|
orderId = reservationRequest.orderId,
|
||||||
totalAmount = reservationRequest.amount,
|
totalAmount = reservationRequest.amount,
|
||||||
)
|
)
|
||||||
|
|
||||||
every {
|
every { paymentClient.confirm(any()) } returns paymentApproveResponse
|
||||||
paymentClient.confirm(any())
|
|
||||||
} returns paymentApproveResponse
|
|
||||||
|
|
||||||
// 예약 저장 과정에서 테마가 없는 예외
|
// 예약 저장 과정에서 테마가 없는 예외
|
||||||
val invalidRequest = reservationRequest.copy(themeId = reservationRequest.themeId + 1)
|
val invalidRequest = reservationRequest.copy(themeId = reservationRequest.themeId + 1)
|
||||||
val expectedException = ThemeErrorCode.THEME_NOT_FOUND
|
val expectedException = ThemeErrorCode.THEME_NOT_FOUND
|
||||||
|
|
||||||
every {
|
every { paymentClient.cancel(any()) } returns PaymentFixture.createCancelResponse()
|
||||||
paymentClient.cancel(any())
|
|
||||||
} returns PaymentFixture.createCancelResponse()
|
|
||||||
|
|
||||||
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
@ -153,13 +157,13 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("GET /reservations") {
|
context("GET /reservations") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
lateinit var reservations: Map<MemberEntity, List<ReservationEntity>>
|
||||||
beforeTest {
|
beforeTest {
|
||||||
reservations = createDummyReservations()
|
reservations = testDataHelper.createDummyReservations()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("관리자이면 정상 응답") {
|
test("관리자이면 정상 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
@ -173,13 +177,14 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("GET /reservations-mine") {
|
context("GET /reservations-mine") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
lateinit var reservations: Map<MemberEntity, List<ReservationEntity>>
|
||||||
beforeTest {
|
beforeTest {
|
||||||
reservations = createDummyReservations()
|
reservations = testDataHelper.createDummyReservations()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("로그인한 회원이 자신의 예약 목록을 조회한다.") {
|
test("로그인한 회원이 자신의 예약 목록을 조회한다.") {
|
||||||
val member: MemberEntity = login(reservations.keys.first())
|
val member = reservations.keys.first()
|
||||||
|
login(member)
|
||||||
val expectedReservations: Int = reservations[member]?.size ?: 0
|
val expectedReservations: Int = reservations[member]?.size ?: 0
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -195,9 +200,9 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("GET /reservations/search") {
|
context("GET /reservations/search") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
lateinit var reservations: Map<MemberEntity, List<ReservationEntity>>
|
||||||
beforeTest {
|
beforeTest {
|
||||||
reservations = createDummyReservations()
|
reservations = testDataHelper.createDummyReservations()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("관리자만 검색할 수 있다.") {
|
test("관리자만 검색할 수 있다.") {
|
||||||
@ -216,7 +221,7 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("파라미터를 지정하지 않으면 전체 목록 응답") {
|
test("파라미터를 지정하지 않으면 전체 목록 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -230,7 +235,7 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("시작 날짜가 종료 날짜 이전이면 예외 응답") {
|
test("시작 날짜가 종료 날짜 이전이면 예외 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
|
|
||||||
val startDate = LocalDate.now().plusDays(1)
|
val startDate = LocalDate.now().plusDays(1)
|
||||||
val endDate = LocalDate.now()
|
val endDate = LocalDate.now()
|
||||||
@ -250,8 +255,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("동일한 회원의 모든 예약 응답") {
|
test("동일한 회원의 모든 예약 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val member: MemberEntity = reservations.keys.first()
|
val member = reservations.keys.first()
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -266,7 +271,7 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("동일한 테마의 모든 예약 응답") {
|
test("동일한 테마의 모든 예약 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val themes = reservations.values.flatten().map { it.theme }
|
val themes = reservations.values.flatten().map { it.theme }
|
||||||
val requestThemeId: Long = themes.first().id!!
|
val requestThemeId: Long = themes.first().id!!
|
||||||
|
|
||||||
@ -278,12 +283,12 @@ class ReservationControllerTest(
|
|||||||
get("/reservations/search")
|
get("/reservations/search")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(200)
|
statusCode(200)
|
||||||
body("data.reservations.size()", equalTo(themes.filter { it.id == requestThemeId }.size))
|
body("data.reservations.size()", equalTo(themes.count { it.id == requestThemeId }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("시작 날짜와 종료 날짜 사이의 예약 응답") {
|
test("시작 날짜와 종료 날짜 사이의 예약 응답") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val dateFrom: LocalDate = reservations.values.flatten().minOf { it.date }
|
val dateFrom: LocalDate = reservations.values.flatten().minOf { it.date }
|
||||||
val dateTo: LocalDate = reservations.values.flatten().maxOf { it.date }
|
val dateTo: LocalDate = reservations.values.flatten().maxOf { it.date }
|
||||||
|
|
||||||
@ -302,14 +307,14 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("DELETE /reservations/{id}") {
|
context("DELETE /reservations/{id}") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
lateinit var reservations: Map<MemberEntity, List<ReservationEntity>>
|
||||||
beforeTest {
|
beforeTest {
|
||||||
reservations = createDummyReservations()
|
reservations = testDataHelper.createDummyReservations()
|
||||||
}
|
}
|
||||||
|
|
||||||
test("관리자만 예약을 삭제할 수 있다.") {
|
test("관리자만 예약을 삭제할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(testDataHelper.createMember(role = Role.MEMBER))
|
||||||
val reservation: ReservationEntity = reservations.values.flatten().first()
|
val reservation = reservations.values.flatten().first()
|
||||||
val expectedError = AuthErrorCode.ACCESS_DENIED
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -323,18 +328,12 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("결제되지 않은 예약은 바로 제거") {
|
test("결제되지 않은 예약은 바로 제거") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val reservationId: Long = reservations.values.flatten().first().id!!
|
val reservationId = reservations.values.flatten().first().id!!
|
||||||
|
|
||||||
transactionTemplate.execute {
|
transactionTemplate.executeWithoutResult {
|
||||||
val reservation: ReservationEntity = entityManager.find(
|
val reservation = entityManager.find(ReservationEntity::class.java, reservationId)
|
||||||
ReservationEntity::class.java,
|
|
||||||
reservationId
|
|
||||||
)
|
|
||||||
reservation.status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
reservation.status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
entityManager.persist(reservation)
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -345,32 +344,18 @@ class ReservationControllerTest(
|
|||||||
statusCode(HttpStatus.NO_CONTENT.value())
|
statusCode(HttpStatus.NO_CONTENT.value())
|
||||||
}
|
}
|
||||||
|
|
||||||
// 예약이 삭제되었는지 확인
|
val deletedReservation = transactionTemplate.execute {
|
||||||
transactionTemplate.executeWithoutResult {
|
entityManager.find(ReservationEntity::class.java, reservationId)
|
||||||
val deletedReservation = entityManager.find(
|
|
||||||
ReservationEntity::class.java,
|
|
||||||
reservationId
|
|
||||||
)
|
|
||||||
deletedReservation shouldBe null
|
|
||||||
}
|
}
|
||||||
|
deletedReservation shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("결제된 예약은 취소 후 제거") {
|
test("결제된 예약은 취소 후 제거") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val reservation: ReservationEntity = reservations.values.flatten().first()
|
val reservation = reservations.values.flatten().first { it.status == ReservationStatus.CONFIRMED }
|
||||||
lateinit var payment: PaymentEntity
|
testDataHelper.createPayment(reservation)
|
||||||
|
|
||||||
transactionTemplate.execute {
|
every { paymentClient.cancel(any()) } returns PaymentFixture.createCancelResponse()
|
||||||
payment = PaymentFixture.create(reservation = reservation).also {
|
|
||||||
entityManager.persist(it)
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
every {
|
|
||||||
paymentClient.cancel(any())
|
|
||||||
} returns PaymentFixture.createCancelResponse()
|
|
||||||
|
|
||||||
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
val canceledPaymentSizeBeforeApiCall: Long = entityManager.createQuery(
|
||||||
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
"SELECT COUNT(c) FROM CanceledPaymentEntity c",
|
||||||
@ -396,15 +381,17 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
context("POST /reservations/admin") {
|
context("POST /reservations/admin") {
|
||||||
test("관리자가 예약을 추가하면 결제 대기 상태로 예약 생성") {
|
test("관리자가 예약을 추가하면 결제 대기 상태로 예약 생성") {
|
||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
val admin = testDataHelper.createMember(role = Role.ADMIN)
|
||||||
val adminRequest: AdminReservationCreateRequest = createRequest().let {
|
login(admin)
|
||||||
AdminReservationCreateRequest(
|
val theme = testDataHelper.createTheme()
|
||||||
date = it.date,
|
val time = testDataHelper.createTime()
|
||||||
themeId = it.themeId,
|
|
||||||
timeId = it.timeId,
|
val adminRequest = AdminReservationCreateRequest(
|
||||||
memberId = member.id!!,
|
date = LocalDate.now().plusDays(1),
|
||||||
)
|
themeId = theme.id!!,
|
||||||
}
|
timeId = time.id!!,
|
||||||
|
memberId = admin.id!!,
|
||||||
|
)
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -420,13 +407,13 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("GET /reservations/waiting") {
|
context("GET /reservations/waiting") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
lateinit var reservations: Map<MemberEntity, List<ReservationEntity>>
|
||||||
beforeTest {
|
beforeTest {
|
||||||
reservations = createDummyReservations()
|
reservations = testDataHelper.createDummyReservations(reservationCount = 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("관리자가 아니면 조회할 수 없다.") {
|
test("관리자가 아니면 조회할 수 없다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(testDataHelper.createMember(role = Role.MEMBER))
|
||||||
val expectedError = AuthErrorCode.ACCESS_DENIED
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -441,7 +428,7 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("대기 중인 예약 목록을 조회한다.") {
|
test("대기 중인 예약 목록을 조회한다.") {
|
||||||
login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val expected = reservations.values.flatten()
|
val expected = reservations.values.flatten()
|
||||||
.count { it.status == ReservationStatus.WAITING }
|
.count { it.status == ReservationStatus.WAITING }
|
||||||
|
|
||||||
@ -459,14 +446,16 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
context("POST /reservations/waiting") {
|
context("POST /reservations/waiting") {
|
||||||
test("회원이 대기 예약을 추가한다.") {
|
test("회원이 대기 예약을 추가한다.") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
val waitingCreateRequest: WaitingCreateRequest = createRequest().let {
|
login(member)
|
||||||
WaitingCreateRequest(
|
val theme = testDataHelper.createTheme()
|
||||||
date = it.date,
|
val time = testDataHelper.createTime()
|
||||||
themeId = it.themeId,
|
|
||||||
timeId = it.timeId
|
val waitingCreateRequest = WaitingCreateRequest(
|
||||||
)
|
date = LocalDate.now().plusDays(1),
|
||||||
}
|
themeId = theme.id!!,
|
||||||
|
timeId = time.id!!
|
||||||
|
)
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -476,33 +465,30 @@ class ReservationControllerTest(
|
|||||||
post("/reservations/waiting")
|
post("/reservations/waiting")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(201)
|
statusCode(201)
|
||||||
body("data.member.id", equalTo(member.id!!.toInt()))
|
body("data.member.id", equalTo(member.id!!))
|
||||||
body("data.status", equalTo(ReservationStatus.WAITING.name))
|
body("data.status", equalTo(ReservationStatus.WAITING.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test("이미 예약된 시간, 테마로 대기 예약 요청 시 예외 응답") {
|
test("이미 예약된 시간, 테마로 대기 예약 요청 시 예외 응답") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
val reservationRequest = createRequest()
|
login(member)
|
||||||
|
val theme = testDataHelper.createTheme()
|
||||||
|
val time = testDataHelper.createTime()
|
||||||
|
val date = LocalDate.now().plusDays(1)
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
testDataHelper.createReservation(
|
||||||
val reservation = ReservationFixture.create(
|
date = date,
|
||||||
date = reservationRequest.date,
|
theme = theme,
|
||||||
theme = entityManager.find(ThemeEntity::class.java, reservationRequest.themeId),
|
time = time,
|
||||||
time = entityManager.find(TimeEntity::class.java, reservationRequest.timeId),
|
member = member,
|
||||||
member = member,
|
status = ReservationStatus.CONFIRMED
|
||||||
status = ReservationStatus.WAITING
|
)
|
||||||
)
|
|
||||||
entityManager.persist(reservation)
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 이미 예약된 시간, 테마로 대기 예약 요청
|
|
||||||
val waitingCreateRequest = WaitingCreateRequest(
|
val waitingCreateRequest = WaitingCreateRequest(
|
||||||
date = reservationRequest.date,
|
date = date,
|
||||||
themeId = reservationRequest.themeId,
|
themeId = theme.id!!,
|
||||||
timeId = reservationRequest.timeId
|
timeId = time.id!!
|
||||||
)
|
)
|
||||||
val expectedError = ReservationErrorCode.ALREADY_RESERVE
|
val expectedError = ReservationErrorCode.ALREADY_RESERVE
|
||||||
|
|
||||||
@ -520,14 +506,10 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context("DELETE /reservations/waiting/{id}") {
|
context("DELETE /reservations/waiting/{id}") {
|
||||||
lateinit var reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>>
|
|
||||||
beforeTest {
|
|
||||||
reservations = createDummyReservations()
|
|
||||||
}
|
|
||||||
|
|
||||||
test("대기 중인 예약을 취소한다.") {
|
test("대기 중인 예약을 취소한다.") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
val waiting: ReservationEntity = createSingleReservation(
|
login(member)
|
||||||
|
val waiting = testDataHelper.createReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
@ -540,17 +522,16 @@ class ReservationControllerTest(
|
|||||||
statusCode(HttpStatus.NO_CONTENT.value())
|
statusCode(HttpStatus.NO_CONTENT.value())
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
val deleted = transactionTemplate.execute {
|
||||||
entityManager.find(
|
entityManager.find(ReservationEntity::class.java, waiting.id)
|
||||||
ReservationEntity::class.java,
|
|
||||||
waiting.id
|
|
||||||
) shouldBe null
|
|
||||||
}
|
}
|
||||||
|
deleted shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
test("이미 확정된 예약을 삭제하면 예외 응답") {
|
test("이미 확정된 예약을 삭제하면 예외 응답") {
|
||||||
val member = login(MemberFixture.create(role = Role.MEMBER))
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
val reservation: ReservationEntity = createSingleReservation(
|
login(member)
|
||||||
|
val reservation = testDataHelper.createReservation(
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
status = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
)
|
)
|
||||||
@ -559,7 +540,7 @@ class ReservationControllerTest(
|
|||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
}.When {
|
}.When {
|
||||||
delete("/reservations/waiting/{id}", reservation.id)
|
delete("/reservations/waiting/${reservation.id}")
|
||||||
}.Then {
|
}.Then {
|
||||||
statusCode(expectedError.httpStatus.value())
|
statusCode(expectedError.httpStatus.value())
|
||||||
body("code", equalTo(expectedError.errorCode))
|
body("code", equalTo(expectedError.errorCode))
|
||||||
@ -569,7 +550,7 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
context("POST /reservations/waiting/{id}/confirm") {
|
context("POST /reservations/waiting/{id}/confirm") {
|
||||||
test("관리자만 승인할 수 있다.") {
|
test("관리자만 승인할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(testDataHelper.createMember(role = Role.MEMBER))
|
||||||
val expectedError = AuthErrorCode.ACCESS_DENIED
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
Given {
|
Given {
|
||||||
port(port)
|
port(port)
|
||||||
@ -582,9 +563,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("대기 예약을 승인하면 결제 대기 상태로 변경") {
|
test("대기 예약을 승인하면 결제 대기 상태로 변경") {
|
||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val reservation = createSingleReservation(
|
val reservation = testDataHelper.createReservation(
|
||||||
member = member,
|
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -596,39 +576,28 @@ class ReservationControllerTest(
|
|||||||
statusCode(200)
|
statusCode(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
val updatedReservation = transactionTemplate.execute {
|
||||||
entityManager.find(
|
entityManager.find(ReservationEntity::class.java, reservation.id)
|
||||||
ReservationEntity::class.java,
|
|
||||||
reservation.id
|
|
||||||
)?.also {
|
|
||||||
it.status shouldBe ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
|
||||||
} ?: throw AssertionError("Reservation not found")
|
|
||||||
}
|
}
|
||||||
|
updatedReservation?.status shouldBe ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
||||||
}
|
}
|
||||||
|
|
||||||
test("다른 확정된 예약을 승인하면 예외 응답") {
|
test("다른 확정된 예약을 승인하면 예외 응답") {
|
||||||
val admin = login(MemberFixture.create(role = Role.ADMIN))
|
val admin = testDataHelper.createMember(role = Role.ADMIN)
|
||||||
val alreadyReserved = createSingleReservation(
|
login(admin)
|
||||||
|
val alreadyReserved = testDataHelper.createReservation(
|
||||||
member = admin,
|
member = admin,
|
||||||
status = ReservationStatus.CONFIRMED
|
status = ReservationStatus.CONFIRMED
|
||||||
)
|
)
|
||||||
|
|
||||||
val member = MemberFixture.create(account = "account", role = Role.MEMBER).also { it ->
|
val member = testDataHelper.createMember(role = Role.MEMBER)
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
val waiting = testDataHelper.createReservation(
|
||||||
entityManager.persist(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val waiting = ReservationFixture.create(
|
|
||||||
date = alreadyReserved.date,
|
date = alreadyReserved.date,
|
||||||
time = alreadyReserved.time,
|
time = alreadyReserved.time,
|
||||||
theme = alreadyReserved.theme,
|
theme = alreadyReserved.theme,
|
||||||
member = member,
|
member = member,
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
).also {
|
)
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
|
||||||
entityManager.persist(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val expectedError = ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS
|
val expectedError = ReservationErrorCode.CONFIRMED_RESERVATION_ALREADY_EXISTS
|
||||||
Given {
|
Given {
|
||||||
@ -636,7 +605,6 @@ class ReservationControllerTest(
|
|||||||
}.When {
|
}.When {
|
||||||
post("/reservations/waiting/${waiting.id!!}/confirm")
|
post("/reservations/waiting/${waiting.id!!}/confirm")
|
||||||
}.Then {
|
}.Then {
|
||||||
log().all()
|
|
||||||
statusCode(expectedError.httpStatus.value())
|
statusCode(expectedError.httpStatus.value())
|
||||||
body("code", equalTo(expectedError.errorCode))
|
body("code", equalTo(expectedError.errorCode))
|
||||||
}
|
}
|
||||||
@ -645,7 +613,7 @@ class ReservationControllerTest(
|
|||||||
|
|
||||||
context("POST /reservations/waiting/{id}/reject") {
|
context("POST /reservations/waiting/{id}/reject") {
|
||||||
test("관리자만 거절할 수 있다.") {
|
test("관리자만 거절할 수 있다.") {
|
||||||
login(MemberFixture.create(role = Role.MEMBER))
|
login(testDataHelper.createMember(role = Role.MEMBER))
|
||||||
val expectedError = AuthErrorCode.ACCESS_DENIED
|
val expectedError = AuthErrorCode.ACCESS_DENIED
|
||||||
|
|
||||||
Given {
|
Given {
|
||||||
@ -659,9 +627,8 @@ class ReservationControllerTest(
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("거절된 예약은 삭제된다.") {
|
test("거절된 예약은 삭제된다.") {
|
||||||
val member = login(MemberFixture.create(role = Role.ADMIN))
|
login(testDataHelper.createMember(role = Role.ADMIN))
|
||||||
val reservation = createSingleReservation(
|
val reservation = testDataHelper.createReservation(
|
||||||
member = member,
|
|
||||||
status = ReservationStatus.WAITING
|
status = ReservationStatus.WAITING
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -673,125 +640,91 @@ class ReservationControllerTest(
|
|||||||
statusCode(204)
|
statusCode(204)
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult { _ ->
|
val rejected = transactionTemplate.execute {
|
||||||
entityManager.find(
|
entityManager.find(ReservationEntity::class.java, reservation.id)
|
||||||
ReservationEntity::class.java,
|
|
||||||
reservation.id
|
|
||||||
) shouldBe null
|
|
||||||
}
|
}
|
||||||
|
rejected shouldBe null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createSingleReservation(
|
|
||||||
date: LocalDate = LocalDate.now().plusDays(1),
|
|
||||||
time: LocalTime = LocalTime.now(),
|
|
||||||
themeName: String = "Default Theme",
|
|
||||||
member: MemberEntity = MemberFixture.create(role = Role.MEMBER),
|
|
||||||
status: ReservationStatus = ReservationStatus.CONFIRMED_PAYMENT_REQUIRED
|
|
||||||
): ReservationEntity {
|
|
||||||
return ReservationFixture.create(
|
|
||||||
date = date,
|
|
||||||
theme = ThemeFixture.create(name = themeName),
|
|
||||||
time = TimeFixture.create(startAt = time),
|
|
||||||
member = member,
|
|
||||||
status = status
|
|
||||||
).also { it ->
|
|
||||||
transactionTemplate.execute { _ ->
|
|
||||||
if (member.id == null) {
|
|
||||||
entityManager.persist(member)
|
|
||||||
}
|
|
||||||
entityManager.persist(it.time)
|
|
||||||
entityManager.persist(it.theme)
|
|
||||||
entityManager.persist(it)
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createDummyReservations(): MutableMap<MemberEntity, MutableList<ReservationEntity>> {
|
|
||||||
val reservations: MutableMap<MemberEntity, MutableList<ReservationEntity>> = mutableMapOf()
|
|
||||||
val members: List<MemberEntity> = listOf(
|
|
||||||
MemberFixture.create(role = Role.MEMBER),
|
|
||||||
MemberFixture.create(role = Role.MEMBER)
|
|
||||||
)
|
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
|
||||||
members.forEach { member ->
|
|
||||||
entityManager.persist(member)
|
|
||||||
}
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
|
||||||
repeat(10) { index ->
|
|
||||||
val theme = ThemeFixture.create(name = "theme$index")
|
|
||||||
val time = TimeFixture.create(startAt = LocalTime.now().plusMinutes(index.toLong()))
|
|
||||||
entityManager.persist(theme)
|
|
||||||
entityManager.persist(time)
|
|
||||||
|
|
||||||
val reservation = ReservationFixture.create(
|
|
||||||
date = LocalDate.now().plusDays(index.toLong()),
|
|
||||||
theme = theme,
|
|
||||||
time = time,
|
|
||||||
member = members[index % members.size],
|
|
||||||
status = ReservationStatus.CONFIRMED
|
|
||||||
)
|
|
||||||
entityManager.persist(reservation)
|
|
||||||
reservations.getOrPut(reservation.member) { mutableListOf() }.add(reservation)
|
|
||||||
}
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
return reservations
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createRequest(
|
|
||||||
theme: ThemeEntity = ThemeFixture.create(),
|
|
||||||
time: TimeEntity = TimeFixture.create(),
|
|
||||||
): ReservationCreateWithPaymentRequest {
|
|
||||||
lateinit var reservationCreateWithPaymentRequest: ReservationCreateWithPaymentRequest
|
|
||||||
|
|
||||||
transactionTemplate.executeWithoutResult {
|
|
||||||
entityManager.persist(theme)
|
|
||||||
entityManager.persist(time)
|
|
||||||
|
|
||||||
reservationCreateWithPaymentRequest = ReservationFixture.createRequest(
|
|
||||||
themeId = theme.id!!,
|
|
||||||
timeId = time.id!!,
|
|
||||||
)
|
|
||||||
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
return reservationCreateWithPaymentRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
fun login(member: MemberEntity): MemberEntity {
|
|
||||||
if (member.id == null) {
|
|
||||||
transactionTemplate.executeWithoutResult {
|
|
||||||
entityManager.persist(member)
|
|
||||||
entityManager.flush()
|
|
||||||
entityManager.clear()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
every {
|
|
||||||
jwtHandler.getMemberIdFromToken(any())
|
|
||||||
} returns member.id!!
|
|
||||||
|
|
||||||
every {
|
|
||||||
memberService.findById(member.id!!)
|
|
||||||
} returns member
|
|
||||||
|
|
||||||
every {
|
|
||||||
memberIdResolver.resolveArgument(any(), any(), any(), any())
|
|
||||||
} returns member.id!!
|
|
||||||
|
|
||||||
return member
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TestDataHelper(
|
||||||
|
private val entityManager: EntityManager,
|
||||||
|
private val transactionTemplate: TransactionTemplate,
|
||||||
|
) {
|
||||||
|
private var memberSequence = 0L
|
||||||
|
private var themeSequence = 0L
|
||||||
|
private var timeSequence = 0L
|
||||||
|
|
||||||
|
fun createMember(
|
||||||
|
role: Role = Role.MEMBER,
|
||||||
|
account: String = "member${++memberSequence}@test.com",
|
||||||
|
): MemberEntity {
|
||||||
|
val member = MemberFixture.create(role = role, account = account)
|
||||||
|
return persist(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTheme(name: String = "theme-${++themeSequence}"): ThemeEntity {
|
||||||
|
val theme = ThemeFixture.create(name = name)
|
||||||
|
return persist(theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createTime(startAt: LocalTime = LocalTime.of(10, 0).plusMinutes(++timeSequence * 10)): TimeEntity {
|
||||||
|
val time = TimeFixture.create(startAt = startAt)
|
||||||
|
return persist(time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createReservation(
|
||||||
|
date: LocalDate = LocalDate.now().plusDays(1),
|
||||||
|
theme: ThemeEntity = createTheme(),
|
||||||
|
time: TimeEntity = createTime(),
|
||||||
|
member: MemberEntity = createMember(),
|
||||||
|
status: ReservationStatus = ReservationStatus.CONFIRMED,
|
||||||
|
): ReservationEntity {
|
||||||
|
val reservation = ReservationFixture.create(
|
||||||
|
date = date,
|
||||||
|
theme = theme,
|
||||||
|
time = time,
|
||||||
|
member = member,
|
||||||
|
status = status
|
||||||
|
)
|
||||||
|
return persist(reservation)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPayment(reservation: ReservationEntity): PaymentEntity {
|
||||||
|
val payment = PaymentFixture.create(reservation = reservation)
|
||||||
|
return persist(payment)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createReservationRequest(
|
||||||
|
theme: ThemeEntity = createTheme(),
|
||||||
|
time: TimeEntity = createTime(),
|
||||||
|
): ReservationCreateWithPaymentRequest {
|
||||||
|
return ReservationFixture.createRequest(
|
||||||
|
themeId = theme.id!!,
|
||||||
|
timeId = time.id!!,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDummyReservations(
|
||||||
|
memberCount: Int = 2,
|
||||||
|
reservationCount: Int = 10,
|
||||||
|
): Map<MemberEntity, List<ReservationEntity>> {
|
||||||
|
val members = (1..memberCount).map { createMember(role = Role.MEMBER) }
|
||||||
|
val reservations = (1..reservationCount).map { index ->
|
||||||
|
createReservation(
|
||||||
|
member = members[index % memberCount],
|
||||||
|
status = ReservationStatus.CONFIRMED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return reservations.groupBy { it.member }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> persist(entity: T): T {
|
||||||
|
transactionTemplate.executeWithoutResult {
|
||||||
|
entityManager.persist(entity)
|
||||||
|
}
|
||||||
|
return entity
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,12 +13,13 @@ import roomescape.theme.infrastructure.persistence.ThemeEntity
|
|||||||
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||||
import roomescape.theme.web.ThemeCreateRequest
|
import roomescape.theme.web.ThemeCreateRequest
|
||||||
import roomescape.theme.web.ThemeRetrieveResponse
|
import roomescape.theme.web.ThemeRetrieveResponse
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
import roomescape.util.ThemeFixture
|
import roomescape.util.ThemeFixture
|
||||||
|
|
||||||
class ThemeServiceTest : FunSpec({
|
class ThemeServiceTest : FunSpec({
|
||||||
|
|
||||||
val themeRepository: ThemeRepository = mockk()
|
val themeRepository: ThemeRepository = mockk()
|
||||||
val themeService = ThemeService(themeRepository)
|
val themeService = ThemeService(TsidFactory, themeRepository)
|
||||||
|
|
||||||
context("findThemeById") {
|
context("findThemeById") {
|
||||||
val themeId = 1L
|
val themeId = 1L
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
|||||||
import roomescape.theme.util.TestThemeCreateUtil
|
import roomescape.theme.util.TestThemeCreateUtil
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class ThemeRepositoryTest(
|
class ThemeRepositoryTest(
|
||||||
val themeRepository: ThemeRepository,
|
val themeRepository: ThemeRepository,
|
||||||
val entityManager: EntityManager
|
val entityManager: EntityManager
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import io.mockk.just
|
|||||||
import io.mockk.runs
|
import io.mockk.runs
|
||||||
import org.hamcrest.Matchers.equalTo
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
|
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
import roomescape.auth.exception.AuthErrorCode
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import roomescape.time.exception.TimeErrorCode
|
|||||||
import roomescape.time.exception.TimeException
|
import roomescape.time.exception.TimeException
|
||||||
import roomescape.time.infrastructure.persistence.TimeRepository
|
import roomescape.time.infrastructure.persistence.TimeRepository
|
||||||
import roomescape.time.web.TimeCreateRequest
|
import roomescape.time.web.TimeCreateRequest
|
||||||
|
import roomescape.util.TsidFactory
|
||||||
import roomescape.util.TimeFixture
|
import roomescape.util.TimeFixture
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ class TimeServiceTest : FunSpec({
|
|||||||
val reservationRepository: ReservationRepository = mockk()
|
val reservationRepository: ReservationRepository = mockk()
|
||||||
|
|
||||||
val timeService = TimeService(
|
val timeService = TimeService(
|
||||||
|
tsidFactory = TsidFactory,
|
||||||
timeRepository = timeRepository,
|
timeRepository = timeRepository,
|
||||||
reservationRepository = reservationRepository
|
reservationRepository = reservationRepository
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
|||||||
import roomescape.util.TimeFixture
|
import roomescape.util.TimeFixture
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
@DataJpaTest
|
@DataJpaTest(showSql = false)
|
||||||
class TimeRepositoryTest(
|
class TimeRepositoryTest(
|
||||||
val entityManager: EntityManager,
|
val entityManager: EntityManager,
|
||||||
val timeRepository: TimeRepository,
|
val timeRepository: TimeRepository,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import io.mockk.every
|
|||||||
import org.hamcrest.Matchers.equalTo
|
import org.hamcrest.Matchers.equalTo
|
||||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
import org.springframework.context.annotation.Import
|
import org.springframework.context.annotation.Import
|
||||||
|
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.test.web.servlet.MockMvc
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
@ -27,7 +28,6 @@ import java.time.LocalDate
|
|||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
@WebMvcTest(TimeController::class)
|
@WebMvcTest(TimeController::class)
|
||||||
@Import(JacksonConfig::class)
|
|
||||||
class TimeControllerTest(
|
class TimeControllerTest(
|
||||||
val mockMvc: MockMvc,
|
val mockMvc: MockMvc,
|
||||||
) : RoomescapeApiTest() {
|
) : RoomescapeApiTest() {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
package roomescape.util
|
package roomescape.util
|
||||||
|
|
||||||
|
import com.github.f4b6a3.tsid.TsidFactory
|
||||||
import roomescape.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.auth.web.LoginRequest
|
import roomescape.auth.web.LoginRequest
|
||||||
|
import roomescape.common.config.next
|
||||||
import roomescape.member.infrastructure.persistence.MemberEntity
|
import roomescape.member.infrastructure.persistence.MemberEntity
|
||||||
import roomescape.member.infrastructure.persistence.Role
|
import roomescape.member.infrastructure.persistence.Role
|
||||||
import roomescape.payment.infrastructure.client.PaymentApproveRequest
|
import roomescape.payment.infrastructure.client.PaymentApproveRequest
|
||||||
@ -20,11 +22,14 @@ import java.time.LocalDate
|
|||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
|
|
||||||
|
val TsidFactory: TsidFactory = TsidFactory(0)
|
||||||
|
|
||||||
object MemberFixture {
|
object MemberFixture {
|
||||||
const val NOT_LOGGED_IN_USERID: Long = 0
|
const val NOT_LOGGED_IN_USERID: Long = 0
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
name: String = "sangdol",
|
name: String = "sangdol",
|
||||||
account: String = "default",
|
account: String = "default",
|
||||||
password: String = "password",
|
password: String = "password",
|
||||||
@ -56,14 +61,14 @@ object MemberFixture {
|
|||||||
|
|
||||||
object TimeFixture {
|
object TimeFixture {
|
||||||
fun create(
|
fun create(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
startAt: LocalTime = LocalTime.now().plusHours(1),
|
startAt: LocalTime = LocalTime.now().plusHours(1),
|
||||||
): TimeEntity = TimeEntity(id, startAt)
|
): TimeEntity = TimeEntity(id, startAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
object ThemeFixture {
|
object ThemeFixture {
|
||||||
fun create(
|
fun create(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
name: String = "Default Theme",
|
name: String = "Default Theme",
|
||||||
description: String = "Default Description",
|
description: String = "Default Description",
|
||||||
thumbnail: String = "https://example.com/default-thumbnail.jpg"
|
thumbnail: String = "https://example.com/default-thumbnail.jpg"
|
||||||
@ -72,7 +77,7 @@ object ThemeFixture {
|
|||||||
|
|
||||||
object ReservationFixture {
|
object ReservationFixture {
|
||||||
fun create(
|
fun create(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
date: LocalDate = LocalDate.now().plusWeeks(1),
|
date: LocalDate = LocalDate.now().plusWeeks(1),
|
||||||
theme: ThemeEntity = ThemeFixture.create(),
|
theme: ThemeEntity = ThemeFixture.create(),
|
||||||
time: TimeEntity = TimeFixture.create(),
|
time: TimeEntity = TimeFixture.create(),
|
||||||
@ -125,14 +130,14 @@ object PaymentFixture {
|
|||||||
const val AMOUNT: Long = 10000L
|
const val AMOUNT: Long = 10000L
|
||||||
|
|
||||||
fun create(
|
fun create(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
orderId: String = ORDER_ID,
|
orderId: String = ORDER_ID,
|
||||||
paymentKey: String = PAYMENT_KEY,
|
paymentKey: String = PAYMENT_KEY,
|
||||||
totalAmount: Long = AMOUNT,
|
totalAmount: Long = AMOUNT,
|
||||||
reservation: ReservationEntity = ReservationFixture.create(id = 1L),
|
reservation: ReservationEntity = ReservationFixture.create(id = 1L),
|
||||||
approvedAt: OffsetDateTime = OffsetDateTime.now()
|
approvedAt: OffsetDateTime = OffsetDateTime.now()
|
||||||
): PaymentEntity = PaymentEntity(
|
): PaymentEntity = PaymentEntity(
|
||||||
id = id,
|
_id = id,
|
||||||
orderId = orderId,
|
orderId = orderId,
|
||||||
paymentKey = paymentKey,
|
paymentKey = paymentKey,
|
||||||
totalAmount = totalAmount,
|
totalAmount = totalAmount,
|
||||||
@ -141,14 +146,14 @@ object PaymentFixture {
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun createCanceled(
|
fun createCanceled(
|
||||||
id: Long? = null,
|
id: Long? = TsidFactory.next(),
|
||||||
paymentKey: String = PAYMENT_KEY,
|
paymentKey: String = PAYMENT_KEY,
|
||||||
cancelReason: String = "Test Cancel",
|
cancelReason: String = "Test Cancel",
|
||||||
cancelAmount: Long = AMOUNT,
|
cancelAmount: Long = AMOUNT,
|
||||||
approvedAt: OffsetDateTime = OffsetDateTime.now(),
|
approvedAt: OffsetDateTime = OffsetDateTime.now(),
|
||||||
canceledAt: OffsetDateTime = approvedAt.plusHours(1)
|
canceledAt: OffsetDateTime = approvedAt.plusHours(1)
|
||||||
): CanceledPaymentEntity = CanceledPaymentEntity(
|
): CanceledPaymentEntity = CanceledPaymentEntity(
|
||||||
id = id,
|
_id = id,
|
||||||
paymentKey = paymentKey,
|
paymentKey = paymentKey,
|
||||||
cancelReason = cancelReason,
|
cancelReason = cancelReason,
|
||||||
cancelAmount = cancelAmount,
|
cancelAmount = cancelAmount,
|
||||||
|
|||||||
@ -1,10 +1,16 @@
|
|||||||
package roomescape.util
|
package roomescape.util
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.github.f4b6a3.tsid.TsidFactory
|
||||||
import com.ninjasquad.springmockk.MockkBean
|
import com.ninjasquad.springmockk.MockkBean
|
||||||
import com.ninjasquad.springmockk.SpykBean
|
import com.ninjasquad.springmockk.SpykBean
|
||||||
import io.kotest.core.spec.style.BehaviorSpec
|
import io.kotest.core.spec.style.BehaviorSpec
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import org.springframework.boot.test.context.TestConfiguration
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Import
|
||||||
|
import org.springframework.context.annotation.Primary
|
||||||
|
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.http.HttpHeaders
|
import org.springframework.http.HttpHeaders
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
@ -21,6 +27,8 @@ import roomescape.member.infrastructure.persistence.MemberEntity
|
|||||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
import roomescape.util.MemberFixture.NOT_LOGGED_IN_USERID
|
import roomescape.util.MemberFixture.NOT_LOGGED_IN_USERID
|
||||||
|
|
||||||
|
@Import(TestConfig::class, JacksonConfig::class)
|
||||||
|
@MockkBean(JpaMetamodelMappingContext::class)
|
||||||
abstract class RoomescapeApiTest : BehaviorSpec() {
|
abstract class RoomescapeApiTest : BehaviorSpec() {
|
||||||
|
|
||||||
@SpykBean
|
@SpykBean
|
||||||
@ -128,3 +136,10 @@ abstract class RoomescapeApiTest : BehaviorSpec() {
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestConfiguration
|
||||||
|
class TestConfig {
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
fun tsidFactory(): TsidFactory = TsidFactory
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user