feat(content-ranking): 랭킹 공개 최근 소식을 발행한다
This commit is contained in:
+115
-2
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.ranking.application
|
||||
|
||||
import kr.co.vividnext.sodalive.v2.home.following.application.HomeFollowingNewsPublishService
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingSnapshotCandidate
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingType
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingAggregationPort
|
||||
@@ -11,6 +12,7 @@ import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.boot.test.system.CapturedOutput
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
@@ -165,16 +167,125 @@ class CreatorRankingSnapshotRefreshServiceTest {
|
||||
assertEquals(true, output.out.contains("error=aggregate failed"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("주간 스냅샷 저장 성공 후 크리에이터 랭킹 최근 소식을 순위와 함께 발행한다")
|
||||
fun shouldPublishCreatorRankingNewsAfterSnapshotsAreReplaced() {
|
||||
val aggregationPort = FakeCreatorRankingAggregationPort()
|
||||
val snapshotPort = FakeCreatorRankingSnapshotPort()
|
||||
val publishService = Mockito.mock(HomeFollowingNewsPublishService::class.java)
|
||||
val service = service(
|
||||
aggregationPort = aggregationPort,
|
||||
snapshotPort = snapshotPort,
|
||||
publishService = publishService
|
||||
)
|
||||
aggregationPort.candidates = listOf(
|
||||
candidate(creatorId = 1L, liveCanAmount = 200),
|
||||
candidate(creatorId = 2L, liveCanAmount = 100)
|
||||
)
|
||||
|
||||
service.refreshLastCompletedWeek(ZonedDateTime.of(2026, 6, 8, 6, 0, 0, 0, ZoneId.of("Asia/Seoul")))
|
||||
|
||||
Mockito.verify(publishService).publishCreatorRankingVisible(
|
||||
creatorId = 1L,
|
||||
creatorNickname = "creator-1",
|
||||
creatorProfileImagePath = "profile-1.png",
|
||||
aggregationStartAtUtc = LocalDateTime.of(2026, 5, 31, 15, 0),
|
||||
visibleFromAtUtc = LocalDateTime.of(2026, 6, 8, 0, 0),
|
||||
rank = 1
|
||||
)
|
||||
Mockito.verify(publishService).publishCreatorRankingVisible(
|
||||
creatorId = 2L,
|
||||
creatorNickname = "creator-2",
|
||||
creatorProfileImagePath = "profile-2.png",
|
||||
aggregationStartAtUtc = LocalDateTime.of(2026, 5, 31, 15, 0),
|
||||
visibleFromAtUtc = LocalDateTime.of(2026, 6, 8, 0, 0),
|
||||
rank = 2
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("주간 스냅샷 저장 실패 시 크리에이터 랭킹 최근 소식을 발행하지 않는다")
|
||||
fun shouldNotPublishCreatorRankingNewsWhenReplaceSnapshotsFails() {
|
||||
val aggregationPort = FakeCreatorRankingAggregationPort()
|
||||
val snapshotPort = FakeCreatorRankingSnapshotPort()
|
||||
val publishService = Mockito.mock(HomeFollowingNewsPublishService::class.java)
|
||||
val service = service(
|
||||
aggregationPort = aggregationPort,
|
||||
snapshotPort = snapshotPort,
|
||||
publishService = publishService
|
||||
)
|
||||
aggregationPort.candidates = listOf(candidate(creatorId = 1L, liveCanAmount = 100))
|
||||
snapshotPort.failure = IllegalStateException("replace failed")
|
||||
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
service.refreshLastCompletedWeek(ZonedDateTime.of(2026, 6, 8, 6, 0, 0, 0, ZoneId.of("Asia/Seoul")))
|
||||
}
|
||||
|
||||
Mockito.verifyNoInteractions(publishService)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("일부 크리에이터 랭킹 최근 소식 발행 실패는 스냅샷 갱신을 실패시키지 않는다")
|
||||
fun shouldNotFailSnapshotRefreshWhenCreatorRankingNewsPublishFails() {
|
||||
val aggregationPort = FakeCreatorRankingAggregationPort()
|
||||
val snapshotPort = FakeCreatorRankingSnapshotPort()
|
||||
val publishService = Mockito.mock(HomeFollowingNewsPublishService::class.java)
|
||||
val service = service(
|
||||
aggregationPort = aggregationPort,
|
||||
snapshotPort = snapshotPort,
|
||||
publishService = publishService
|
||||
)
|
||||
aggregationPort.candidates = listOf(
|
||||
candidate(creatorId = 1L, liveCanAmount = 200),
|
||||
candidate(creatorId = 2L, liveCanAmount = 100)
|
||||
)
|
||||
Mockito.doAnswer { invocation ->
|
||||
if (invocation.getArgument<Long>(0) == 1L) {
|
||||
throw IllegalStateException("publish failed")
|
||||
}
|
||||
0
|
||||
}.`when`(publishService)
|
||||
.publishCreatorRankingVisible(
|
||||
creatorId = Mockito.anyLong(),
|
||||
creatorNickname = anyStringValue(),
|
||||
creatorProfileImagePath = Mockito.anyString(),
|
||||
aggregationStartAtUtc = anyLocalDateTime(),
|
||||
visibleFromAtUtc = anyLocalDateTime(),
|
||||
rank = Mockito.anyInt()
|
||||
)
|
||||
|
||||
service.refreshLastCompletedWeek(ZonedDateTime.of(2026, 6, 8, 6, 0, 0, 0, ZoneId.of("Asia/Seoul")))
|
||||
|
||||
Mockito.verify(publishService).publishCreatorRankingVisible(
|
||||
creatorId = 2L,
|
||||
creatorNickname = "creator-2",
|
||||
creatorProfileImagePath = "profile-2.png",
|
||||
aggregationStartAtUtc = LocalDateTime.of(2026, 5, 31, 15, 0),
|
||||
visibleFromAtUtc = LocalDateTime.of(2026, 6, 8, 0, 0),
|
||||
rank = 2
|
||||
)
|
||||
}
|
||||
|
||||
private fun service(
|
||||
aggregationPort: CreatorRankingAggregationPort = FakeCreatorRankingAggregationPort(),
|
||||
snapshotPort: CreatorRankingSnapshotPort = FakeCreatorRankingSnapshotPort()
|
||||
snapshotPort: CreatorRankingSnapshotPort = FakeCreatorRankingSnapshotPort(),
|
||||
publishService: HomeFollowingNewsPublishService = Mockito.mock(HomeFollowingNewsPublishService::class.java)
|
||||
): CreatorRankingSnapshotRefreshService {
|
||||
return CreatorRankingSnapshotRefreshService(
|
||||
aggregationPort = aggregationPort,
|
||||
snapshotPort = snapshotPort
|
||||
snapshotPort = snapshotPort,
|
||||
homeFollowingNewsPublishService = publishService
|
||||
)
|
||||
}
|
||||
|
||||
private fun anyStringValue(): String {
|
||||
return Mockito.anyString() ?: ""
|
||||
}
|
||||
|
||||
private fun anyLocalDateTime(): LocalDateTime {
|
||||
return Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.MIN
|
||||
}
|
||||
|
||||
private fun candidate(
|
||||
creatorId: Long,
|
||||
finalScore: Double = 0.0,
|
||||
@@ -247,6 +358,7 @@ private class FakeCreatorRankingSnapshotPort : CreatorRankingSnapshotPort {
|
||||
var aggregationStartAtUtc: LocalDateTime? = null
|
||||
var aggregationEndAtUtc: LocalDateTime? = null
|
||||
var visibleFromAtUtc: LocalDateTime? = null
|
||||
var failure: RuntimeException? = null
|
||||
|
||||
override fun findSnapshotsByAggregationPeriod(
|
||||
aggregationStartAtUtc: LocalDateTime,
|
||||
@@ -281,6 +393,7 @@ private class FakeCreatorRankingSnapshotPort : CreatorRankingSnapshotPort {
|
||||
visibleFromAtUtc: LocalDateTime,
|
||||
newSnapshots: List<CreatorRankingSnapshotRecord>
|
||||
) {
|
||||
failure?.let { throw it }
|
||||
this.rankingType = rankingType
|
||||
this.aggregationStartAtUtc = aggregationStartAtUtc
|
||||
this.aggregationEndAtUtc = aggregationEndAtUtc
|
||||
|
||||
Reference in New Issue
Block a user