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