feat(recommend): 홈 장르 추천 후보 조회를 보강한다
This commit is contained in:
@@ -1504,8 +1504,95 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("장르 기반 크리에이터 추천은 서비스 중복 제거용 후보 그룹을 genreLimit보다 많이 반환한다")
|
||||
fun shouldReturnMoreCandidateGroupsThanFinalGenreLimitForServiceDeduplicationBackfill() {
|
||||
@DisplayName("조회 이력이 없으면 크리에이터 8명을 채울 수 있는 콘텐츠 테마 후보를 먼저 반환한다")
|
||||
fun shouldRecommendFullRandomThemeCandidatesFirstWhenViewHistoryDoesNotExist() {
|
||||
repeat(5) { themeIndex ->
|
||||
val theme = saveTheme("no-history-underfilled-theme-$themeIndex")
|
||||
saveAudioContent(
|
||||
saveMember("no-history-underfilled-creator-$themeIndex", MemberRole.CREATOR),
|
||||
LocalDateTime.of(2026, 5, 30, 10, 0).plusMinutes(themeIndex.toLong()),
|
||||
isActive = true,
|
||||
theme = theme
|
||||
)
|
||||
}
|
||||
repeat(5) { themeIndex ->
|
||||
val theme = saveTheme("no-history-full-theme-$themeIndex")
|
||||
repeat(8) { creatorIndex ->
|
||||
saveAudioContent(
|
||||
saveMember("no-history-full-$themeIndex-creator-$creatorIndex", MemberRole.CREATOR),
|
||||
LocalDateTime.of(2026, 5, 30, 11, 0).plusMinutes((themeIndex * 10 + creatorIndex).toLong()),
|
||||
isActive = true,
|
||||
theme = theme
|
||||
)
|
||||
}
|
||||
}
|
||||
flushAndClear()
|
||||
|
||||
val recommendations = repository.findGenreCreatorRecommendations(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
)
|
||||
|
||||
assertEquals(true, recommendations.size >= 5)
|
||||
assertEquals(true, recommendations.take(5).all { it.genreName.startsWith("no-history-full-theme-") })
|
||||
assertEquals(true, recommendations.take(5).all { it.creators.size == 8 })
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("조회 이력 콘텐츠 테마는 8명이 되지 않아도 후보에 포함하고 부족한 장르는 8명 보유 테마 후보로 채운다")
|
||||
fun shouldKeepViewedThemeCandidateEvenWhenUnderfilledAndReturnFullRandomThemeCandidates() {
|
||||
val viewer = saveMember("viewed-partial-viewer", MemberRole.USER)
|
||||
val viewedTheme = saveTheme("viewed-partial-theme")
|
||||
val viewedContent = saveAudioContent(
|
||||
saveMember("viewed-partial-creator", MemberRole.CREATOR),
|
||||
LocalDateTime.of(2026, 5, 30, 10, 0),
|
||||
isActive = true,
|
||||
theme = viewedTheme
|
||||
)
|
||||
repeat(5) { themeIndex ->
|
||||
val theme = saveTheme("viewed-fill-full-theme-$themeIndex")
|
||||
repeat(8) { creatorIndex ->
|
||||
saveAudioContent(
|
||||
saveMember("viewed-fill-full-$themeIndex-creator-$creatorIndex", MemberRole.CREATOR),
|
||||
LocalDateTime.of(2026, 5, 30, 11, 0).plusMinutes((themeIndex * 10 + creatorIndex).toLong()),
|
||||
isActive = true,
|
||||
theme = theme
|
||||
)
|
||||
}
|
||||
}
|
||||
entityManager.persist(
|
||||
CreatorContentViewHistory(
|
||||
memberId = viewer.id!!,
|
||||
contentId = viewedContent.id!!,
|
||||
genreId = 999L,
|
||||
viewedAt = LocalDateTime.of(2026, 5, 31, 10, 0)
|
||||
)
|
||||
)
|
||||
flushAndClear()
|
||||
|
||||
val recommendations = repository.findGenreCreatorRecommendations(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
)
|
||||
|
||||
assertEquals(true, recommendations.size >= 5)
|
||||
assertEquals(true, recommendations.any { it.genreId == viewedTheme.id && it.creators.size == 1 })
|
||||
assertEquals(
|
||||
true,
|
||||
recommendations
|
||||
.filter { it.genreId != viewedTheme.id }
|
||||
.take(4)
|
||||
.all { it.genreName.startsWith("viewed-fill-full-theme-") && it.creators.size == 8 }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("장르 기반 크리에이터 추천 repository는 service 보충용 후보 그룹을 genreLimit보다 많이 반환한다")
|
||||
fun shouldReturnMoreCandidateGroupsThanFinalGenreLimitForServiceBackfill() {
|
||||
val sharedCreator = saveMember("candidate-shared", MemberRole.CREATOR)
|
||||
val backfillCreator = saveMember("candidate-backfill", MemberRole.CREATOR)
|
||||
val firstTheme = saveTheme("candidate-first-theme")
|
||||
|
||||
Reference in New Issue
Block a user