feat(content): 콘텐츠 전체보기 facade를 추가한다

This commit is contained in:
2026-06-27 06:41:06 +09:00
parent ef9ddae94b
commit 4e2b63acf4
2 changed files with 189 additions and 0 deletions
@@ -0,0 +1,117 @@
package kr.co.vividnext.sodalive.v2.api.content.overview.application
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
import kr.co.vividnext.sodalive.v2.api.content.overview.dto.ContentOverviewType
import kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryService
import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioCard
import kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryService
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeFirstAudioContentRecord
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import java.time.LocalDateTime
class ContentOverviewFacadeTest {
private val audioRecommendationQueryService = Mockito.mock(AudioRecommendationQueryService::class.java)
private val homeRecommendationQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
private val memberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
private val facade = ContentOverviewFacade(
audioRecommendationQueryService = audioRecommendationQueryService,
homeRecommendationQueryService = homeRecommendationQueryService,
memberContentPreferenceService = memberContentPreferenceService,
cloudFrontHost = "https://cdn.test",
queryPolicy = ContentOverviewQueryPolicy()
)
@Test
@DisplayName("New & Hot 전체보기는 size + 1 조회 결과를 공통 페이지 응답으로 변환한다")
fun shouldReturnNewAndHotPage() {
val member = member(id = 10L)
Mockito.doReturn((1L..21L).map { audioCard(it) }).`when`(audioRecommendationQueryService)
.findNewAndHotAudios(member, offset = 0L, limit = 21)
val response = facade.getContents("NEW_AND_HOT_AUDIO", page = 0, size = 20, member = member)
assertEquals(ContentOverviewType.NEW_AND_HOT_AUDIO, response.type)
assertEquals((1L..20L).toList(), response.items.map { it.contentId })
assertEquals("https://cdn.test/audio1.png", response.items[0].coverImage)
assertEquals(0, response.page)
assertEquals(20, response.size)
assertEquals(true, response.hasNext)
}
@Test
@DisplayName("첫 번째 오디오 콘텐츠 전체보기는 adult visibility와 offset을 반영해 조회한다")
fun shouldReturnFirstAudioContentPage() {
val member = member(id = 10L)
Mockito.doReturn(true).`when`(memberContentPreferenceService).canViewAdultContent(member)
Mockito.doReturn(listOf(firstAudio(1L), firstAudio(2L))).`when`(homeRecommendationQueryService)
.findFirstAudioContents(
anyLocalDateTime(),
eqValue(20L),
eqValue(21),
eqValue(member.id),
eqValue(true)
)
val response = facade.getContents("FIRST_AUDIO_CONTENT", page = 1, size = 20, member = member)
assertEquals(ContentOverviewType.FIRST_AUDIO_CONTENT, response.type)
assertEquals(listOf(1L, 2L), response.items.map { it.contentId })
assertEquals("https://cdn.test/cover/audio1.png", response.items[0].coverImage)
assertEquals(true, response.items[0].isFirstContent)
assertEquals(false, response.hasNext)
}
private fun member(id: Long): Member {
return Member(
email = "viewer$id@test.com",
password = "password",
nickname = "viewer$id",
role = MemberRole.USER
).apply {
this.id = id
}
}
private fun audioCard(id: Long): AudioCard {
return AudioCard(
audioContentId = id,
title = "audio$id",
duration = "00:01",
imageUrl = "https://cdn.test/audio$id.png",
price = id.toInt(),
isAdult = false,
isPointAvailable = true,
isFirstContent = true,
isOriginalSeries = false,
creatorNickname = "creator$id"
)
}
private fun anyLocalDateTime(): LocalDateTime {
return Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.of(2026, 6, 27, 0, 0)
}
private fun <T> eqValue(value: T): T {
return Mockito.eq(value) ?: value
}
private fun firstAudio(id: Long): HomeFirstAudioContentRecord {
return HomeFirstAudioContentRecord(
contentId = id,
creatorId = id + 100,
creatorNickname = "creator$id",
creatorProfileImage = null,
title = "first audio$id",
price = id.toInt(),
coverImage = "cover/audio$id.png",
isPointAvailable = true,
isAdult = false,
isOriginalSeries = false
)
}
}