feat(home-live): 라이브 추천 조회 정보를 확장한다

This commit is contained in:
2026-06-27 00:05:49 +09:00
parent 8ae48d7e67
commit 38595ee88a
4 changed files with 97 additions and 6 deletions

View File

@@ -62,7 +62,10 @@ class DefaultHomeRecommendationQueryRepository(
HomeLiveRecommendationRecord::class.java, HomeLiveRecommendationRecord::class.java,
liveRoom.id, liveRoom.id,
member.nickname, member.nickname,
member.profileImage member.profileImage,
liveRoom.title,
liveRoom.price,
liveRoom.beginDateTime
) )
) )
.from(liveRoom) .from(liveRoom)

View File

@@ -80,7 +80,10 @@ interface HomeRecommendationQueryPort {
data class HomeLiveRecommendationRecord( data class HomeLiveRecommendationRecord(
val liveRoomId: Long, val liveRoomId: Long,
val creatorNickname: String, val creatorNickname: String,
val creatorProfileImage: String? val creatorProfileImage: String?,
val title: String,
val price: Int,
val beginDateTime: LocalDateTime
) )
data class HomeBannerRecommendationRecord( data class HomeBannerRecommendationRecord(

View File

@@ -106,6 +106,66 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
assertEquals(listOf(oldest.id), page1.map { it.liveRoomId }) assertEquals(listOf(oldest.id), page1.map { it.liveRoomId })
} }
@Test
@DisplayName("라이브 추천 조회는 진행 중인 라이브의 제목, 가격, 시작 시간을 함께 반환한다")
fun shouldReturnLiveTitlePriceAndBeginDateTimeForOnAirLiveQuery() {
val beginDateTime = LocalDateTime.of(2026, 6, 26, 12, 30)
val viewer = saveMember("on-air-viewer", MemberRole.USER)
val creator = saveMember("on-air-creator", MemberRole.CREATOR)
val live = saveLiveRoom(
creator = creator,
beginDateTime = beginDateTime,
channelName = "channel",
title = "paid live",
price = 30
)
flushAndClear()
val lives = repository.findLiveRecommendations(
offset = 0,
limit = 1,
memberId = viewer.id,
includeAdultLives = true
)
assertEquals(listOf(live.id), lives.map { it.liveRoomId })
assertEquals("paid live", lives.single().title)
assertEquals(30, lives.single().price)
assertEquals(beginDateTime, lives.single().beginDateTime)
}
@Test
@DisplayName("진행 중 라이브 조회 정책은 활성 방송자, 채널명, 활성 라이브, 성인 노출, 차단 관계를 적용한다")
fun shouldApplyOnAirLiveVisibilityPolicy() {
val baseAt = LocalDateTime.of(2026, 6, 26, 12, 0)
val viewer = saveMember("policy-viewer", MemberRole.USER)
val visibleCreator = saveMember("policy-visible", MemberRole.CREATOR)
val inactiveCreator = saveMember("policy-inactive", MemberRole.CREATOR, isActive = false)
val viewerBlockedCreator = saveMember("policy-viewer-blocked", MemberRole.CREATOR)
val creatorBlockedViewer = saveMember("policy-creator-blocked", MemberRole.CREATOR)
val olderVisibleLive = saveLiveRoom(visibleCreator, baseAt, channelName = "older")
val newerVisibleLive = saveLiveRoom(visibleCreator, baseAt.plusMinutes(1), channelName = "newer")
saveLiveRoom(inactiveCreator, baseAt.plusMinutes(6), channelName = "inactive-creator")
saveLiveRoom(visibleCreator, baseAt.plusMinutes(5), channelName = "inactive-live", isActive = false)
saveLiveRoom(visibleCreator, baseAt.plusMinutes(5), channelName = null)
saveLiveRoom(visibleCreator, baseAt.plusMinutes(4), channelName = "")
saveLiveRoom(visibleCreator, baseAt.plusMinutes(3), channelName = "adult", isAdult = true)
saveLiveRoom(viewerBlockedCreator, baseAt.plusMinutes(2), channelName = "viewer-blocked")
saveLiveRoom(creatorBlockedViewer, baseAt.plusMinutes(2), channelName = "creator-blocked")
saveBlock(viewer, viewerBlockedCreator)
saveBlock(creatorBlockedViewer, viewer)
flushAndClear()
val lives = repository.findLiveRecommendations(
offset = 0,
limit = 10,
memberId = viewer.id,
includeAdultLives = false
)
assertEquals(listOf(newerVisibleLive.id, olderVisibleLive.id), lives.map { it.liveRoomId })
}
@Test @Test
@DisplayName("라이브 추천은 회원과 크리에이터의 양방향 차단 관계를 제외한다") @DisplayName("라이브 추천은 회원과 크리에이터의 양방향 차단 관계를 제외한다")
fun shouldExcludeBidirectionalBlockedCreatorsFromLiveRecommendations() { fun shouldExcludeBidirectionalBlockedCreatorsFromLiveRecommendations() {
@@ -2082,17 +2142,22 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
creator: Member, creator: Member,
beginDateTime: LocalDateTime, beginDateTime: LocalDateTime,
channelName: String?, channelName: String?,
isAdult: Boolean = false isAdult: Boolean = false,
title: String = "live-${creator.nickname}-$beginDateTime",
price: Int = 0,
isActive: Boolean = true
): LiveRoom { ): LiveRoom {
val room = LiveRoom( val room = LiveRoom(
title = "live-${creator.nickname}-$beginDateTime", title = title,
notice = "notice", notice = "notice",
beginDateTime = beginDateTime, beginDateTime = beginDateTime,
numberOfPeople = 0, numberOfPeople = 0,
isAdult = isAdult isAdult = isAdult,
price = price
) )
room.member = creator room.member = creator
room.channelName = channelName room.channelName = channelName
room.isActive = isActive
entityManager.persist(room) entityManager.persist(room)
return room return room
} }

View File

@@ -65,6 +65,23 @@ class HomeRecommendationQueryServiceTest {
assertEquals(port.liveRecommendations, recommendations) assertEquals(port.liveRecommendations, recommendations)
} }
@Test
@DisplayName("라이브 추천 조회는 paging과 성인 노출 여부를 조회 포트에 그대로 위임한다")
fun shouldDelegateLiveRecommendationQueryWithPagingAndAdultFlag() {
val recommendations = service.findLiveRecommendations(
offset = 40,
limit = 21,
memberId = 100L,
includeAdultLives = true
)
assertEquals(40, port.liveOffset)
assertEquals(21, port.liveLimit)
assertEquals(100L, port.liveMemberId)
assertEquals(true, port.liveIncludeAdultLives)
assertEquals(port.liveRecommendations, recommendations)
}
@Test @Test
@DisplayName("홈 배너 추천은 기본 20개를 활성 배너 조회 포트에 위임한다") @DisplayName("홈 배너 추천은 기본 20개를 활성 배너 조회 포트에 위임한다")
fun shouldFindHomeBannersWithDefaultLimit() { fun shouldFindHomeBannersWithDefaultLimit() {
@@ -628,7 +645,10 @@ class HomeRecommendationQueryServiceTest {
HomeLiveRecommendationRecord( HomeLiveRecommendationRecord(
liveRoomId = 1L, liveRoomId = 1L,
creatorNickname = "creator", creatorNickname = "creator",
creatorProfileImage = "profile.png" creatorProfileImage = "profile.png",
title = "live",
price = 10,
beginDateTime = LocalDateTime.of(2026, 6, 26, 12, 30)
) )
) )
val banners = listOf( val banners = listOf(