test #426

Merged
klaus merged 415 commits from test into main 2026-06-27 00:35:30 +00:00
3 changed files with 200 additions and 0 deletions
Showing only changes of commit c71f1ed17c - Show all commits

View File

@@ -0,0 +1,36 @@
package kr.co.vividnext.sodalive.v2.api.creator.channel.audio.application
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.v2.api.creator.channel.audio.dto.CreatorChannelAudioTabResponse
import kr.co.vividnext.sodalive.v2.creator.channel.audio.application.CreatorChannelAudioQueryService
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
@Service
@Transactional(readOnly = true)
class CreatorChannelAudioFacade(
private val creatorChannelAudioQueryService: CreatorChannelAudioQueryService
) {
fun getAudioTab(
creatorId: Long,
viewer: Member,
sort: String?,
themeId: Long?,
page: Int?,
size: Int?,
now: LocalDateTime = LocalDateTime.now()
): CreatorChannelAudioTabResponse {
return CreatorChannelAudioTabResponse.from(
creatorChannelAudioQueryService.getAudioTab(
creatorId = creatorId,
viewer = viewer,
sort = sort,
themeId = themeId,
page = page,
size = size,
now = now
)
)
}
}

View File

@@ -0,0 +1,54 @@
package kr.co.vividnext.sodalive.v2.api.creator.channel.audio.dto
import com.fasterxml.jackson.annotation.JsonProperty
import kr.co.vividnext.sodalive.v2.api.creator.channel.common.dto.CreatorChannelAudioContentResponse
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTab
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTheme
data class CreatorChannelAudioTabResponse(
val audioContentCount: Int,
val paidAudioContentCount: Int,
val purchasedAudioContentCount: Int,
val purchasedAudioContentRate: Double,
val themes: List<CreatorChannelAudioThemeResponse>,
val audioContents: List<CreatorChannelAudioContentResponse>,
val sort: ContentSort,
val themeId: Long?,
val page: Int,
val size: Int,
@JsonProperty("hasNext")
val hasNext: Boolean
) {
companion object {
fun from(tab: CreatorChannelAudioTab): CreatorChannelAudioTabResponse {
return CreatorChannelAudioTabResponse(
audioContentCount = tab.audioContentCount,
paidAudioContentCount = tab.paidAudioContentCount,
purchasedAudioContentCount = tab.purchasedAudioContentCount,
purchasedAudioContentRate = tab.purchasedAudioContentRate,
themes = tab.themes.map(CreatorChannelAudioThemeResponse::from),
audioContents = tab.audioContents.map(CreatorChannelAudioContentResponse::from),
sort = tab.sort,
themeId = tab.themeId,
page = tab.page.page,
size = tab.page.size,
hasNext = tab.hasNext
)
}
}
}
data class CreatorChannelAudioThemeResponse(
val themeId: Long,
val themeName: String
) {
companion object {
fun from(theme: CreatorChannelAudioTheme): CreatorChannelAudioThemeResponse {
return CreatorChannelAudioThemeResponse(
themeId = theme.themeId,
themeName = theme.themeName
)
}
}
}

View File

@@ -0,0 +1,110 @@
package kr.co.vividnext.sodalive.v2.api.creator.channel.audio.application
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.MemberRole
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
import kr.co.vividnext.sodalive.v2.creator.channel.audio.application.CreatorChannelAudioQueryService
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTab
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTheme
import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent
import kr.co.vividnext.sodalive.v2.creator.channel.live.domain.CreatorChannelPage
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import java.time.LocalDateTime
class CreatorChannelAudioFacadeTest {
@Test
@DisplayName("오디오 탭 facade는 query service 결과를 공개 응답 DTO로 변환한다")
fun shouldMapAudioTabQueryResultToPublicResponse() {
val service = Mockito.mock(CreatorChannelAudioQueryService::class.java)
val facade = CreatorChannelAudioFacade(service)
val viewer = createMember(id = 10L)
val now = LocalDateTime.of(2026, 6, 19, 10, 0)
Mockito.doReturn(createTab()).`when`(service).getAudioTab(
creatorId = 1L,
viewer = viewer,
sort = "OWNED",
themeId = 10L,
page = 0,
size = 20,
now = now
)
val response = facade.getAudioTab(
creatorId = 1L,
viewer = viewer,
sort = "OWNED",
themeId = 10L,
page = 0,
size = 20,
now = now
)
assertEquals(3, response.audioContentCount)
assertEquals(2, response.paidAudioContentCount)
assertEquals(1, response.purchasedAudioContentCount)
assertEquals(50.0, response.purchasedAudioContentRate)
assertEquals(10L, response.themes.first().themeId)
assertEquals("theme", response.themes.first().themeName)
assertEquals(201L, response.audioContents.first().audioContentId)
assertTrue(response.audioContents.first().isOwned)
assertFalse(response.audioContents.first().isRented)
assertEquals(ContentSort.OWNED, response.sort)
assertEquals(10L, response.themeId)
assertEquals(0, response.page)
assertEquals(20, response.size)
assertTrue(response.hasNext)
val json = ObjectMapper().registerModule(KotlinModule.Builder().build()).readTree(
ObjectMapper().registerModule(KotlinModule.Builder().build()).writeValueAsString(response)
)
assertTrue(json["hasNext"].asBoolean())
assertTrue(json["audioContents"][0]["isOwned"].asBoolean())
assertFalse(json["audioContents"][0]["isRented"].asBoolean())
}
private fun createMember(id: Long): Member {
return Member(
email = "viewer$id@test.com",
password = "password",
nickname = "viewer$id",
role = MemberRole.USER
).apply { this.id = id }
}
private fun createTab(): CreatorChannelAudioTab {
return CreatorChannelAudioTab(
audioContentCount = 3,
paidAudioContentCount = 2,
purchasedAudioContentCount = 1,
purchasedAudioContentRate = 50.0,
themes = listOf(CreatorChannelAudioTheme(themeId = 10L, themeName = "theme")),
audioContents = listOf(
CreatorChannelAudioContent(
audioContentId = 201L,
title = "audio",
duration = "00:10:00",
imageUrl = "audio.png",
price = 30,
isAdult = false,
isPointAvailable = true,
isFirstContent = true,
seriesName = "series",
isOriginalSeries = true,
isOwned = true,
isRented = false
)
),
sort = ContentSort.OWNED,
themeId = 10L,
page = CreatorChannelPage(page = 0, size = 20),
hasNext = true
)
}
}