|
|
|
|
@@ -47,7 +47,7 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
@DisplayName("일 스냅샷 갱신은 전날 23시 59분 59초 기준으로 DB 점수 계산 스냅샷을 저장한다")
|
|
|
|
|
@DisplayName("일 스냅샷 갱신은 응원 크리에이터를 인기 커뮤니티와 같은 7일 window로 저장한다")
|
|
|
|
|
fun shouldRefreshDailySnapshotsWithPreviousDayEndSnapshotAt(output: CapturedOutput) {
|
|
|
|
|
val snapshotPort = FakeRecommendationSnapshotPort()
|
|
|
|
|
val queryPort = Mockito.mock(HomeRecommendationQueryPort::class.java)
|
|
|
|
|
@@ -71,7 +71,7 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
Mockito.`when`(queryPort.findCheerCreatorSnapshots(aiWindowStart, aiWindowEndExclusive, 16)).thenReturn(
|
|
|
|
|
Mockito.`when`(queryPort.findCheerCreatorSnapshots(windowStart, windowEndExclusive, 16)).thenReturn(
|
|
|
|
|
listOf(
|
|
|
|
|
RecommendationSnapshotRecord(
|
|
|
|
|
sectionType = RecommendedSectionType.CHEER_CREATOR,
|
|
|
|
|
@@ -112,7 +112,7 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
assertEquals(40.0, communitySnapshots.single().score, 0.0001)
|
|
|
|
|
|
|
|
|
|
Mockito.verify(queryPort).findAiCharacterSnapshots(aiWindowStart, aiWindowEndExclusive, 20)
|
|
|
|
|
Mockito.verify(queryPort).findCheerCreatorSnapshots(aiWindowStart, aiWindowEndExclusive, 16)
|
|
|
|
|
Mockito.verify(queryPort).findCheerCreatorSnapshots(windowStart, windowEndExclusive, 16)
|
|
|
|
|
Mockito.verify(queryPort).findPopularCommunitySnapshots(windowStart, windowEndExclusive, 20)
|
|
|
|
|
assertEquals(true, output.out.contains("event=recommendation_snapshot_refresh_success"))
|
|
|
|
|
assertEquals(true, output.out.contains("aiCharacterCount=1"))
|
|
|
|
|
@@ -135,8 +135,8 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
).thenReturn(emptyList())
|
|
|
|
|
Mockito.`when`(
|
|
|
|
|
queryPort.findCheerCreatorSnapshots(
|
|
|
|
|
LocalDateTime.of(2026, 5, 28, 15, 0, 0),
|
|
|
|
|
LocalDateTime.of(2026, 5, 29, 15, 0, 0),
|
|
|
|
|
windowStart,
|
|
|
|
|
windowEndExclusive,
|
|
|
|
|
16
|
|
|
|
|
)
|
|
|
|
|
).thenReturn(emptyList())
|
|
|
|
|
@@ -179,8 +179,8 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
)
|
|
|
|
|
Mockito.`when`(
|
|
|
|
|
queryPort.findCheerCreatorSnapshots(
|
|
|
|
|
LocalDateTime.of(2026, 5, 28, 15, 0, 0),
|
|
|
|
|
aiWindowEndExclusive,
|
|
|
|
|
windowStart,
|
|
|
|
|
windowEndExclusive,
|
|
|
|
|
16
|
|
|
|
|
)
|
|
|
|
|
).thenReturn(
|
|
|
|
|
@@ -229,8 +229,8 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
).thenReturn(emptyList())
|
|
|
|
|
Mockito.`when`(
|
|
|
|
|
queryPort.findCheerCreatorSnapshots(
|
|
|
|
|
LocalDateTime.of(2026, 5, 28, 15, 0, 0),
|
|
|
|
|
LocalDateTime.of(2026, 5, 29, 15, 0, 0),
|
|
|
|
|
windowStart,
|
|
|
|
|
windowEndExclusive,
|
|
|
|
|
16
|
|
|
|
|
)
|
|
|
|
|
).thenReturn(emptyList())
|
|
|
|
|
@@ -264,8 +264,6 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
val windowStart = LocalDateTime.of(2026, 5, 22, 15, 0, 0)
|
|
|
|
|
val windowEndExclusive = LocalDateTime.of(2026, 5, 29, 15, 0, 0)
|
|
|
|
|
val snapshotAt = LocalDateTime.of(2026, 5, 29, 14, 59, 59)
|
|
|
|
|
val cheerWindowStart = LocalDateTime.of(2026, 5, 28, 15, 0, 0)
|
|
|
|
|
val cheerWindowEndExclusive = LocalDateTime.of(2026, 5, 29, 15, 0, 0)
|
|
|
|
|
Mockito.`when`(redissonClient.getLock(RecommendationSnapshotFallbackService.AI_CHARACTER_LOCK_KEY)).thenReturn(aiLock)
|
|
|
|
|
Mockito.`when`(redissonClient.getLock(RecommendationSnapshotFallbackService.CHEER_CREATOR_LOCK_KEY)).thenReturn(cheerLock)
|
|
|
|
|
Mockito.`when`(redissonClient.getLock(RecommendationSnapshotFallbackService.POPULAR_COMMUNITY_LOCK_KEY))
|
|
|
|
|
@@ -276,7 +274,7 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
Mockito.`when`(cheerLock.isHeldByCurrentThread).thenReturn(true)
|
|
|
|
|
Mockito.`when`(popularLock.tryLock(0, -1, TimeUnit.MILLISECONDS)).thenReturn(true)
|
|
|
|
|
Mockito.`when`(popularLock.isHeldByCurrentThread).thenReturn(true)
|
|
|
|
|
Mockito.`when`(queryPort.findCheerCreatorSnapshots(cheerWindowStart, cheerWindowEndExclusive, 16)).thenReturn(
|
|
|
|
|
Mockito.`when`(queryPort.findCheerCreatorSnapshots(windowStart, windowEndExclusive, 16)).thenReturn(
|
|
|
|
|
listOf(snapshot(RecommendedSectionType.CHEER_CREATOR, targetId = 10L, score = 10.0, snapshotAt = snapshotAt))
|
|
|
|
|
)
|
|
|
|
|
Mockito.`when`(queryPort.findPopularCommunitySnapshots(windowStart, windowEndExclusive, 20)).thenReturn(emptyList())
|
|
|
|
|
@@ -285,7 +283,7 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
|
|
|
|
|
Mockito.verify(redissonClient).getLock(RecommendationSnapshotFallbackService.CHEER_CREATOR_LOCK_KEY)
|
|
|
|
|
Mockito.verify(cheerLock).tryLock(0, -1, TimeUnit.MILLISECONDS)
|
|
|
|
|
Mockito.verify(queryPort).findCheerCreatorSnapshots(cheerWindowStart, cheerWindowEndExclusive, 16)
|
|
|
|
|
Mockito.verify(queryPort).findCheerCreatorSnapshots(windowStart, windowEndExclusive, 16)
|
|
|
|
|
assertEquals(listOf(10L), snapshotPort.findLatestSnapshots(RecommendedSectionType.CHEER_CREATOR).map { it.targetId })
|
|
|
|
|
Mockito.verify(cheerLock).unlock()
|
|
|
|
|
Mockito.verify(popularLock).unlock()
|
|
|
|
|
@@ -322,8 +320,8 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
service.refreshDailySnapshots(now)
|
|
|
|
|
|
|
|
|
|
Mockito.verify(queryPort, Mockito.never()).findCheerCreatorSnapshots(
|
|
|
|
|
LocalDateTime.of(2026, 5, 28, 15, 0, 0),
|
|
|
|
|
LocalDateTime.of(2026, 5, 29, 15, 0, 0),
|
|
|
|
|
windowStart,
|
|
|
|
|
windowEndExclusive,
|
|
|
|
|
16
|
|
|
|
|
)
|
|
|
|
|
assertEquals(
|
|
|
|
|
@@ -361,8 +359,8 @@ class RecommendationSnapshotRefreshServiceTest {
|
|
|
|
|
Mockito.`when`(popularLock.isHeldByCurrentThread).thenReturn(true)
|
|
|
|
|
Mockito.`when`(
|
|
|
|
|
queryPort.findCheerCreatorSnapshots(
|
|
|
|
|
LocalDateTime.of(2026, 5, 28, 15, 0, 0),
|
|
|
|
|
LocalDateTime.of(2026, 5, 29, 15, 0, 0),
|
|
|
|
|
windowStart,
|
|
|
|
|
windowEndExclusive,
|
|
|
|
|
16
|
|
|
|
|
)
|
|
|
|
|
).thenReturn(
|
|
|
|
|
|