test #449
+4
-2
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.recommendation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendationSnapshotWindowPolicy
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
|
||||
@@ -29,7 +30,8 @@ class HomeRecommendationQueryService(
|
||||
private val aiCharacterSnapshotFallbackService: AiCharacterSnapshotFallbackPort? = null,
|
||||
private val cheerCreatorSnapshotFallbackService: CheerCreatorSnapshotFallbackPort? = null,
|
||||
private val popularCommunitySnapshotFallbackService: PopularCommunitySnapshotFallbackPort? = null,
|
||||
private val clock: Clock = Clock.systemUTC()
|
||||
private val clock: Clock = Clock.systemUTC(),
|
||||
private val langContext: LangContext
|
||||
) {
|
||||
private val snapshotWindowPolicy = RecommendationSnapshotWindowPolicy()
|
||||
|
||||
@@ -76,7 +78,7 @@ class HomeRecommendationQueryService(
|
||||
memberId: Long? = null,
|
||||
includeAdultContents: Boolean = false
|
||||
): List<HomeFirstAudioContentRecord> {
|
||||
return queryPort.findFirstAudioContents(now, offset, limit, memberId, includeAdultContents)
|
||||
return queryPort.findFirstAudioContents(now, offset, limit, memberId, includeAdultContents, langContext.lang.code)
|
||||
}
|
||||
|
||||
fun findAiCharacterRecommendations(
|
||||
|
||||
+2
-1
@@ -38,7 +38,8 @@ interface HomeRecommendationQueryPort {
|
||||
offset: Long = 0,
|
||||
limit: Int,
|
||||
memberId: Long? = null,
|
||||
includeAdultContents: Boolean = false
|
||||
includeAdultContents: Boolean = false,
|
||||
locale: String
|
||||
): List<HomeFirstAudioContentRecord>
|
||||
|
||||
fun findAiCharacterSnapshots(
|
||||
|
||||
+28
-16
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.recommendation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeAiCharacterRecommendationRecord
|
||||
@@ -27,7 +28,8 @@ import java.time.ZoneOffset
|
||||
class HomeRecommendationQueryServiceTest {
|
||||
private val port = FakeHomeRecommendationQueryPort()
|
||||
private val snapshotPort = FakeHomeRecommendationSnapshotPort()
|
||||
private val service = HomeRecommendationQueryService(port, snapshotPort)
|
||||
private val langContext = LangContext()
|
||||
private val service = HomeRecommendationQueryService(port, snapshotPort, langContext = langContext)
|
||||
|
||||
@Test
|
||||
@DisplayName("다시듣기 테마 콘텐츠는 AUDIO가 아니라 LIVE_REPLAY 활동으로 분류한다")
|
||||
@@ -152,6 +154,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
assertEquals(now, port.firstAudioNow)
|
||||
assertEquals(103L, port.firstAudioMemberId)
|
||||
assertEquals(10, port.firstAudioLimit)
|
||||
assertEquals(Lang.KO.code, port.firstAudioLocale)
|
||||
assertEquals(port.firstAudioContents, contents)
|
||||
}
|
||||
|
||||
@@ -159,7 +162,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@DisplayName("AI 캐릭터 추천은 최신 스냅샷 20개를 기준으로 순서를 유지해 상세를 조립한다")
|
||||
fun shouldFindAiCharactersFromLatestSnapshotsWithLimitAndDetails() {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(emptyList())
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
val oldSnapshotAt = LocalDateTime.of(2026, 5, 28, 23, 59, 59)
|
||||
val latestSnapshotAt = LocalDateTime.of(2026, 5, 29, 23, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -261,7 +264,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(
|
||||
listOf(snapshot(RecommendedSectionType.AI_CHARACTER, 10L, 10.0, LocalDateTime.of(2026, 7, 9, 14, 59, 59)))
|
||||
)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
port.aiCharacterDetails = listOf(
|
||||
HomeAiCharacterRecommendationRecord(
|
||||
characterId = 10L,
|
||||
@@ -286,7 +289,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@DisplayName("AI 캐릭터 추천은 fallback 후에도 스냅샷이 없으면 빈 배열을 반환한다")
|
||||
fun shouldReturnEmptyAiCharactersWhenFallbackDoesNotCreateSnapshots() {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(emptyList())
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
|
||||
val characters = service.findAiCharacterRecommendations()
|
||||
|
||||
@@ -302,7 +305,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(
|
||||
listOf(snapshot(RecommendedSectionType.AI_CHARACTER, 99L, 99.0, LocalDateTime.of(2026, 7, 9, 14, 59, 59)))
|
||||
)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.AI_CHARACTER,
|
||||
LocalDateTime.of(2026, 7, 9, 14, 59, 59),
|
||||
@@ -325,7 +328,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(
|
||||
listOf(snapshot(RecommendedSectionType.AI_CHARACTER, 99L, 99.0, LocalDateTime.of(2026, 7, 9, 14, 59, 59)))
|
||||
)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.AI_CHARACTER,
|
||||
@@ -352,7 +355,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
val fallback = FakeAiCharacterSnapshotFallbackPort(
|
||||
listOf(snapshot(RecommendedSectionType.AI_CHARACTER, 99L, 99.0, LocalDateTime.of(2026, 7, 9, 14, 59, 59)))
|
||||
)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback)
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, fallback, langContext = langContext)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.AI_CHARACTER,
|
||||
@@ -376,7 +379,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -419,7 +423,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
port.cheerCreatorDetails = listOf(
|
||||
HomeCheerCreatorRecommendationRecord(
|
||||
@@ -448,7 +453,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
val staleSnapshotAt = LocalDateTime.of(2026, 7, 8, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -483,7 +489,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.CHEER_CREATOR,
|
||||
@@ -502,7 +509,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("인기 커뮤니티 추천은 대상일 스냅샷 10개를 기준으로 크리에이터 중복을 제거하고 상세를 조립한다")
|
||||
fun shouldFindPopularCommunitiesFromTargetDaySnapshotsWithLimitDetailsAndCreatorUniqueness() {
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, clock = fixedClock())
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, clock = fixedClock(), langContext = langContext)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.POPULAR_COMMUNITY,
|
||||
@@ -576,7 +583,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("인기 커뮤니티 추천은 상위 스냅샷 중복 제거 후 뒤 후보로 기본 10개를 채운다")
|
||||
fun shouldBackfillPopularCommunitiesAfterRemovingDuplicateCreators() {
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, clock = fixedClock())
|
||||
val service = HomeRecommendationQueryService(port, snapshotPort, clock = fixedClock(), langContext = langContext)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.POPULAR_COMMUNITY,
|
||||
@@ -621,7 +628,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
popularCommunitySnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
val staleSnapshotAt = LocalDateTime.of(2026, 7, 8, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -666,7 +674,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
popularCommunitySnapshotFallbackService = fallback,
|
||||
clock = fixedClock()
|
||||
clock = fixedClock(),
|
||||
langContext = langContext
|
||||
)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.POPULAR_COMMUNITY,
|
||||
@@ -991,6 +1000,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
var firstAudioOffset: Long? = null
|
||||
var firstAudioMemberId: Long? = null
|
||||
var firstAudioIncludeAdultContents: Boolean? = null
|
||||
var firstAudioLocale: String? = null
|
||||
var aiCharacterDetailIds: List<Long> = emptyList()
|
||||
val aiCharacterDetailIdRequests = mutableListOf<List<Long>>()
|
||||
var randomAiCharacterExcludeIds: List<Long>? = null
|
||||
@@ -1121,13 +1131,15 @@ class HomeRecommendationQueryServiceTest {
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultContents: Boolean
|
||||
includeAdultContents: Boolean,
|
||||
locale: String
|
||||
): List<HomeFirstAudioContentRecord> {
|
||||
firstAudioNow = now
|
||||
firstAudioOffset = offset
|
||||
firstAudioLimit = limit
|
||||
firstAudioMemberId = memberId
|
||||
firstAudioIncludeAdultContents = includeAdultContents
|
||||
firstAudioLocale = locale
|
||||
return firstAudioContents
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user