fix(recommend): 장르 추천에서 요청자를 제외한다

This commit is contained in:
2026-06-08 10:11:42 +09:00
parent a50f658333
commit 29db5c3fd0
3 changed files with 134 additions and 0 deletions

View File

@@ -1427,6 +1427,108 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
assertEquals(listOf(visibleCreator.id), recommendations.single().creators.map { it.creatorId })
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 요청자 본인만 있는 장르를 후보에서 제외한다")
fun shouldExcludeRequesterOnlyGenreFromGenreCreatorRecommendations() {
val viewer = saveMember("self-only-viewer", MemberRole.CREATOR)
val fallbackCreator = saveMember("self-only-fallback", MemberRole.CREATOR)
val selfTheme = saveTheme("self-only-theme")
val fallbackTheme = saveTheme("self-only-fallback-theme")
val selfContent = saveAudioContent(
viewer,
LocalDateTime.of(2026, 5, 30, 10, 0),
isActive = true,
theme = selfTheme
)
saveAudioContent(
fallbackCreator,
LocalDateTime.of(2026, 5, 30, 11, 0),
isActive = true,
theme = fallbackTheme
)
entityManager.persist(
CreatorContentViewHistory(
memberId = viewer.id!!,
contentId = selfContent.id!!,
genreId = 999L,
viewedAt = LocalDateTime.of(2026, 5, 31, 10, 0)
)
)
flushAndClear()
val recommendations = repository.findGenreCreatorRecommendations(
memberId = viewer.id!!,
includeAdultGenres = false,
genreLimit = 1,
creatorLimit = 8
)
assertEquals(listOf(fallbackTheme.id), recommendations.map { it.genreId })
assertEquals(listOf(fallbackCreator.id), recommendations.single().creators.map { it.creatorId })
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 요청자 본인을 제외한 뒤 대체 크리에이터로 8명을 채운다")
fun shouldBackfillCreatorAfterExcludingRequesterFromGenreCreatorRecommendations() {
val viewer = saveMember("self-backfill-viewer", MemberRole.CREATOR)
val theme = saveTheme("self-backfill-theme")
saveAudioContent(viewer, LocalDateTime.of(2026, 5, 30, 10, 0), isActive = true, theme = theme)
val expectedCreators = (0..8).map { index ->
saveMember("self-backfill-creator-$index", MemberRole.CREATOR).also { creator ->
saveAudioContent(
creator,
LocalDateTime.of(2026, 5, 30, 11, 0).plusMinutes(index.toLong()),
isActive = true,
theme = theme
)
}
}
flushAndClear()
val recommendations = repository.findGenreCreatorRecommendations(
memberId = viewer.id!!,
includeAdultGenres = false,
genreLimit = 1,
creatorLimit = 8
)
val creatorIds = recommendations.single().creators.map { it.creatorId }
assertEquals(8, creatorIds.size)
assertEquals(false, creatorIds.contains(viewer.id))
assertEquals(true, creatorIds.all { it in expectedCreators.map { creator -> creator.id } })
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 요청자 본인 제외 후 대체가 없으면 가능한 크리에이터만 응답한다")
fun shouldReturnAvailableCreatorsAfterExcludingRequesterFromGenreCreatorRecommendations() {
val viewer = saveMember("self-partial-viewer", MemberRole.CREATOR)
val theme = saveTheme("self-partial-theme")
saveAudioContent(viewer, LocalDateTime.of(2026, 5, 30, 10, 0), isActive = true, theme = theme)
val expectedCreators = (0 until 7).map { index ->
saveMember("self-partial-creator-$index", MemberRole.CREATOR).also { creator ->
saveAudioContent(
creator,
LocalDateTime.of(2026, 5, 30, 11, 0).plusMinutes(index.toLong()),
isActive = true,
theme = theme
)
}
}
flushAndClear()
val recommendations = repository.findGenreCreatorRecommendations(
memberId = viewer.id!!,
includeAdultGenres = false,
genreLimit = 1,
creatorLimit = 8
)
val creatorIds = recommendations.single().creators.map { it.creatorId }
assertEquals(7, creatorIds.size)
assertEquals(false, creatorIds.contains(viewer.id))
assertEquals(expectedCreators.map { it.id }.toSet(), creatorIds.toSet())
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 series_genre가 아니라 content_theme 기준으로 그룹을 만든다")
fun shouldGroupGenreCreatorRecommendationsByContentThemeNotSeriesGenre() {

View File

@@ -526,6 +526,35 @@ class HomeRecommendationQueryServiceTest {
assertEquals((101L..108L).toList(), recommendations[1].creators.map { it.creatorId })
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 장르의 추천 가능 크리에이터가 8명 미만이면 가능한 만큼 응답한다")
fun shouldReturnAvailableCreatorsWhenGenreCreatorCountIsUnderLimit() {
val availableCreators = (1L..7L).map { creatorId ->
HomeGenreCreatorRecommendationRecord(
creatorId = creatorId,
creatorNickname = "available-$creatorId",
creatorProfileImage = null
)
}
port.genreCreatorRecommendations = listOf(
HomeGenreCreatorRecommendationGroup(
genreId = 1L,
genreName = "partial-theme",
creators = availableCreators
)
)
val recommendations = service.findGenreCreatorRecommendations(
memberId = 100L,
includeAdultGenres = false,
genreLimit = 5,
creatorLimit = 8
)
assertEquals(listOf(1L), recommendations.map { it.genreId })
assertEquals((1L..7L).toList(), recommendations.single().creators.map { it.creatorId })
}
@Test
@DisplayName("장르 기반 크리에이터 추천은 조회 이력 장르는 중복 제거 후 8명 미만이어도 유지한다")
fun shouldKeepViewedThemeWhenCreatorDeduplicationMakesThemeUnderfilled() {