Test #460
@@ -18,6 +18,7 @@ import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.LocalDateTime
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
data class GiftApplicationCommand(
|
||||
val recipientMemberId: Long,
|
||||
@@ -297,7 +298,7 @@ class GiftCommandService(
|
||||
throw invalidRequest()
|
||||
}
|
||||
val delivery = deliveryRepository.findByGiftIdForUpdate(gift.id ?: throw invalidRequest()) ?: throw invalidRequest()
|
||||
val deliveredAt = now()
|
||||
val deliveredAt = now().truncatedTo(ChronoUnit.SECONDS)
|
||||
|
||||
gift.status = GiftStatus.DELIVERED
|
||||
delivery.deliveredAt = deliveredAt
|
||||
|
||||
+53
@@ -22,6 +22,7 @@ import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import kr.co.vividnext.sodalive.v2.api.gift.dto.GiftDeliveryConfirmationResponse
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.Gift
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategory
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategoryRepository
|
||||
@@ -29,11 +30,13 @@ import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDelivery
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDeliveryRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReview
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReviewRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftSizePrice
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftSizePriceRepository
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.scheduler.GiftScheduler
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftAdminService
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftApplicationCommand
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftApplicationNoGenerator
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftCommandService
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftPushService
|
||||
import kr.co.vividnext.sodalive.v2.gift.application.GiftRecipientAddressRegistrationCommand
|
||||
@@ -55,6 +58,7 @@ import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.EnumSource
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.aop.framework.Advised
|
||||
import org.springframework.aop.support.AopUtils
|
||||
@@ -121,6 +125,8 @@ class AdminGiftControllerTest @Autowired constructor(
|
||||
private val sizePriceRepository: GiftSizePriceRepository,
|
||||
private val giftRepository: GiftRepository,
|
||||
private val giftDeliveryRepository: GiftDeliveryRepository,
|
||||
private val giftReviewRepository: GiftReviewRepository,
|
||||
private val applicationNoGenerator: GiftApplicationNoGenerator,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val chargeRepository: ChargeRepository,
|
||||
private val useCanRepository: UseCanRepository,
|
||||
@@ -592,6 +598,53 @@ class AdminGiftControllerTest @Autowired constructor(
|
||||
println("P16_CONFIRM_HTTP status=200 success=true rejected=true repeated=false senderPush=1 recipientPush=0")
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = [0, 123456789, 999999999])
|
||||
@DisplayName("수령 확인 시각은 나노초 입력에도 초 단위 DB 저장값과 응답이 일치한다")
|
||||
fun shouldPersistAndReturnSameSecondPrecisionDeliveryTime(nanos: Int) {
|
||||
val (gift, _) = saveAdminGift(
|
||||
applicationNo = APPLICATION_NO,
|
||||
status = GiftStatus.INSPECTION_COMPLETED,
|
||||
senderNickname = "precision-sender",
|
||||
recipientNickname = "precision-recipient",
|
||||
withTracking = true
|
||||
)
|
||||
val giftId = requireNotNull(gift.id)
|
||||
val fixedNow = LocalDateTime.of(2026, 10, 22, 23, 59, 59, nanos)
|
||||
val service = GiftCommandService(
|
||||
giftRepository = giftRepository,
|
||||
deliveryRepository = giftDeliveryRepository,
|
||||
reviewRepository = giftReviewRepository,
|
||||
categoryRepository = categoryRepository,
|
||||
sizePriceRepository = sizePriceRepository,
|
||||
memberRepository = memberRepository,
|
||||
applicationNoGenerator = applicationNoGenerator,
|
||||
canPaymentService = canPaymentService,
|
||||
giftPushService = giftPushService,
|
||||
now = { fixedNow }
|
||||
)
|
||||
|
||||
val result = requireNotNull(
|
||||
TransactionTemplate(transactionManager).execute {
|
||||
val recipient = memberRepository.findById(gift.recipientMemberId).orElseThrow()
|
||||
service.confirmDelivery(recipient, gift.applicationNo).also {
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
}
|
||||
}
|
||||
)
|
||||
val persisted = requireNotNull(giftDeliveryRepository.findByGiftId(giftId)?.deliveredAt)
|
||||
println(
|
||||
"P16_CONFIRM_PRECISION nanos=$nanos input=$fixedNow returned=${result.deliveredAt} " +
|
||||
"reloaded=$persisted expected=2026-10-22T23:59:59"
|
||||
)
|
||||
assertEquals(persisted, result.deliveredAt)
|
||||
assertEquals(LocalDateTime.of(2026, 10, 22, 23, 59, 59), persisted)
|
||||
assertEquals(0, persisted.nano)
|
||||
assertEquals("2026-10-22T23:59:59Z", GiftDeliveryConfirmationResponse.from(result).deliveredAt)
|
||||
assertEquals(GiftStatus.DELIVERED, giftRepository.findById(giftId).orElseThrow().status)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("실제 transactional 스케줄러 배송지 만료는 발신자만 한 번 알리고 재실행은 추가 알림을 보내지 않는다")
|
||||
fun shouldExpireRecipientAddressThroughTransactionalSchedulerAndNotifyOnlySenderOnce() {
|
||||
|
||||
Reference in New Issue
Block a user