feat(creatorname): v2 조회와 채팅에 언어별 이름을 적용한다
This commit is contained in:
+10
-3
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.content.all.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.configs.SecurityConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.jwt.JwtAccessDeniedHandler
|
||||
@@ -14,6 +15,7 @@ import kr.co.vividnext.sodalive.v2.api.content.all.application.MainContentAllFac
|
||||
import kr.co.vividnext.sodalive.v2.api.content.all.dto.MainContentAllTabResponse
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
import kr.co.vividnext.sodalive.v2.content.all.domain.MainContentAllType
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -41,6 +43,11 @@ class MainContentAllControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -57,7 +64,7 @@ class MainContentAllControllerTest @Autowired constructor(
|
||||
@DisplayName("전체 탭 조회는 비회원에게 200 OK와 기본 응답을 반환한다")
|
||||
fun shouldAllowAnonymousAndUseDefaultType() {
|
||||
Mockito.doReturn(response(MainContentAllType.AUDIO, ContentSort.LATEST)).`when`(facade)
|
||||
.getContents(null, null, null, null, null, null)
|
||||
.getContents(null, null, null, null, null, null, Lang.KO)
|
||||
|
||||
mockMvc.perform(get("/api/v2/audio/contents"))
|
||||
.andExpect(status().isOk)
|
||||
@@ -76,7 +83,7 @@ class MainContentAllControllerTest @Autowired constructor(
|
||||
role = MemberRole.USER
|
||||
).apply { id = 10L }
|
||||
Mockito.doReturn(response(MainContentAllType.SERIES, ContentSort.POPULAR)).`when`(facade)
|
||||
.getContents("SERIES", "POPULAR", "MON", 1, 30, member)
|
||||
.getContents("SERIES", "POPULAR", "MON", 1, 30, member, Lang.KO)
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/audio/contents")
|
||||
@@ -92,7 +99,7 @@ class MainContentAllControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.type").value("SERIES"))
|
||||
.andExpect(jsonPath("$.data.sort").value("POPULAR"))
|
||||
|
||||
Mockito.verify(facade).getContents("SERIES", "POPULAR", "MON", 1, 30, member)
|
||||
Mockito.verify(facade).getContents("SERIES", "POPULAR", "MON", 1, 30, member, Lang.KO)
|
||||
}
|
||||
|
||||
private fun response(type: MainContentAllType, sort: ContentSort): MainContentAllTabResponse {
|
||||
|
||||
+108
-3
@@ -10,12 +10,16 @@ import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDays
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import org.hamcrest.Matchers.contains
|
||||
import org.hamcrest.Matchers.nullValue
|
||||
import org.hibernate.SessionFactory
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
@@ -30,6 +34,7 @@ import javax.persistence.EntityManager
|
||||
properties = [
|
||||
"cloud.aws.cloud-front.host=https://cdn.test",
|
||||
"spring.cache.type=none",
|
||||
"spring.jpa.properties.hibernate.generate_statistics=true",
|
||||
"spring.datasource.url=jdbc:h2:mem:main-content-all-e2e;MODE=MySQL;NON_KEYWORDS=VALUE;DB_CLOSE_ON_EXIT=FALSE"
|
||||
]
|
||||
)
|
||||
@@ -39,8 +44,107 @@ import javax.persistence.EntityManager
|
||||
class MainContentAllEndToEndTest @Autowired constructor(
|
||||
private val mockMvc: MockMvc,
|
||||
private val entityManager: EntityManager,
|
||||
private val transactionTemplate: TransactionTemplate
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
private val jdbcTemplate: JdbcTemplate
|
||||
) {
|
||||
@Test
|
||||
@DisplayName("전체 콘텐츠 API는 JA 별칭을 우선하고 KO 별칭 미등록 시 일본어 원본을, 별칭 없는 작성자는 현재 원본을 반환한다")
|
||||
fun shouldSelectLocalizedCreatorNamesWithoutChangingAudioTitles() {
|
||||
transactionTemplate.executeWithoutResult { saveMember("main-all-resource-id-control", MemberRole.USER) }
|
||||
val localized = createAudioFixture("main-all-localized")
|
||||
val fallback = createAudioFixture("main-all-fallback")
|
||||
transactionTemplate.executeWithoutResult {
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
insert into creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at)
|
||||
values (?, 'JA', ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""".trimIndent(),
|
||||
localized.creatorId,
|
||||
"日本語クリエイター"
|
||||
)
|
||||
entityManager.find(Member::class.java, localized.creatorId).nickname = "改名さくら"
|
||||
}
|
||||
|
||||
mockMvc.perform(get("/api/v2/audio/contents").param("type", "AUDIO").header("Accept-Language", "ko"))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.totalCount").value(2))
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${localized.audioContentId})].creatorNickname")
|
||||
.value(contains("改名さくら"))
|
||||
)
|
||||
|
||||
val statistics = entityManager.entityManagerFactory.unwrap(SessionFactory::class.java).statistics
|
||||
statistics.clear()
|
||||
mockMvc.perform(get("/api/v2/audio/contents").param("type", "AUDIO").header("Accept-Language", "ja"))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.totalCount").value(2))
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${localized.audioContentId})].creatorNickname")
|
||||
.value(contains("日本語クリエイター"))
|
||||
)
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${fallback.audioContentId})].creatorNickname")
|
||||
.value(contains("main-all-fallback-creator"))
|
||||
)
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${localized.audioContentId})].title")
|
||||
.value(contains("main-all-localized-audio"))
|
||||
)
|
||||
.andExpect(jsonPath("$.data.audios[0].creatorId").doesNotExist())
|
||||
.andExpect(jsonPath("$.data.audios[0].creatorMemberId").doesNotExist())
|
||||
|
||||
val aliasQueries = statistics.queries.filter {
|
||||
Regex("""(?is)^select\s+\w+\.memberId,\s*\w+\.displayName\s+from\s+CreatorLocalizedNameEntity\b""")
|
||||
.containsMatchIn(it)
|
||||
}
|
||||
val aliasQueryCount = aliasQueries.sumOf { statistics.getQueryStatistics(it).executionCount }
|
||||
assertEquals(
|
||||
0L,
|
||||
aliasQueryCount,
|
||||
"Standalone alias SELECTs (total queries=${statistics.queryExecutionCount}): $aliasQueries"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("영어 활성 이름도 JOIN으로 읽으며 비활성 이름은 원본으로 fallback하고 인기순 집계를 유지한다")
|
||||
fun shouldReadActiveEnglishCreatorNameAndFallbackWhenInactive() {
|
||||
val active = createAudioFixture("main-all-english-active")
|
||||
val inactive = createAudioFixture("main-all-english-inactive")
|
||||
transactionTemplate.executeWithoutResult {
|
||||
listOf(Triple(active.creatorId, "English creator", true), Triple(inactive.creatorId, "Inactive name", false))
|
||||
.forEach { (creatorId, name, isActive) ->
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
insert into creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at)
|
||||
values (?, 'EN', ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""".trimIndent(),
|
||||
creatorId,
|
||||
name,
|
||||
isActive
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/audio/contents").param("type", "AUDIO").param("sort", "POPULAR").header("Accept-Language", "en")
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.totalCount").value(2))
|
||||
.andExpect(jsonPath("$.data.audios.length()").value(2))
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${active.audioContentId})].creatorNickname")
|
||||
.value(contains("English creator"))
|
||||
)
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${inactive.audioContentId})].creatorNickname")
|
||||
.value(contains("main-all-english-inactive-creator"))
|
||||
)
|
||||
.andExpect(
|
||||
jsonPath("$.data.audios[?(@.audioContentId == ${active.audioContentId})].title")
|
||||
.value(contains("main-all-english-active-audio"))
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("전체 탭 AUDIO API는 controller-service-repository를 거쳐 오디오 응답과 빈 series를 반환한다")
|
||||
fun shouldReturnAudioContentsThroughControllerServiceAndRepository() {
|
||||
@@ -196,7 +300,7 @@ class MainContentAllEndToEndTest @Autowired constructor(
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
|
||||
AudioFixture(audioContentId = audio.id!!)
|
||||
AudioFixture(audioContentId = audio.id!!, creatorId = creator.id!!)
|
||||
}!!
|
||||
}
|
||||
|
||||
@@ -308,7 +412,8 @@ class MainContentAllEndToEndTest @Autowired constructor(
|
||||
}
|
||||
|
||||
private data class AudioFixture(
|
||||
val audioContentId: Long
|
||||
val audioContentId: Long,
|
||||
val creatorId: Long
|
||||
)
|
||||
|
||||
private data class SeriesFixture(
|
||||
|
||||
+5
-3
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.content.all.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
@@ -36,7 +37,7 @@ class MainContentAllFacadeTest {
|
||||
page = MainContentPage(1, 30),
|
||||
hasNext = false
|
||||
)
|
||||
).`when`(queryService).getContents("FREE", "PRICE_LOW", "MON", 1, 30, member)
|
||||
).`when`(queryService).getContents("FREE", "PRICE_LOW", "MON", 1, 30, member, Lang.KO)
|
||||
|
||||
val response = facade.getContents(
|
||||
type = "FREE",
|
||||
@@ -44,10 +45,11 @@ class MainContentAllFacadeTest {
|
||||
dayOfWeek = "MON",
|
||||
page = 1,
|
||||
size = 30,
|
||||
member = member
|
||||
member = member,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
Mockito.verify(queryService).getContents("FREE", "PRICE_LOW", "MON", 1, 30, member)
|
||||
Mockito.verify(queryService).getContents("FREE", "PRICE_LOW", "MON", 1, 30, member, Lang.KO)
|
||||
assertEquals(MainContentAllType.FREE, response.type)
|
||||
assertEquals(ContentSort.PRICE_LOW, response.sort)
|
||||
}
|
||||
|
||||
+4
@@ -27,6 +27,7 @@ class MainContentAllTabResponseTest {
|
||||
audios = emptyList(),
|
||||
series = listOf(
|
||||
MainContentAllSeries(
|
||||
creatorMemberId = 100L,
|
||||
seriesId = 10L,
|
||||
title = "시리즈",
|
||||
coverImageUrl = "https://cdn/series.jpg",
|
||||
@@ -58,6 +59,7 @@ class MainContentAllTabResponseTest {
|
||||
totalCount = 1,
|
||||
audios = listOf(
|
||||
MainContentAllAudio(
|
||||
creatorMemberId = 100L,
|
||||
audioContentId = 1L,
|
||||
title = "audio",
|
||||
imageUrl = "https://cdn/audio.jpg",
|
||||
@@ -69,6 +71,7 @@ class MainContentAllTabResponseTest {
|
||||
creatorNickname = "creator"
|
||||
),
|
||||
MainContentAllAudio(
|
||||
creatorMemberId = 100L,
|
||||
audioContentId = 2L,
|
||||
title = "free audio",
|
||||
imageUrl = "https://cdn/free-audio.jpg",
|
||||
@@ -80,6 +83,7 @@ class MainContentAllTabResponseTest {
|
||||
creatorNickname = "creator"
|
||||
),
|
||||
MainContentAllAudio(
|
||||
creatorMemberId = 100L,
|
||||
audioContentId = 3L,
|
||||
title = "point unavailable audio",
|
||||
imageUrl = "https://cdn/point-unavailable-audio.jpg",
|
||||
|
||||
+10
-2
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.content.overview.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.configs.SecurityConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.jwt.JwtAccessDeniedHandler
|
||||
@@ -13,6 +14,7 @@ import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.content.overview.application.ContentOverviewFacade
|
||||
import kr.co.vividnext.sodalive.v2.api.content.overview.dto.ContentOverviewPageResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.content.overview.dto.ContentOverviewType
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -41,6 +43,11 @@ class ContentOverviewControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -62,7 +69,7 @@ class ContentOverviewControllerTest @Autowired constructor(
|
||||
fun shouldPassAuthenticatedMemberAndQueryParameters() {
|
||||
val member = member(id = 10L)
|
||||
Mockito.doReturn(emptyResponse(ContentOverviewType.FIRST_AUDIO_CONTENT)).`when`(facade)
|
||||
.getContents(eqValue("FIRST_AUDIO_CONTENT"), eqValue(1), eqValue(30), eqValue(member))
|
||||
.getContents(eqValue("FIRST_AUDIO_CONTENT"), eqValue(1), eqValue(30), eqValue(member), eqValue(Lang.KO))
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/contents")
|
||||
@@ -75,7 +82,8 @@ class ContentOverviewControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.data.type").value("FIRST_AUDIO_CONTENT"))
|
||||
|
||||
Mockito.verify(facade).getContents(eqValue("FIRST_AUDIO_CONTENT"), eqValue(1), eqValue(30), eqValue(member))
|
||||
Mockito.verify(facade)
|
||||
.getContents(eqValue("FIRST_AUDIO_CONTENT"), eqValue(1), eqValue(30), eqValue(member), eqValue(Lang.KO))
|
||||
}
|
||||
|
||||
private fun <T> eqValue(value: T): T {
|
||||
|
||||
+7
-4
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.content.overview.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
@@ -31,9 +32,9 @@ class ContentOverviewFacadeTest {
|
||||
fun shouldReturnNewAndHotPage() {
|
||||
val member = member(id = 10L)
|
||||
Mockito.doReturn((1L..21L).map { audioCard(it) }).`when`(audioRecommendationQueryService)
|
||||
.findNewAndHotAudios(member, offset = 0L, limit = 21)
|
||||
.findNewAndHotAudios(member, offset = 0L, limit = 21, lang = Lang.KO)
|
||||
|
||||
val response = facade.getContents("NEW_AND_HOT_AUDIO", page = 0, size = 20, member = member)
|
||||
val response = facade.getContents("NEW_AND_HOT_AUDIO", page = 0, size = 20, member = member, lang = Lang.KO)
|
||||
|
||||
assertEquals(ContentOverviewType.NEW_AND_HOT_AUDIO, response.type)
|
||||
assertEquals((1L..20L).toList(), response.items.map { it.contentId })
|
||||
@@ -54,10 +55,11 @@ class ContentOverviewFacadeTest {
|
||||
eqValue(20L),
|
||||
eqValue(21),
|
||||
eqValue(member.id),
|
||||
eqValue(true)
|
||||
eqValue(true),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
val response = facade.getContents("FIRST_AUDIO_CONTENT", page = 1, size = 20, member = member)
|
||||
val response = facade.getContents("FIRST_AUDIO_CONTENT", page = 1, size = 20, member = member, lang = Lang.KO)
|
||||
|
||||
assertEquals(ContentOverviewType.FIRST_AUDIO_CONTENT, response.type)
|
||||
assertEquals(listOf(1L, 2L), response.items.map { it.contentId })
|
||||
@@ -79,6 +81,7 @@ class ContentOverviewFacadeTest {
|
||||
|
||||
private fun audioCard(id: Long): AudioCard {
|
||||
return AudioCard(
|
||||
creatorMemberId = id + 100L,
|
||||
audioContentId = id,
|
||||
title = "audio$id",
|
||||
duration = "00:01",
|
||||
|
||||
+1
@@ -120,6 +120,7 @@ class ContentOverviewPageResponseTest {
|
||||
|
||||
private fun audioCard(price: Int, isPointAvailable: Boolean): AudioCard {
|
||||
return AudioCard(
|
||||
creatorMemberId = 10L,
|
||||
audioContentId = price.toLong() + 1,
|
||||
title = "audio",
|
||||
duration = "00:01",
|
||||
|
||||
+5
-3
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.content.ranking.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.v2.content.ranking.application.AudioRankingQueryService
|
||||
import kr.co.vividnext.sodalive.v2.content.ranking.domain.AudioRanking
|
||||
@@ -23,6 +24,7 @@ class AudioRankingFacadeTest {
|
||||
type = AudioRankingType.RISING,
|
||||
items = listOf(
|
||||
AudioRankingItem(
|
||||
creatorMemberId = 10L,
|
||||
contentId = 1L,
|
||||
title = "audio",
|
||||
creatorNickname = "creator",
|
||||
@@ -33,11 +35,11 @@ class AudioRankingFacadeTest {
|
||||
)
|
||||
)
|
||||
)
|
||||
Mockito.doReturn(ranking).`when`(queryService).getRankings(AudioRankingType.RISING, member)
|
||||
Mockito.doReturn(ranking).`when`(queryService).getRankings(AudioRankingType.RISING, member, Lang.KO)
|
||||
|
||||
val response = facade.getRankings(AudioRankingType.RISING, member)
|
||||
val response = facade.getRankings(AudioRankingType.RISING, member, Lang.KO)
|
||||
|
||||
Mockito.verify(queryService).getRankings(AudioRankingType.RISING, member)
|
||||
Mockito.verify(queryService).getRankings(AudioRankingType.RISING, member, Lang.KO)
|
||||
assertEquals(true, response.showRankChange)
|
||||
assertEquals(AudioRankingType.RISING, response.type)
|
||||
assertEquals(1, response.items.size)
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ class AudioRankingResponseTest {
|
||||
type = AudioRankingType.RISING,
|
||||
items = listOf(
|
||||
AudioRankingItem(
|
||||
creatorMemberId = 10L,
|
||||
contentId = 1001L,
|
||||
title = "rising audio",
|
||||
creatorNickname = "creator",
|
||||
|
||||
+10
-3
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.content.recommendation.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.configs.SecurityConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.jwt.JwtAccessDeniedHandler
|
||||
@@ -12,6 +13,7 @@ import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.content.recommendation.application.AudioRecommendationFacade
|
||||
import kr.co.vividnext.sodalive.v2.api.content.recommendation.dto.AudioRecommendationsResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -39,6 +41,11 @@ class AudioRecommendationControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -54,7 +61,7 @@ class AudioRecommendationControllerTest @Autowired constructor(
|
||||
@Test
|
||||
@DisplayName("오디오 추천 조회는 비회원에게 200 OK와 ApiResponse.ok wrapper를 반환한다")
|
||||
fun shouldReturnRecommendationsForAnonymous() {
|
||||
Mockito.doReturn(emptyResponse()).`when`(facade).getRecommendations(null)
|
||||
Mockito.doReturn(emptyResponse()).`when`(facade).getRecommendations(null, Lang.KO)
|
||||
|
||||
mockMvc.perform(get("/api/v2/audio/recommendations"))
|
||||
.andExpect(status().isOk)
|
||||
@@ -74,13 +81,13 @@ class AudioRecommendationControllerTest @Autowired constructor(
|
||||
nickname = "viewer",
|
||||
role = MemberRole.USER
|
||||
).apply { id = 10L }
|
||||
Mockito.doReturn(emptyResponse()).`when`(facade).getRecommendations(eqValue(member))
|
||||
Mockito.doReturn(emptyResponse()).`when`(facade).getRecommendations(eqValue(member), eqValue(Lang.KO))
|
||||
|
||||
mockMvc.perform(get("/api/v2/audio/recommendations").with(user(MemberAdapter(member))))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
|
||||
Mockito.verify(facade).getRecommendations(eqValue(member))
|
||||
Mockito.verify(facade).getRecommendations(eqValue(member), eqValue(Lang.KO))
|
||||
}
|
||||
|
||||
private fun emptyResponse(): AudioRecommendationsResponse {
|
||||
|
||||
+4
-2
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.content.recommendation.application
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.RecommendationBanner
|
||||
import kr.co.vividnext.sodalive.v2.content.recommendation.application.AudioRecommendationQueryService
|
||||
import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioCard
|
||||
@@ -20,9 +21,9 @@ class AudioRecommendationFacadeTest {
|
||||
@Test
|
||||
@DisplayName("facade는 도메인 추천 결과를 모든 공개 응답 필드로 변환한다")
|
||||
fun shouldConvertDomainRecommendationsToResponse() {
|
||||
Mockito.doReturn(domain()).`when`(queryService).getRecommendations(null)
|
||||
Mockito.doReturn(domain()).`when`(queryService).getRecommendations(null, Lang.KO)
|
||||
|
||||
val response = facade.getRecommendations(null)
|
||||
val response = facade.getRecommendations(null, Lang.KO)
|
||||
|
||||
assertEquals(1, response.banners.size)
|
||||
assertEquals(1, response.originalSeries.size)
|
||||
@@ -49,6 +50,7 @@ class AudioRecommendationFacadeTest {
|
||||
|
||||
private fun domain(): AudioRecommendations {
|
||||
val card = AudioCard(
|
||||
creatorMemberId = 10L,
|
||||
audioContentId = 1L,
|
||||
title = "audio",
|
||||
duration = "00:01",
|
||||
|
||||
+15
-4
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.audio.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -11,6 +12,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.audio.dto.CreatorChannelA
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.audio.dto.CreatorChannelAudioThemeResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.common.dto.CreatorChannelAudioContentResponse
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -47,6 +49,11 @@ class CreatorChannelAudioControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -88,7 +95,8 @@ class CreatorChannelAudioControllerTest @Autowired constructor(
|
||||
eqValue(null),
|
||||
eqValue(null),
|
||||
eqValue(null),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -118,7 +126,8 @@ class CreatorChannelAudioControllerTest @Autowired constructor(
|
||||
eqValue(null),
|
||||
eqValue(null),
|
||||
eqValue(null),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,7 +142,8 @@ class CreatorChannelAudioControllerTest @Autowired constructor(
|
||||
eqValue(999L),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -158,7 +168,8 @@ class CreatorChannelAudioControllerTest @Autowired constructor(
|
||||
eqValue(999L),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -2,6 +2,7 @@ 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.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
@@ -33,7 +34,8 @@ class CreatorChannelAudioFacadeTest {
|
||||
themeId = 10L,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getAudioTab(
|
||||
@@ -43,7 +45,8 @@ class CreatorChannelAudioFacadeTest {
|
||||
themeId = 10L,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(3, response.audioContentCount)
|
||||
|
||||
+29
-11
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.community.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -14,6 +15,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChan
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityRepliesResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityReplyResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -50,6 +52,11 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -89,7 +96,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -117,7 +125,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -130,7 +139,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -148,7 +158,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -169,7 +180,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
Mockito.doReturn(createDetailResponse()).`when`(facade).getCommunityPostDetail(
|
||||
eqValue(101L),
|
||||
eqValue(viewer),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -195,7 +207,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(0),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -222,7 +235,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -240,7 +254,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -253,7 +268,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(0),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -278,7 +294,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -296,7 +313,8 @@ class CreatorChannelCommunityControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+64
-1
@@ -22,6 +22,7 @@ import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.mock.mockito.MockBean
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
@@ -44,7 +45,8 @@ import javax.persistence.EntityManager
|
||||
class CreatorChannelCommunityEndToEndTest @Autowired constructor(
|
||||
private val mockMvc: MockMvc,
|
||||
private val entityManager: EntityManager,
|
||||
private val transactionTemplate: TransactionTemplate
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
private val jdbcTemplate: JdbcTemplate
|
||||
) {
|
||||
@MockBean
|
||||
private lateinit var audioContentCloudFront: AudioContentCloudFront
|
||||
@@ -52,6 +54,67 @@ class CreatorChannelCommunityEndToEndTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var creatorCommunityTranslationService: CreatorCommunityTranslationService
|
||||
|
||||
@Test
|
||||
@DisplayName("커뮤니티 상세의 JA 이름은 크리에이터 댓글과 최신 답글에만 적용하고 USER 이름은 유지한다")
|
||||
fun shouldLocalizeCreatorAuthorsAndLatestRepliesWithoutChangingUserNames() {
|
||||
val fixture = transactionTemplate.execute {
|
||||
val viewer = saveMember("community-localized-viewer", MemberRole.USER)
|
||||
val creator = saveMember("community-localized-creator", MemberRole.CREATOR)
|
||||
savePreference(viewer, isAdultContentVisible = true)
|
||||
val post = saveCommunity(creator, isFixed = false, price = 0, content = "localized-name community")
|
||||
val userComment = saveCommunityComment(viewer, post)
|
||||
val creatorComment = saveCommunityComment(creator, post)
|
||||
saveCommunityComment(creator, post, parent = userComment)
|
||||
entityManager.flush()
|
||||
listOf(creator.id!! to "日本語の投稿者", viewer.id!! to "USERには使わない名前").forEach { (memberId, name) ->
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
insert into creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at)
|
||||
values (?, 'JA', ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""".trimIndent(),
|
||||
memberId,
|
||||
name
|
||||
)
|
||||
}
|
||||
updateCommentCreatedAt(userComment.id!!, LocalDateTime.of(2026, 10, 14, 10, 0))
|
||||
updateCommentCreatedAt(creatorComment.id!!, LocalDateTime.of(2026, 10, 14, 11, 0))
|
||||
entityManager.clear()
|
||||
PostFixture(viewer = viewer, postId = post.id!!)
|
||||
}!!
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/creator-channels/community-posts/${fixture.postId}")
|
||||
.header("Accept-Language", "ja")
|
||||
.with(user(MemberAdapter(fixture.viewer)))
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.data.creatorNickname").value("日本語の投稿者"))
|
||||
.andExpect(jsonPath("$.data.content").value("localized-name community"))
|
||||
.andExpect(jsonPath("$.data.comments.comments.length()").value(2))
|
||||
.andExpect(jsonPath("$.data.comments.comments[0].writerNickname").value("日本語の投稿者"))
|
||||
.andExpect(jsonPath("$.data.comments.comments[1].writerId").value(fixture.viewer.id))
|
||||
.andExpect(jsonPath("$.data.comments.comments[1].writerNickname").value("community-localized-viewer"))
|
||||
.andExpect(jsonPath("$.data.comments.comments[1].latestReply.writerNickname").value("日本語の投稿者"))
|
||||
|
||||
transactionTemplate.executeWithoutResult {
|
||||
jdbcTemplate.update(
|
||||
"update creator_localized_name set display_name = ? where member_id = ? and lang = 'JA'",
|
||||
"deleted_表示名そのまま",
|
||||
entityManager.find(CreatorCommunity::class.java, fixture.postId).member!!.id!!
|
||||
)
|
||||
}
|
||||
mockMvc.perform(
|
||||
get("/api/v2/creator-channels/community-posts/${fixture.postId}")
|
||||
.header("Accept-Language", "ja")
|
||||
.with(user(MemberAdapter(fixture.viewer)))
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.creatorNickname").value("deleted_表示名そのまま"))
|
||||
.andExpect(jsonPath("$.data.comments.comments[0].writerNickname").value("deleted_表示名そのまま"))
|
||||
.andExpect(jsonPath("$.data.comments.comments[1].latestReply.writerNickname").value("deleted_表示名そのまま"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("커뮤니티 탭 API는 E2E로 정렬, fallback, 성인 필터, 유료 미디어 접근 정책을 반환한다")
|
||||
fun shouldReturnCommunityTabThroughControllerServiceAndRepository() {
|
||||
|
||||
+11
-8
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.creator.channel.community.application
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.community.dto.CreatorChannelCommunityTabResponse
|
||||
@@ -71,7 +72,8 @@ class CreatorChannelCommunityFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getCommunityTab(
|
||||
@@ -79,7 +81,8 @@ class CreatorChannelCommunityFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2, response.communityPostCount)
|
||||
@@ -99,9 +102,9 @@ class CreatorChannelCommunityFacadeTest {
|
||||
val facade = CreatorChannelCommunityFacade(service)
|
||||
val viewer = createMember(id = 10L)
|
||||
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||
Mockito.doReturn(createDetail()).`when`(service).getCommunityPostDetail(101L, viewer, now)
|
||||
Mockito.doReturn(createDetail()).`when`(service).getCommunityPostDetail(101L, viewer, now, Lang.KO)
|
||||
|
||||
val response = facade.getCommunityPostDetail(101L, viewer, now)
|
||||
val response = facade.getCommunityPostDetail(101L, viewer, now, Lang.KO)
|
||||
|
||||
assertEquals(101L, response.postId)
|
||||
assertTrue(response.isLiked)
|
||||
@@ -119,9 +122,9 @@ class CreatorChannelCommunityFacadeTest {
|
||||
val facade = CreatorChannelCommunityFacade(service)
|
||||
val viewer = createMember(id = 10L)
|
||||
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||
Mockito.doReturn(createComments()).`when`(service).getCommunityComments(101L, viewer, -1, 100, now)
|
||||
Mockito.doReturn(createComments()).`when`(service).getCommunityComments(101L, viewer, -1, 100, now, Lang.KO)
|
||||
|
||||
val response = facade.getCommunityComments(101L, viewer, -1, 100, now)
|
||||
val response = facade.getCommunityComments(101L, viewer, -1, 100, now, Lang.KO)
|
||||
|
||||
assertEquals(1, response.commentCount)
|
||||
assertEquals(0, response.page)
|
||||
@@ -139,9 +142,9 @@ class CreatorChannelCommunityFacadeTest {
|
||||
val facade = CreatorChannelCommunityFacade(service)
|
||||
val viewer = createMember(id = 10L)
|
||||
val now = LocalDateTime.of(2026, 7, 6, 12, 0)
|
||||
Mockito.doReturn(createReplies()).`when`(service).getCommunityReplies(201L, viewer, -1, 100, now)
|
||||
Mockito.doReturn(createReplies()).`when`(service).getCommunityReplies(201L, viewer, -1, 100, now, Lang.KO)
|
||||
|
||||
val response = facade.getCommunityReplies(201L, viewer, -1, 100, now)
|
||||
val response = facade.getCommunityReplies(201L, viewer, -1, 100, now, Lang.KO)
|
||||
|
||||
assertEquals(1, response.replyCount)
|
||||
assertEquals(201L, response.replies.first().commentId)
|
||||
|
||||
+11
-2
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.donation.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -10,6 +11,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.application.Crea
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto.CreatorChannelDonationResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto.CreatorChannelDonationTabResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto.MemberDonationRankingResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -46,6 +48,11 @@ class CreatorChannelDonationControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -85,7 +92,8 @@ class CreatorChannelDonationControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -117,7 +125,8 @@ class CreatorChannelDonationControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.creator.channel.donation.application
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.donation.dto.CreatorChannelDonationTabResponse
|
||||
@@ -10,6 +11,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.donation.domain.CreatorChanne
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.domain.CreatorChannelDonationRanking
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.donation.domain.CreatorChannelDonationTab
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.live.domain.CreatorChannelPage
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
@@ -57,7 +59,10 @@ class CreatorChannelDonationFacadeTest {
|
||||
@DisplayName("후원 탭 facade는 query service 결과를 공개 응답 DTO로 변환한다")
|
||||
fun shouldMapDonationTabQueryResultToPublicResponse() {
|
||||
val service = Mockito.mock(CreatorChannelDonationQueryService::class.java)
|
||||
val facade = CreatorChannelDonationFacade(service)
|
||||
val facade = CreatorChannelDonationFacade(
|
||||
service,
|
||||
Mockito.mock(CreatorLocalizedNameService::class.java)
|
||||
)
|
||||
val viewer = createMember(id = 10L)
|
||||
val now = LocalDateTime.of(2026, 6, 21, 12, 0)
|
||||
Mockito.doReturn(createTab()).`when`(service).getDonationTab(
|
||||
@@ -65,7 +70,8 @@ class CreatorChannelDonationFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getDonationTab(
|
||||
@@ -73,7 +79,8 @@ class CreatorChannelDonationFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(3, response.donationCount)
|
||||
@@ -106,6 +113,7 @@ class CreatorChannelDonationFacadeTest {
|
||||
),
|
||||
donations = listOf(
|
||||
CreatorChannelDonation(
|
||||
memberId = 10L,
|
||||
nickname = "donor",
|
||||
profileImageUrl = "https://cdn.test/donor.png",
|
||||
can = 50,
|
||||
|
||||
+11
-2
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -10,6 +11,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.application.Creat
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.dto.CreatorChannelFanTalkReplyResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.dto.CreatorChannelFanTalkResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.dto.CreatorChannelFanTalkTabResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -46,6 +48,11 @@ class CreatorChannelFanTalkControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -85,7 +92,8 @@ class CreatorChannelFanTalkControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -111,7 +119,8 @@ class CreatorChannelFanTalkControllerTest @Autowired constructor(
|
||||
eqValue(viewer),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.application
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.fantalk.dto.CreatorChannelFanTalkTabResponse
|
||||
@@ -59,7 +60,8 @@ class CreatorChannelFanTalkFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getFanTalkTab(
|
||||
@@ -67,7 +69,8 @@ class CreatorChannelFanTalkFacadeTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2, response.fanTalkCount)
|
||||
|
||||
+14
-3
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.home.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -21,6 +22,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelLiv
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSchedule
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSeries
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSns
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -57,6 +59,11 @@ class CreatorChannelHomeControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -94,7 +101,8 @@ class CreatorChannelHomeControllerTest @Autowired constructor(
|
||||
Mockito.doReturn(CreatorChannelHomeResponse.from(createHome())).`when`(facade).getHome(
|
||||
Mockito.eq(1L),
|
||||
Mockito.any(Member::class.java) ?: viewer,
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now()
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now(),
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -147,7 +155,8 @@ class CreatorChannelHomeControllerTest @Autowired constructor(
|
||||
Mockito.verify(facade).getHome(
|
||||
Mockito.eq(1L),
|
||||
Mockito.eq(viewer) ?: viewer,
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now()
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now(),
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
}
|
||||
|
||||
@@ -158,7 +167,8 @@ class CreatorChannelHomeControllerTest @Autowired constructor(
|
||||
Mockito.doReturn(CreatorChannelHomeResponse.from(createEmptyHome())).`when`(facade).getHome(
|
||||
Mockito.eq(1L),
|
||||
Mockito.any(Member::class.java) ?: viewer,
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now()
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now(),
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -244,6 +254,7 @@ class CreatorChannelHomeControllerTest @Autowired constructor(
|
||||
),
|
||||
channelDonations = listOf(
|
||||
CreatorChannelDonation(
|
||||
memberId = 20L,
|
||||
nickname = "fan",
|
||||
profileImageUrl = "fan.png",
|
||||
can = 50,
|
||||
|
||||
+11
-5
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.home.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
|
||||
@@ -39,13 +40,15 @@ class CreatorChannelHomeFacadeTest {
|
||||
Mockito.doReturn(createHome()).`when`(service).getHome(
|
||||
creatorId = 1L,
|
||||
viewer = viewer,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getHome(
|
||||
creatorId = 1L,
|
||||
viewer = viewer,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1L, response.creator.creatorId)
|
||||
@@ -90,21 +93,23 @@ class CreatorChannelHomeFacadeTest {
|
||||
Mockito.doReturn(createHome()).`when`(service).getHome(
|
||||
Mockito.eq(1L),
|
||||
Mockito.eq(viewer) ?: viewer,
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now()
|
||||
Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.now(),
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
|
||||
try {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"))
|
||||
val beforeUtc = LocalDateTime.now(ZoneOffset.UTC).minusSeconds(1)
|
||||
|
||||
facade.getHome(creatorId = 1L, viewer = viewer)
|
||||
facade.getHome(creatorId = 1L, viewer = viewer, lang = Lang.KO)
|
||||
|
||||
val afterUtc = LocalDateTime.now(ZoneOffset.UTC).plusSeconds(1)
|
||||
val nowCaptor = ArgumentCaptor.forClass(LocalDateTime::class.java)
|
||||
Mockito.verify(service).getHome(
|
||||
Mockito.eq(1L),
|
||||
Mockito.eq(viewer) ?: viewer,
|
||||
nowCaptor.capture() ?: LocalDateTime.MIN
|
||||
nowCaptor.capture() ?: LocalDateTime.MIN,
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
val capturedNow = nowCaptor.value
|
||||
assertTrue(!capturedNow.isBefore(beforeUtc), "captured now should be after UTC lower bound")
|
||||
@@ -180,6 +185,7 @@ class CreatorChannelHomeFacadeTest {
|
||||
),
|
||||
channelDonations = listOf(
|
||||
CreatorChannelDonation(
|
||||
memberId = 20L,
|
||||
nickname = "fan",
|
||||
profileImageUrl = "fan.png",
|
||||
can = 50,
|
||||
|
||||
+17
-5
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.live.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -11,6 +12,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.live.application.CreatorC
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.live.dto.CreatorChannelLiveResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.live.dto.CreatorChannelLiveTabResponse
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -47,6 +49,11 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -87,7 +94,8 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
eqValue(ContentSort.LATEST),
|
||||
eqValue(0),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -112,7 +120,8 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
eqValue(ContentSort.LATEST),
|
||||
eqValue(0),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -127,7 +136,8 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
eqValue(ContentSort.LATEST),
|
||||
eqValue(0),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -162,7 +172,8 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
eqValue(ContentSort.LATEST),
|
||||
eqValue(-1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -185,7 +196,8 @@ class CreatorChannelLiveControllerTest @Autowired constructor(
|
||||
eqValue(ContentSort.LATEST),
|
||||
eqValue(0),
|
||||
eqValue(0),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
|
||||
+5
-2
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.live.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
@@ -30,7 +31,8 @@ class CreatorChannelLiveFacadeTest {
|
||||
sort = ContentSort.LATEST,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getLiveTab(
|
||||
@@ -39,7 +41,8 @@ class CreatorChannelLiveFacadeTest {
|
||||
sort = ContentSort.LATEST,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1, response.liveReplayContentCount)
|
||||
|
||||
+15
-4
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.series.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -10,6 +11,7 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.series.application.Creato
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.series.dto.CreatorChannelSeriesResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.series.dto.CreatorChannelSeriesTabResponse
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -46,6 +48,11 @@ class CreatorChannelSeriesControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -86,7 +93,8 @@ class CreatorChannelSeriesControllerTest @Autowired constructor(
|
||||
eqValue("POPULAR"),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -118,7 +126,8 @@ class CreatorChannelSeriesControllerTest @Autowired constructor(
|
||||
eqValue("POPULAR"),
|
||||
eqValue(1),
|
||||
eqValue(20),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -132,7 +141,8 @@ class CreatorChannelSeriesControllerTest @Autowired constructor(
|
||||
eqValue("INVALID"),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
mockMvc.perform(
|
||||
@@ -153,7 +163,8 @@ class CreatorChannelSeriesControllerTest @Autowired constructor(
|
||||
eqValue("INVALID"),
|
||||
eqValue(-1),
|
||||
eqValue(100),
|
||||
anyValue(LocalDateTime.now())
|
||||
anyValue(LocalDateTime.now()),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.creator.channel.series.application
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.creator.channel.series.dto.CreatorChannelSeriesTabResponse
|
||||
@@ -63,7 +64,8 @@ class CreatorChannelSeriesFacadeTest {
|
||||
sort = "OWNED",
|
||||
page = 1,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val response = facade.getSeriesTab(
|
||||
@@ -72,7 +74,8 @@ class CreatorChannelSeriesFacadeTest {
|
||||
sort = "OWNED",
|
||||
page = 1,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2, response.seriesCount)
|
||||
|
||||
+46
-1
@@ -9,11 +9,13 @@ import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import kr.co.vividnext.sodalive.v2.ranking.adapter.out.persistence.CreatorRankingSnapshot
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingScoreSpec
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingType
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
@@ -37,8 +39,51 @@ import javax.persistence.EntityManager
|
||||
class CreatorRankingControllerTest @Autowired constructor(
|
||||
private val mockMvc: MockMvc,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val entityManager: EntityManager
|
||||
private val entityManager: EntityManager,
|
||||
private val jdbcTemplate: JdbcTemplate
|
||||
) {
|
||||
@Test
|
||||
@DisplayName("언어 중립 랭킹은 조회 언어의 현재 이름을 반환하고 저장된 스냅샷 이름은 변경하지 않는다")
|
||||
fun shouldRenderCurrentLocalizedNamesWithoutRewritingRankingSnapshots() {
|
||||
val localized = saveMember("ranking-localized-before", MemberRole.CREATOR)
|
||||
val fallback = saveMember("ranking-fallback-before", MemberRole.CREATOR)
|
||||
saveSnapshot(localized.id!!, "ranking-localized-before", null, rankNo = 1)
|
||||
saveSnapshot(fallback.id!!, "ranking-fallback-before", null, rankNo = 2)
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
insert into creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at)
|
||||
values (?, 'JA', ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""".trimIndent(),
|
||||
localized.id,
|
||||
"日本語ランキング名"
|
||||
)
|
||||
localized.nickname = "ranking-localized-current"
|
||||
fallback.nickname = "ranking-fallback-current"
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
|
||||
mockMvc.perform(get("/api/v2/home/rankings/creators").header("Accept-Language", "ja"))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.items[0].creatorId").value(localized.id))
|
||||
.andExpect(jsonPath("$.data.items[0].nickname").value("日本語ランキング名"))
|
||||
.andExpect(jsonPath("$.data.items[1].creatorId").value(fallback.id))
|
||||
.andExpect(jsonPath("$.data.items[1].nickname").value("ranking-fallback-current"))
|
||||
|
||||
mockMvc.perform(get("/api/v2/home/rankings/creators").header("Accept-Language", "ko"))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.items[0].nickname").value("ranking-localized-current"))
|
||||
.andExpect(jsonPath("$.data.items[1].nickname").value("ranking-fallback-current"))
|
||||
|
||||
assertEquals(
|
||||
listOf("ranking-localized-before", "ranking-fallback-before"),
|
||||
entityManager.createQuery(
|
||||
"select s.nickname from CreatorRankingSnapshot s order by s.rankNo",
|
||||
String::class.java
|
||||
).resultList
|
||||
)
|
||||
assertEquals("ranking-localized-current", memberRepository.findById(localized.id!!).get().nickname)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("크리에이터 랭킹 API는 공개 응답 스키마만 노출하고 내부 스냅샷 필드를 숨긴다")
|
||||
fun shouldReturnOnlyPublicCreatorRankingSchemaThroughEndpoint() {
|
||||
|
||||
+67
-10
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.home
|
||||
|
||||
import kr.co.vividnext.sodalive.chat.character.ChatCharacter
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoom
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -35,6 +36,7 @@ import org.springframework.boot.test.mock.mockito.MockBean
|
||||
import org.springframework.boot.test.system.CapturedOutput
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.web.servlet.MockMvc
|
||||
@@ -56,11 +58,50 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
private val mockMvc: MockMvc,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val creatorFollowingRepository: CreatorFollowingRepository,
|
||||
private val entityManager: EntityManager
|
||||
private val entityManager: EntityManager,
|
||||
private val jdbcTemplate: JdbcTemplate
|
||||
) {
|
||||
@MockBean
|
||||
private lateinit var creatorCommunityTranslationService: CreatorCommunityTranslationService
|
||||
|
||||
@Test
|
||||
@DisplayName("native 데뷔 크리에이터 조회도 JA 별칭을 우선하고 KO 별칭 미등록 시 현재 원본 이름을 반환한다")
|
||||
fun shouldLocalizeNativeDebutCreatorResultsByRequestLanguage() {
|
||||
val viewer = saveMember("localized-native-viewer", MemberRole.USER)
|
||||
val creator = saveMember("localized-native-before", MemberRole.CREATOR)
|
||||
saveLiveRoom(creator, LocalDateTime.now().minusDays(1), "localized-native-live", isAdult = false)
|
||||
entityManager.flush()
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
insert into creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at)
|
||||
values (?, 'JA', ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""".trimIndent(),
|
||||
creator.id,
|
||||
"日本語デビュー名"
|
||||
)
|
||||
creator.nickname = "localized-native-current"
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/home/recommendations/debut-creators")
|
||||
.header("Accept-Language", "ko")
|
||||
.with(user(MemberAdapter(viewer)))
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.items[0].creatorId").value(creator.id))
|
||||
.andExpect(jsonPath("$.data.items[0].creatorNickname").value("localized-native-current"))
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/home/recommendations/debut-creators")
|
||||
.header("Accept-Language", "ja")
|
||||
.with(user(MemberAdapter(viewer)))
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.items[0].creatorId").value(creator.id))
|
||||
.andExpect(jsonPath("$.data.items[0].creatorNickname").value("日本語デビュー名"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("추천 크리에이터 동시 팔로우 비로그인 요청은 Spring Security에서 거부한다")
|
||||
fun shouldRejectAnonymousFollowRequest() {
|
||||
@@ -328,12 +369,16 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
fun shouldLogHomeRecommendationFailure(output: CapturedOutput) {
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
Mockito.`when`(failingQueryService.findLiveRecommendations(limit = 20, memberId = null, includeAdultLives = false))
|
||||
val facade = HomeRecommendationFacade(
|
||||
failingQueryService,
|
||||
preferenceService,
|
||||
"https://cdn.test"
|
||||
)
|
||||
Mockito.`when`(failingQueryService.findLiveRecommendations(limit = 20, memberId = null, lang = Lang.KO))
|
||||
.thenThrow(IllegalStateException("home query failed"))
|
||||
|
||||
val exception = assertThrows(IllegalStateException::class.java) {
|
||||
facade.getHomeRecommendations(member = null)
|
||||
facade.getHomeRecommendations(member = null, lang = Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("home query failed", exception.message)
|
||||
@@ -366,7 +411,11 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
val member = saveMember("page-failure-viewer", MemberRole.USER)
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
val facade = HomeRecommendationFacade(
|
||||
failingQueryService,
|
||||
preferenceService,
|
||||
"https://cdn.test"
|
||||
)
|
||||
Mockito.`when`(preferenceService.canViewAdultContent(member)).thenReturn(false)
|
||||
Mockito.`when`(
|
||||
failingQueryService.findLiveRecommendations(
|
||||
@@ -375,13 +424,14 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
memberId = member.id,
|
||||
includeAdultLives = false,
|
||||
isViewerCreator = false,
|
||||
effectiveViewerGender = Gender.NONE
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
)
|
||||
.thenThrow(IllegalStateException("page query failed"))
|
||||
|
||||
val exception = assertThrows(IllegalStateException::class.java) {
|
||||
facade.getLives(member, page = 0, size = 20)
|
||||
facade.getLives(member, page = 0, size = 20, lang = Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("page query failed", exception.message)
|
||||
@@ -395,7 +445,11 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
val member = saveMember("other-page-failure-viewer", MemberRole.USER)
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
val facade = HomeRecommendationFacade(
|
||||
failingQueryService,
|
||||
preferenceService,
|
||||
"https://cdn.test"
|
||||
)
|
||||
Mockito.`when`(preferenceService.canViewAdultContent(member)).thenReturn(false)
|
||||
Mockito.`when`(
|
||||
failingQueryService.findRecentDebutCreators(
|
||||
@@ -403,13 +457,16 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
offset = Mockito.eq(0L),
|
||||
limit = Mockito.eq(21),
|
||||
memberId = Mockito.eq(member.id),
|
||||
includeAdultContents = Mockito.eq(false)
|
||||
includeAdultContents = Mockito.eq(false),
|
||||
lang = Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
).thenThrow(IllegalStateException("debut page failed"))
|
||||
Mockito.`when`(failingQueryService.findAiCharacterRecommendations(offset = 0L, limit = 21))
|
||||
.thenThrow(IllegalStateException("ai page failed"))
|
||||
|
||||
assertThrows(IllegalStateException::class.java) { facade.getRecentDebutCreators(member, page = 0, size = 20) }
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
facade.getRecentDebutCreators(member, page = 0, size = 20, lang = Lang.KO)
|
||||
}
|
||||
assertThrows(IllegalStateException::class.java) { facade.getAiCharacters(member, page = 0, size = 20) }
|
||||
|
||||
assertTrue(output.out.contains("section=DEBUT_CREATOR"))
|
||||
|
||||
+23
-15
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
@@ -35,11 +34,14 @@ class HomeRecommendationFacadeTest {
|
||||
private val queryService = HomeRecommendationQueryService(
|
||||
queryPort,
|
||||
EmptyRecommendationSnapshotPort(),
|
||||
langContext = LangContext(),
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
private val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
private val facade = HomeRecommendationFacade(queryService, preferenceService, "https://cdn.test")
|
||||
private val facade = HomeRecommendationFacade(
|
||||
queryService,
|
||||
preferenceService,
|
||||
"https://cdn.test"
|
||||
)
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 첫 오디오 응답은 무료 콘텐츠의 포인트 가능 여부를 false로 보정한다")
|
||||
@@ -50,7 +52,7 @@ class HomeRecommendationFacadeTest {
|
||||
firstAudio(price = 100, isPointAvailable = false)
|
||||
)
|
||||
|
||||
val response = facade.getHomeRecommendations(null)
|
||||
val response = facade.getHomeRecommendations(null, Lang.KO)
|
||||
|
||||
assertFalse(response.firstAudioContents[0].isPointAvailable)
|
||||
assertTrue(response.firstAudioContents[1].isPointAvailable)
|
||||
@@ -63,7 +65,7 @@ class HomeRecommendationFacadeTest {
|
||||
val member = Member(password = "password", nickname = "member").apply { id = 10L }
|
||||
Mockito.doReturn(true).`when`(preferenceService).canViewAdultContent(member)
|
||||
|
||||
facade.getHomeRecommendations(member)
|
||||
facade.getHomeRecommendations(member, Lang.KO)
|
||||
|
||||
assertTrue(queryPort.bannerIncludeAdultBanners)
|
||||
}
|
||||
@@ -74,7 +76,7 @@ class HomeRecommendationFacadeTest {
|
||||
val member = Member(password = "password", nickname = "jp-member").apply { id = 11L }
|
||||
Mockito.doReturn("JP").`when`(preferenceService).resolveCountryCode(member)
|
||||
|
||||
facade.getHomeRecommendations(member)
|
||||
facade.getHomeRecommendations(member, Lang.KO)
|
||||
|
||||
assertTrue(queryPort.bannerLang == Lang.JA)
|
||||
}
|
||||
@@ -84,7 +86,7 @@ class HomeRecommendationFacadeTest {
|
||||
fun shouldPassKoToHomeBannerQueryForNonJapan() {
|
||||
Mockito.doReturn("KR").`when`(preferenceService).resolveCountryCode(null)
|
||||
|
||||
facade.getHomeRecommendations(null)
|
||||
facade.getHomeRecommendations(null, Lang.KO)
|
||||
|
||||
assertTrue(queryPort.bannerLang == Lang.KO)
|
||||
}
|
||||
@@ -94,7 +96,7 @@ class HomeRecommendationFacadeTest {
|
||||
fun shouldPassCreatorRoleAndAuthGenderToHomeLiveQuery() {
|
||||
val member = createMember(id = 12L, role = MemberRole.CREATOR, gender = Gender.FEMALE, authGender = 1)
|
||||
|
||||
facade.getHomeRecommendations(member)
|
||||
facade.getHomeRecommendations(member, Lang.KO)
|
||||
|
||||
assertTrue(queryPort.liveIsViewerCreator == true)
|
||||
assertTrue(queryPort.liveEffectiveViewerGender == Gender.MALE)
|
||||
@@ -105,7 +107,7 @@ class HomeRecommendationFacadeTest {
|
||||
fun shouldPassCreatorRoleAndMemberGenderToLivePageQuery() {
|
||||
val member = createMember(id = 13L, role = MemberRole.CREATOR, gender = Gender.FEMALE)
|
||||
|
||||
facade.getLives(member, page = 0, size = 20)
|
||||
facade.getLives(member, page = 0, size = 20, lang = Lang.KO)
|
||||
|
||||
assertTrue(queryPort.liveIsViewerCreator == true)
|
||||
assertTrue(queryPort.liveEffectiveViewerGender == Gender.FEMALE)
|
||||
@@ -153,7 +155,8 @@ class HomeRecommendationFacadeTest {
|
||||
memberId: Long?,
|
||||
includeAdultLives: Boolean,
|
||||
isViewerCreator: Boolean,
|
||||
effectiveViewerGender: Gender?
|
||||
effectiveViewerGender: Gender?,
|
||||
lang: Lang
|
||||
): List<HomeLiveRecommendationRecord> {
|
||||
liveIsViewerCreator = isViewerCreator
|
||||
liveEffectiveViewerGender = effectiveViewerGender
|
||||
@@ -174,7 +177,8 @@ class HomeRecommendationFacadeTest {
|
||||
override fun findRecentlyActiveCreators(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultActivities: Boolean
|
||||
includeAdultActivities: Boolean,
|
||||
lang: Lang
|
||||
): List<RecentlyActiveCreatorRecord> = emptyList()
|
||||
|
||||
override fun findRecentDebutCreators(
|
||||
@@ -182,7 +186,8 @@ class HomeRecommendationFacadeTest {
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultContents: Boolean
|
||||
includeAdultContents: Boolean,
|
||||
lang: Lang
|
||||
): List<RecentDebutCreatorRecord> = emptyList()
|
||||
|
||||
override fun findFirstAudioContents(
|
||||
@@ -220,20 +225,23 @@ class HomeRecommendationFacadeTest {
|
||||
|
||||
override fun findCheerCreatorRecommendationDetails(
|
||||
creatorIds: List<Long>,
|
||||
memberId: Long?
|
||||
memberId: Long?,
|
||||
lang: Lang
|
||||
): List<HomeCheerCreatorRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findPopularCommunityRecommendationDetails(
|
||||
communityIds: List<Long>,
|
||||
memberId: Long?,
|
||||
includeAdultCommunities: Boolean
|
||||
includeAdultCommunities: Boolean,
|
||||
lang: Lang
|
||||
): List<HomePopularCommunityRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findGenreCreatorRecommendations(
|
||||
memberId: Long?,
|
||||
includeAdultGenres: Boolean,
|
||||
genreLimit: Int,
|
||||
creatorLimit: Int
|
||||
creatorLimit: Int,
|
||||
lang: Lang
|
||||
): List<HomeGenreCreatorRecommendationGroup> = emptyList()
|
||||
}
|
||||
|
||||
|
||||
+10
-3
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.home.following.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.configs.SecurityConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.jwt.JwtAccessDeniedHandler
|
||||
@@ -12,6 +13,7 @@ import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.home.following.application.HomeFollowingFacade
|
||||
import kr.co.vividnext.sodalive.v2.api.home.following.dto.HomeFollowingTabResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -39,6 +41,11 @@ class HomeFollowingControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -54,7 +61,7 @@ class HomeFollowingControllerTest @Autowired constructor(
|
||||
@Test
|
||||
@DisplayName("팔로잉 탭 조회는 비회원에게 200 OK와 로그인 필요 응답을 반환한다")
|
||||
fun shouldReturnLoginRequiredForAnonymous() {
|
||||
Mockito.doReturn(HomeFollowingTabResponse.loginRequired()).`when`(facade).getFollowingTab(null)
|
||||
Mockito.doReturn(HomeFollowingTabResponse.loginRequired()).`when`(facade).getFollowingTab(null, Lang.KO)
|
||||
|
||||
mockMvc.perform(get("/api/v2/home/following"))
|
||||
.andExpect(status().isOk)
|
||||
@@ -76,14 +83,14 @@ class HomeFollowingControllerTest @Autowired constructor(
|
||||
nickname = "viewer",
|
||||
role = MemberRole.USER
|
||||
).apply { id = 10L }
|
||||
Mockito.doReturn(loggedInEmptyResponse()).`when`(facade).getFollowingTab(eqValue(member))
|
||||
Mockito.doReturn(loggedInEmptyResponse()).`when`(facade).getFollowingTab(eqValue(member), eqValue(Lang.KO))
|
||||
|
||||
mockMvc.perform(get("/api/v2/home/following").with(user(MemberAdapter(member))))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
.andExpect(jsonPath("$.data.isLoginRequired").value(false))
|
||||
|
||||
Mockito.verify(facade).getFollowingTab(eqValue(member))
|
||||
Mockito.verify(facade).getFollowingTab(eqValue(member), eqValue(Lang.KO))
|
||||
}
|
||||
|
||||
private fun loggedInEmptyResponse(): HomeFollowingTabResponse {
|
||||
|
||||
+13
-7
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.following.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.chat.dto.ChatRoomListItemResponse
|
||||
@@ -24,12 +25,15 @@ import org.mockito.Mockito
|
||||
class HomeFollowingFacadeTest {
|
||||
private val queryService = Mockito.mock(HomeFollowingQueryService::class.java)
|
||||
private val chatRoomListService = Mockito.mock(ChatRoomListService::class.java)
|
||||
private val facade = HomeFollowingFacade(queryService, chatRoomListService)
|
||||
private val facade = HomeFollowingFacade(
|
||||
queryService,
|
||||
chatRoomListService
|
||||
)
|
||||
|
||||
@Test
|
||||
@DisplayName("비로그인 회원은 로그인 필요 응답을 반환하고 조회/채팅 서비스를 호출하지 않는다")
|
||||
fun shouldReturnLoginRequiredWithoutCallingServicesForAnonymous() {
|
||||
val response = facade.getFollowingTab(null)
|
||||
val response = facade.getFollowingTab(null, Lang.KO)
|
||||
|
||||
assertTrue(response.isLoginRequired)
|
||||
assertTrue(response.followingCreators.isEmpty())
|
||||
@@ -58,12 +62,12 @@ class HomeFollowingFacadeTest {
|
||||
lastMessage = "hello",
|
||||
lastMessageAt = "2026-06-25T01:00:00Z"
|
||||
)
|
||||
Mockito.doReturn(home).`when`(queryService).findHomeFollowing(member)
|
||||
Mockito.doReturn(home).`when`(queryService).findHomeFollowing(member, Lang.KO)
|
||||
Mockito.doReturn(ChatRoomListPageResponse(rooms = listOf(recentChat), hasMore = false, nextCursor = null))
|
||||
.`when`(chatRoomListService)
|
||||
.getRooms(member, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
.getRooms(member, Lang.KO, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
|
||||
val response = facade.getFollowingTab(member)
|
||||
val response = facade.getFollowingTab(member, Lang.KO)
|
||||
|
||||
assertFalse(response.isLoginRequired)
|
||||
assertEquals(1L, response.followingCreators.single().creatorId)
|
||||
@@ -71,9 +75,9 @@ class HomeFollowingFacadeTest {
|
||||
assertEquals(listOf(recentChat), response.recentChats)
|
||||
assertEquals("LIVE:4", response.monthlySchedules.single().scheduleId)
|
||||
assertEquals("news-5", response.recentNews.single().newsId)
|
||||
Mockito.verify(queryService).findHomeFollowing(member)
|
||||
Mockito.verify(queryService).findHomeFollowing(member, Lang.KO)
|
||||
Mockito.verify(chatRoomListService)
|
||||
.getRooms(member, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
.getRooms(member, Lang.KO, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
}
|
||||
|
||||
private fun homeFollowing(): HomeFollowing {
|
||||
@@ -87,6 +91,7 @@ class HomeFollowingFacadeTest {
|
||||
),
|
||||
onAirLives = listOf(
|
||||
HomeFollowingLive(
|
||||
creatorMemberId = 1L,
|
||||
liveId = 2L,
|
||||
creatorProfileImageUrl = "https://cdn.test/live.png",
|
||||
creatorNickname = "creator",
|
||||
@@ -110,6 +115,7 @@ class HomeFollowingFacadeTest {
|
||||
),
|
||||
recentNews = listOf(
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 1L,
|
||||
newsId = "news-5",
|
||||
type = FollowingNewsType.CREATOR_RANKING,
|
||||
visibleFromAtUtc = "2026-06-25T04:00:00Z",
|
||||
|
||||
+6
@@ -115,6 +115,7 @@ class HomeFollowingTabResponseTest {
|
||||
followingCreators = listOf(HomeFollowingCreator(1L, "creator", "https://cdn/profile.jpg")),
|
||||
onAirLives = listOf(
|
||||
HomeFollowingLive(
|
||||
creatorMemberId = 101L,
|
||||
liveId = 10L,
|
||||
creatorProfileImageUrl = "https://cdn/live-profile.jpg",
|
||||
creatorNickname = "live-creator",
|
||||
@@ -147,6 +148,7 @@ class HomeFollowingTabResponseTest {
|
||||
),
|
||||
recentNews = listOf(
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 1L,
|
||||
newsId = "30",
|
||||
type = FollowingNewsType.CREATOR_RANKING,
|
||||
visibleFromAtUtc = "2026-06-25T09:00:00Z",
|
||||
@@ -158,6 +160,7 @@ class HomeFollowingTabResponseTest {
|
||||
)
|
||||
),
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 2L,
|
||||
newsId = "31",
|
||||
type = FollowingNewsType.AUDIO_CONTENT,
|
||||
visibleFromAtUtc = "2026-06-26T00:00:00Z",
|
||||
@@ -170,6 +173,7 @@ class HomeFollowingTabResponseTest {
|
||||
)
|
||||
),
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 3L,
|
||||
newsId = "32",
|
||||
type = FollowingNewsType.PHOTO_CONTENT,
|
||||
visibleFromAtUtc = "2026-06-27T00:00:00Z",
|
||||
@@ -182,6 +186,7 @@ class HomeFollowingTabResponseTest {
|
||||
)
|
||||
),
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 4L,
|
||||
newsId = "33",
|
||||
type = FollowingNewsType.CONTENT_RANKING,
|
||||
visibleFromAtUtc = "2026-06-28T00:00:00Z",
|
||||
@@ -193,6 +198,7 @@ class HomeFollowingTabResponseTest {
|
||||
)
|
||||
),
|
||||
HomeFollowingNews(
|
||||
creatorMemberId = 5L,
|
||||
newsId = "34",
|
||||
type = FollowingNewsType.COMMUNITY_POST,
|
||||
visibleFromAtUtc = "2026-06-25T03:00:00Z",
|
||||
|
||||
+9
-2
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.api.home.live.adapter.`in`.web
|
||||
|
||||
import kr.co.vividnext.sodalive.common.CountryContext
|
||||
import kr.co.vividnext.sodalive.configs.SecurityConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.jwt.JwtAccessDeniedHandler
|
||||
@@ -13,6 +14,7 @@ import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.v2.api.home.live.application.HomeOnAirLiveFacade
|
||||
import kr.co.vividnext.sodalive.v2.api.home.live.dto.HomeOnAirLivePageResponse
|
||||
import kr.co.vividnext.sodalive.v2.api.home.live.dto.HomeOnAirLiveResponse
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
@@ -41,6 +43,11 @@ class HomeOnAirLiveControllerTest @Autowired constructor(
|
||||
@MockBean
|
||||
private lateinit var langContext: LangContext
|
||||
|
||||
@BeforeEach
|
||||
fun setUpLanguage() {
|
||||
Mockito.`when`(langContext.lang).thenReturn(Lang.KO)
|
||||
}
|
||||
|
||||
@MockBean
|
||||
private lateinit var sodaMessageSource: SodaMessageSource
|
||||
|
||||
@@ -61,7 +68,7 @@ class HomeOnAirLiveControllerTest @Autowired constructor(
|
||||
@DisplayName("현재 진행 중인 라이브 조회는 인증 회원과 page를 facade에 전달하고 성공 응답을 반환한다")
|
||||
fun shouldPassAuthenticatedMemberAndPageToFacade() {
|
||||
val member = createMember(100L)
|
||||
Mockito.doReturn(createResponse()).`when`(facade).getOnAirLives(eqValue(member), eqValue(2))
|
||||
Mockito.doReturn(createResponse()).`when`(facade).getOnAirLives(eqValue(member), eqValue(2), eqValue(Lang.KO))
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/home/on-air-lives")
|
||||
@@ -73,7 +80,7 @@ class HomeOnAirLiveControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.size").value(20))
|
||||
.andExpect(jsonPath("$.data.items[0].title").value("paid live"))
|
||||
|
||||
Mockito.verify(facade).getOnAirLives(eqValue(member), eqValue(2))
|
||||
Mockito.verify(facade).getOnAirLives(eqValue(member), eqValue(2), eqValue(Lang.KO))
|
||||
}
|
||||
|
||||
private fun createResponse() = HomeOnAirLivePageResponse(
|
||||
|
||||
+23
-11
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.live.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
@@ -16,7 +17,11 @@ import java.time.LocalDateTime
|
||||
class HomeOnAirLiveFacadeTest {
|
||||
private val queryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
private val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
private val facade = HomeOnAirLiveFacade(queryService, preferenceService, "https://cdn.test")
|
||||
private val facade = HomeOnAirLiveFacade(
|
||||
queryService,
|
||||
preferenceService,
|
||||
"https://cdn.test"
|
||||
)
|
||||
|
||||
@Test
|
||||
@DisplayName("현재 진행 중인 라이브 facade는 20개 고정 page와 hasNext를 조립한다")
|
||||
@@ -29,10 +34,11 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(true),
|
||||
eqValue(false),
|
||||
eqValue(Gender.NONE)
|
||||
eqValue(Gender.NONE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
val response = facade.getOnAirLives(member, page = 0)
|
||||
val response = facade.getOnAirLives(member, page = 0, lang = Lang.KO)
|
||||
|
||||
assertEquals(0, response.page)
|
||||
assertEquals(20, response.size)
|
||||
@@ -44,7 +50,8 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(true),
|
||||
eqValue(false),
|
||||
eqValue(Gender.NONE)
|
||||
eqValue(Gender.NONE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -59,10 +66,11 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(false),
|
||||
eqValue(false),
|
||||
eqValue(Gender.NONE)
|
||||
eqValue(Gender.NONE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
val response = facade.getOnAirLives(member, page = 0)
|
||||
val response = facade.getOnAirLives(member, page = 0, lang = Lang.KO)
|
||||
|
||||
assertEquals("https://cdn.test/profile/default-profile.png", response.items.single().creatorProfileImage)
|
||||
}
|
||||
@@ -79,10 +87,11 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(false),
|
||||
eqValue(false),
|
||||
eqValue(Gender.NONE)
|
||||
eqValue(Gender.NONE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
val response = facade.getOnAirLives(member, page = 0)
|
||||
val response = facade.getOnAirLives(member, page = 0, lang = Lang.KO)
|
||||
|
||||
assertEquals("2026-06-26T12:30:00Z", response.items.single().beginDateTimeUtc)
|
||||
}
|
||||
@@ -98,10 +107,11 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(true),
|
||||
eqValue(true),
|
||||
eqValue(Gender.MALE)
|
||||
eqValue(Gender.MALE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
|
||||
facade.getOnAirLives(member, page = 0)
|
||||
facade.getOnAirLives(member, page = 0, lang = Lang.KO)
|
||||
|
||||
Mockito.verify(queryService).findLiveRecommendations(
|
||||
eqValue(0L),
|
||||
@@ -109,7 +119,8 @@ class HomeOnAirLiveFacadeTest {
|
||||
eqValue(member.id),
|
||||
eqValue(true),
|
||||
eqValue(true),
|
||||
eqValue(Gender.MALE)
|
||||
eqValue(Gender.MALE),
|
||||
eqValue(Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,6 +129,7 @@ class HomeOnAirLiveFacadeTest {
|
||||
creatorProfileImage: String? = "profile.png",
|
||||
beginDateTime: LocalDateTime = LocalDateTime.of(2026, 6, 26, 12, 30)
|
||||
) = HomeLiveRecommendationRecord(
|
||||
creatorMemberId = id + 100L,
|
||||
liveRoomId = id,
|
||||
creatorNickname = "creator-$id",
|
||||
creatorProfileImage = creatorProfileImage,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.chat
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.v2.chat.controller.ChatRoomListController
|
||||
import kr.co.vividnext.sodalive.v2.chat.dto.ChatRoomListItemResponse
|
||||
@@ -21,7 +23,7 @@ class ChatRoomListControllerTest {
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
service = Mockito.mock(ChatRoomListService::class.java)
|
||||
controller = ChatRoomListController(service)
|
||||
controller = ChatRoomListController(service, LangContext())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -45,12 +47,12 @@ class ChatRoomListControllerTest {
|
||||
hasMore = false,
|
||||
nextCursor = null
|
||||
)
|
||||
Mockito.`when`(service.getRooms(member, "DM", "cursor", 10)).thenReturn(serviceResponse)
|
||||
Mockito.`when`(service.getRooms(member, Lang.KO, "DM", "cursor", 10)).thenReturn(serviceResponse)
|
||||
|
||||
val response = controller.getRooms(member = member, filter = "DM", cursor = "cursor", limit = 10)
|
||||
|
||||
assertTrue(response.success)
|
||||
assertEquals(serviceResponse, response.data)
|
||||
Mockito.verify(service).getRooms(member, "DM", "cursor", 10)
|
||||
Mockito.verify(service).getRooms(member, Lang.KO, "DM", "cursor", 10)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.v2.chat
|
||||
|
||||
import kr.co.vividnext.sodalive.chat.room.ChatMessageType
|
||||
import kr.co.vividnext.sodalive.chat.room.repository.ChatRoomRepository
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.v2.chat.dto.ChatRoomListQueryDto
|
||||
import kr.co.vividnext.sodalive.v2.chat.service.ChatRoomListService
|
||||
@@ -55,7 +56,7 @@ class ChatRoomListServiceTest {
|
||||
)
|
||||
)
|
||||
Mockito.`when`(
|
||||
dmRoomRepository.findDmChatListRooms(1L, null, null, null, false, PageRequest.of(0, 31))
|
||||
dmRoomRepository.findDmChatListRooms(1L, null, null, null, false, Lang.KO, PageRequest.of(0, 31))
|
||||
).thenReturn(
|
||||
listOf(
|
||||
ChatRoomListQueryDto(
|
||||
@@ -70,7 +71,7 @@ class ChatRoomListServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val response = service.getRooms(member, filter = "ALL", cursor = null, limit = 30)
|
||||
val response = service.getRooms(member, Lang.KO, filter = "ALL", cursor = null, limit = 30)
|
||||
|
||||
assertFalse(response.hasMore)
|
||||
assertEquals(listOf("DM", "AI"), response.rooms.map { it.chatType })
|
||||
@@ -85,7 +86,7 @@ class ChatRoomListServiceTest {
|
||||
fun shouldReturnOnlyDmRoomsWithVoicePreview() {
|
||||
val member = member(1L)
|
||||
Mockito.`when`(
|
||||
dmRoomRepository.findDmChatListRooms(1L, null, null, null, false, PageRequest.of(0, 31))
|
||||
dmRoomRepository.findDmChatListRooms(1L, null, null, null, false, Lang.KO, PageRequest.of(0, 31))
|
||||
).thenReturn(
|
||||
listOf(
|
||||
ChatRoomListQueryDto(
|
||||
@@ -100,7 +101,7 @@ class ChatRoomListServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val response = service.getRooms(member, filter = "DM", cursor = null, limit = 30)
|
||||
val response = service.getRooms(member, Lang.KO, filter = "DM", cursor = null, limit = 30)
|
||||
|
||||
assertEquals(1, response.rooms.size)
|
||||
assertEquals("DM", response.rooms[0].chatType)
|
||||
@@ -128,7 +129,7 @@ class ChatRoomListServiceTest {
|
||||
aiRoomRepository.findAiChatListRooms(1L, null, null, null, false, PageRequest.of(0, 31))
|
||||
).thenReturn(rows)
|
||||
|
||||
val response = service.getRooms(member, filter = "AI", cursor = null, limit = 30)
|
||||
val response = service.getRooms(member, Lang.KO, filter = "AI", cursor = null, limit = 30)
|
||||
|
||||
assertEquals(30, response.rooms.size)
|
||||
assertTrue(response.hasMore)
|
||||
@@ -157,7 +158,7 @@ class ChatRoomListServiceTest {
|
||||
)
|
||||
)
|
||||
Mockito.`when`(
|
||||
dmRoomRepository.findDmChatListRooms(1L, cursorAt, "DM", 20L, false, PageRequest.of(0, 31))
|
||||
dmRoomRepository.findDmChatListRooms(1L, cursorAt, "DM", 20L, false, Lang.KO, PageRequest.of(0, 31))
|
||||
).thenReturn(
|
||||
listOf(
|
||||
ChatRoomListQueryDto(
|
||||
@@ -181,7 +182,7 @@ class ChatRoomListServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val response = service.getRooms(member, filter = "ALL", cursor = "2026-05-14T12:00:00:DM:20", limit = 30)
|
||||
val response = service.getRooms(member, Lang.KO, filter = "ALL", cursor = "2026-05-14T12:00:00:DM:20", limit = 30)
|
||||
|
||||
assertEquals(listOf(30L, 10L), response.rooms.map { it.roomId })
|
||||
assertEquals("https://cdn.test/profile/default-profile.png", response.rooms[0].targetImageUrl)
|
||||
@@ -194,13 +195,13 @@ class ChatRoomListServiceTest {
|
||||
val pageable = PageRequest.of(0, 11)
|
||||
Mockito.`when`(aiRoomRepository.findAiChatListRooms(1L, null, null, null, true, pageable))
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(dmRoomRepository.findDmChatListRooms(1L, null, null, null, true, pageable))
|
||||
Mockito.`when`(dmRoomRepository.findDmChatListRooms(1L, null, null, null, true, Lang.KO, pageable))
|
||||
.thenReturn(emptyList())
|
||||
|
||||
service.getRooms(member, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
service.getRooms(member, Lang.KO, filter = "ALL", cursor = null, limit = 10, followedCreatorsOnly = true)
|
||||
|
||||
Mockito.verify(aiRoomRepository).findAiChatListRooms(1L, null, null, null, true, pageable)
|
||||
Mockito.verify(dmRoomRepository).findDmChatListRooms(1L, null, null, null, true, pageable)
|
||||
Mockito.verify(dmRoomRepository).findDmChatListRooms(1L, null, null, null, true, Lang.KO, pageable)
|
||||
}
|
||||
|
||||
private fun member(id: Long) = Member(password = "pw", nickname = "user").apply { this.id = id }
|
||||
|
||||
+36
-15
@@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.v2.content.all.application
|
||||
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
@@ -27,7 +26,15 @@ class MainContentAllQueryServiceTest {
|
||||
val port = FakeMainContentAllQueryPort()
|
||||
val service = createService(port)
|
||||
|
||||
val tab = service.getContents(type = "AUDIO", sort = "POPULAR", dayOfWeek = "MON", page = 1, size = 20, member = null)
|
||||
val tab = service.getContents(
|
||||
type = "AUDIO",
|
||||
sort = "POPULAR",
|
||||
dayOfWeek = "MON",
|
||||
page = 1,
|
||||
size = 20,
|
||||
member = null,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(MainContentAllType.AUDIO, tab.type)
|
||||
assertEquals("audio", port.lastListKind)
|
||||
@@ -50,7 +57,15 @@ class MainContentAllQueryServiceTest {
|
||||
val port = FakeMainContentAllQueryPort()
|
||||
val service = createService(port)
|
||||
|
||||
val tab = service.getContents(type = "FREE", sort = "LATEST", dayOfWeek = null, page = 0, size = 20, member = null)
|
||||
val tab = service.getContents(
|
||||
type = "FREE",
|
||||
sort = "LATEST",
|
||||
dayOfWeek = null,
|
||||
page = 0,
|
||||
size = 20,
|
||||
member = null,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(MainContentAllType.FREE, tab.type)
|
||||
assertEquals("audio", port.lastListKind)
|
||||
@@ -69,7 +84,15 @@ class MainContentAllQueryServiceTest {
|
||||
val port = FakeMainContentAllQueryPort()
|
||||
val service = createService(port)
|
||||
|
||||
val tab = service.getContents(type = "POINT", sort = "PRICE_LOW", dayOfWeek = null, page = 0, size = 20, member = null)
|
||||
val tab = service.getContents(
|
||||
type = "POINT",
|
||||
sort = "PRICE_LOW",
|
||||
dayOfWeek = null,
|
||||
page = 0,
|
||||
size = 20,
|
||||
member = null,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(MainContentAllType.POINT, tab.type)
|
||||
assertEquals("audio", port.lastListKind)
|
||||
@@ -87,9 +110,9 @@ class MainContentAllQueryServiceTest {
|
||||
@DisplayName("SERIES는 요일을 전달하고 ORIGINAL은 original 필터와 dayOfWeek null을 전달한다")
|
||||
fun shouldQuerySeriesByType() {
|
||||
val seriesPort = FakeMainContentAllQueryPort()
|
||||
val service = createService(seriesPort, lang = Lang.JA)
|
||||
val service = createService(seriesPort)
|
||||
|
||||
val seriesTab = service.getContents("SERIES", "POPULAR", "MON", 0, 20, null)
|
||||
val seriesTab = service.getContents("SERIES", "POPULAR", "MON", 0, 20, null, Lang.JA)
|
||||
|
||||
assertEquals(MainContentAllType.SERIES, seriesTab.type)
|
||||
assertEquals("series", seriesPort.lastListKind)
|
||||
@@ -100,7 +123,7 @@ class MainContentAllQueryServiceTest {
|
||||
val originalPort = FakeMainContentAllQueryPort()
|
||||
val originalService = createService(originalPort)
|
||||
|
||||
val originalTab = originalService.getContents("ORIGINAL", "POPULAR", "MON", 0, 20, null)
|
||||
val originalTab = originalService.getContents("ORIGINAL", "POPULAR", "MON", 0, 20, null, Lang.EN)
|
||||
|
||||
assertEquals(MainContentAllType.ORIGINAL, originalTab.type)
|
||||
assertEquals("series", originalPort.lastListKind)
|
||||
@@ -112,7 +135,7 @@ class MainContentAllQueryServiceTest {
|
||||
@DisplayName("비회원은 성인 콘텐츠 비노출로 조회하고 회원은 preference 결과를 전달한다")
|
||||
fun shouldPassAdultVisibilityByMember() {
|
||||
val anonymousPort = FakeMainContentAllQueryPort()
|
||||
createService(anonymousPort).getContents("AUDIO", null, null, null, null, null)
|
||||
createService(anonymousPort).getContents("AUDIO", null, null, null, null, null, Lang.EN)
|
||||
|
||||
assertEquals(null, anonymousPort.lastMemberId)
|
||||
assertFalse(anonymousPort.lastCanViewAdultContent)
|
||||
@@ -127,7 +150,7 @@ class MainContentAllQueryServiceTest {
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
Mockito.doReturn(true).`when`(preferenceService).canViewAdultContent(member)
|
||||
|
||||
createService(memberPort, preferenceService).getContents("AUDIO", null, null, null, null, member)
|
||||
createService(memberPort, preferenceService).getContents("AUDIO", null, null, null, null, member, Lang.EN)
|
||||
|
||||
assertEquals(10L, memberPort.lastMemberId)
|
||||
assertTrue(memberPort.lastCanViewAdultContent)
|
||||
@@ -136,16 +159,12 @@ class MainContentAllQueryServiceTest {
|
||||
|
||||
private fun createService(
|
||||
port: MainContentAllQueryPort,
|
||||
preferenceService: MemberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java),
|
||||
lang: Lang = Lang.EN
|
||||
preferenceService: MemberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
): MainContentAllQueryService {
|
||||
val langContext = LangContext()
|
||||
langContext.setLang(lang)
|
||||
return MainContentAllQueryService(
|
||||
queryPort = port,
|
||||
memberContentPreferenceService = preferenceService,
|
||||
queryPolicy = MainContentAllQueryPolicy(),
|
||||
langContext = langContext
|
||||
queryPolicy = MainContentAllQueryPolicy()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -204,6 +223,7 @@ private class FakeMainContentAllQueryPort : MainContentAllQueryPort {
|
||||
lastOnlyPointAvailable = onlyPointAvailable
|
||||
return (1L..limit.toLong()).map { id ->
|
||||
MainContentAllAudio(
|
||||
creatorMemberId = 10L,
|
||||
audioContentId = id,
|
||||
title = "audio-$id",
|
||||
imageUrl = null,
|
||||
@@ -253,6 +273,7 @@ private class FakeMainContentAllQueryPort : MainContentAllQueryPort {
|
||||
lastLocale = locale
|
||||
return listOf(
|
||||
MainContentAllSeries(
|
||||
creatorMemberId = 10L,
|
||||
seriesId = 1L,
|
||||
title = "series",
|
||||
coverImageUrl = null,
|
||||
|
||||
+6
-1
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.content.ranking.adapter.out.persistence
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.content.translation.ContentTranslation
|
||||
import kr.co.vividnext.sodalive.content.translation.ContentTranslationPayload
|
||||
@@ -31,7 +32,11 @@ class DefaultAudioRankingSnapshotPersistenceAdapterTest @Autowired constructor(
|
||||
private val entityManager: EntityManager,
|
||||
private val entityManagerFactory: EntityManagerFactory
|
||||
) {
|
||||
private val adapter = DefaultAudioRankingSnapshotPersistenceAdapter(repository, contentTranslationRepository)
|
||||
private val adapter = DefaultAudioRankingSnapshotPersistenceAdapter(
|
||||
repository,
|
||||
contentTranslationRepository,
|
||||
JPAQueryFactory(entityManager)
|
||||
)
|
||||
|
||||
@Test
|
||||
@DisplayName("SQL NULL 번역 payload는 snapshot 제목으로 fallback한다")
|
||||
|
||||
+34
-23
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.content.ranking.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
import kr.co.vividnext.sodalive.v2.content.ranking.domain.AudioRankingType
|
||||
@@ -35,14 +34,11 @@ class AudioRankingQueryServiceTest {
|
||||
"en" to originalLatestSnapshots.map { it.copy(title = "en-title-${it.contentId}") },
|
||||
"ja" to originalLatestSnapshots.map { it.copy(title = "ja-title-${it.contentId}") }
|
||||
)
|
||||
val langContext = LangContext().apply { setLang(Lang.EN) }
|
||||
val service = service(snapshotPort, langContext = langContext)
|
||||
val service = service(snapshotPort)
|
||||
|
||||
val english = service.getRankings(AudioRankingType.REVENUE, member = null)
|
||||
langContext.setLang(Lang.JA)
|
||||
val japanese = service.getRankings(AudioRankingType.REVENUE, member = null)
|
||||
langContext.setLang(Lang.EN)
|
||||
val englishAgain = service.getRankings(AudioRankingType.REVENUE, member = null)
|
||||
val english = service.getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.EN)
|
||||
val japanese = service.getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.JA)
|
||||
val englishAgain = service.getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.EN)
|
||||
|
||||
assertEquals(listOf("en-title-2", "en-title-1"), english.items.map { it.title })
|
||||
assertEquals(listOf("ja-title-2", "ja-title-1"), japanese.items.map { it.title })
|
||||
@@ -64,7 +60,8 @@ class AudioRankingQueryServiceTest {
|
||||
val method = AudioRankingQueryService::class.java.getDeclaredMethod(
|
||||
"getRankings",
|
||||
AudioRankingType::class.java,
|
||||
Member::class.java
|
||||
Member::class.java,
|
||||
Lang::class.java
|
||||
)
|
||||
|
||||
assertEquals(null, method.getAnnotation(Transactional::class.java))
|
||||
@@ -84,7 +81,7 @@ class AudioRankingQueryServiceTest {
|
||||
)
|
||||
val service = service(snapshotPort)
|
||||
|
||||
val result = service.getRankings(AudioRankingType.REVENUE, member = null)
|
||||
val result = service.getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.KO)
|
||||
|
||||
assertTrue(result.showRankChange)
|
||||
assertEquals(AudioRankingType.REVENUE, result.type)
|
||||
@@ -106,7 +103,7 @@ class AudioRankingQueryServiceTest {
|
||||
snapshotPort.latestSnapshots = listOf(snapshot(contentId = 1L, rank = 1))
|
||||
val service = service(snapshotPort)
|
||||
|
||||
val result = service.getRankings(AudioRankingType.WEEKLY_POPULAR, member = null)
|
||||
val result = service.getRankings(AudioRankingType.WEEKLY_POPULAR, member = null, lang = Lang.KO)
|
||||
|
||||
assertFalse(result.showRankChange)
|
||||
assertEquals(listOf(1L), result.items.map { it.contentId })
|
||||
@@ -116,7 +113,11 @@ class AudioRankingQueryServiceTest {
|
||||
|
||||
@Test
|
||||
fun shouldReturnEmptyRankingWhenLatestSnapshotDoesNotExist() {
|
||||
val result = service(FakeAudioRankingQuerySnapshotPort()).getRankings(AudioRankingType.LIKE_COUNT, member = null)
|
||||
val result = service(FakeAudioRankingQuerySnapshotPort()).getRankings(
|
||||
AudioRankingType.LIKE_COUNT,
|
||||
member = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertFalse(result.showRankChange)
|
||||
assertEquals(AudioRankingType.LIKE_COUNT, result.type)
|
||||
@@ -136,7 +137,7 @@ class AudioRankingQueryServiceTest {
|
||||
snapshot(contentId = 2L, rank = 2)
|
||||
)
|
||||
|
||||
val result = service(snapshotPort).getRankings(AudioRankingType.REVENUE, member = null)
|
||||
val result = service(snapshotPort).getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(2L, 3L), result.items.map { it.contentId })
|
||||
assertEquals(listOf(1, 2), result.items.map { it.rank })
|
||||
@@ -150,7 +151,7 @@ class AudioRankingQueryServiceTest {
|
||||
val member = Mockito.mock(Member::class.java)
|
||||
snapshotPort.latestSnapshots = listOf(snapshot(contentId = 1L, rank = 1, isAdult = true))
|
||||
|
||||
val result = service(snapshotPort, adultMember = member).getRankings(AudioRankingType.REVENUE, member)
|
||||
val result = service(snapshotPort, adultMember = member).getRankings(AudioRankingType.REVENUE, member, Lang.KO)
|
||||
|
||||
assertEquals(listOf(1L), result.items.map { it.contentId })
|
||||
}
|
||||
@@ -170,7 +171,7 @@ class AudioRankingQueryServiceTest {
|
||||
snapshot(contentId = 1L, rank = 2, creatorMemberId = 101L)
|
||||
)
|
||||
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(AudioRankingType.REVENUE, member)
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(AudioRankingType.REVENUE, member, Lang.KO)
|
||||
|
||||
assertEquals(listOf(1L, 3L), result.items.map { it.contentId })
|
||||
assertEquals(listOf(1, 2), result.items.map { it.rank })
|
||||
@@ -185,7 +186,11 @@ class AudioRankingQueryServiceTest {
|
||||
val blockPort = FakeAudioRankingBlockPort(blockedCreatorMemberIds = setOf(101L))
|
||||
snapshotPort.latestSnapshots = listOf(snapshot(contentId = 1L, rank = 1, creatorMemberId = 101L))
|
||||
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(AudioRankingType.REVENUE, member = null)
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(
|
||||
AudioRankingType.REVENUE,
|
||||
member = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L), result.items.map { it.contentId })
|
||||
assertEquals(0, blockPort.callCount)
|
||||
@@ -200,7 +205,11 @@ class AudioRankingQueryServiceTest {
|
||||
listOf(snapshot(contentId = 1L, rank = 1))
|
||||
)
|
||||
|
||||
val result = service(snapshotPort, jobService = jobService).getRankings(AudioRankingType.LIKE_COUNT, member = null)
|
||||
val result = service(snapshotPort, jobService = jobService).getRankings(
|
||||
AudioRankingType.LIKE_COUNT,
|
||||
member = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L), result.items.map { it.contentId })
|
||||
assertEquals(2, snapshotPort.latestCallCount)
|
||||
@@ -214,7 +223,11 @@ class AudioRankingQueryServiceTest {
|
||||
Mockito.doThrow(IllegalStateException("aggregate failed"))
|
||||
.`when`(jobService).refreshLastCompletedWeekByFallback(AudioRankingType.LIKE_COUNT)
|
||||
|
||||
val result = service(snapshotPort, jobService = jobService).getRankings(AudioRankingType.LIKE_COUNT, member = null)
|
||||
val result = service(snapshotPort, jobService = jobService).getRankings(
|
||||
AudioRankingType.LIKE_COUNT,
|
||||
member = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertFalse(result.showRankChange)
|
||||
assertEquals(AudioRankingType.LIKE_COUNT, result.type)
|
||||
@@ -230,7 +243,7 @@ class AudioRankingQueryServiceTest {
|
||||
val jobService = Mockito.mock(AudioRankingSnapshotJobService::class.java)
|
||||
snapshotPort.latestSnapshots = listOf(snapshot(contentId = 1L, rank = 1))
|
||||
|
||||
service(snapshotPort, jobService = jobService).getRankings(AudioRankingType.REVENUE, member = null)
|
||||
service(snapshotPort, jobService = jobService).getRankings(AudioRankingType.REVENUE, member = null, lang = Lang.KO)
|
||||
|
||||
Mockito.verify(jobService, Mockito.never()).refreshLastCompletedWeekByFallback(AudioRankingType.REVENUE)
|
||||
}
|
||||
@@ -250,7 +263,7 @@ class AudioRankingQueryServiceTest {
|
||||
snapshot(contentId = 2L, rank = 3, creatorMemberId = 102L)
|
||||
)
|
||||
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(AudioRankingType.REVENUE, member)
|
||||
val result = service(snapshotPort, blockPort = blockPort).getRankings(AudioRankingType.REVENUE, member, Lang.KO)
|
||||
|
||||
assertEquals(setOf(101L, 102L, 999L), blockPort.creatorMemberIds)
|
||||
assertEquals(listOf(0, 0), result.items.map { it.rankChange })
|
||||
@@ -261,8 +274,7 @@ class AudioRankingQueryServiceTest {
|
||||
snapshotPort: FakeAudioRankingQuerySnapshotPort,
|
||||
adultMember: Member? = null,
|
||||
blockPort: AudioRankingBlockPort = FakeAudioRankingBlockPort(),
|
||||
jobService: AudioRankingSnapshotJobService = Mockito.mock(AudioRankingSnapshotJobService::class.java),
|
||||
langContext: LangContext = LangContext()
|
||||
jobService: AudioRankingSnapshotJobService = Mockito.mock(AudioRankingSnapshotJobService::class.java)
|
||||
): AudioRankingQueryService {
|
||||
val memberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
if (adultMember != null) {
|
||||
@@ -270,7 +282,6 @@ class AudioRankingQueryServiceTest {
|
||||
}
|
||||
return AudioRankingQueryService(
|
||||
snapshotPort = snapshotPort,
|
||||
langContext = langContext,
|
||||
memberContentPreferenceService = memberContentPreferenceService,
|
||||
blockPort = blockPort,
|
||||
jobService = jobService,
|
||||
|
||||
+7
-9
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.content.recommendation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
@@ -20,12 +19,10 @@ class AudioRecommendationQueryServiceTest {
|
||||
private val queryPort = Mockito.mock(AudioRecommendationQueryPort::class.java)
|
||||
private val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
private val fallbackService = Mockito.mock(AudioRecommendationSnapshotFallbackService::class.java)
|
||||
private val langContext = LangContext().apply { setLang(Lang.EN) }
|
||||
private val service = AudioRecommendationQueryService(
|
||||
queryPort,
|
||||
preferenceService,
|
||||
fallbackService,
|
||||
langContext
|
||||
fallbackService
|
||||
)
|
||||
|
||||
@Test
|
||||
@@ -63,7 +60,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
emptyList()
|
||||
)
|
||||
|
||||
val recommendations = service.getRecommendations(null)
|
||||
val recommendations = service.getRecommendations(null, Lang.EN)
|
||||
|
||||
assertEquals(0, recommendations.mostCommentedAudios.size)
|
||||
verifyFallback(
|
||||
@@ -134,7 +131,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
listOf(snapshot(RecommendedSectionType.RECOMMENDED_AUDIO_SAFE, 2L))
|
||||
)
|
||||
|
||||
service.getRecommendations(null)
|
||||
service.getRecommendations(null, Lang.EN)
|
||||
|
||||
verifyFallback(
|
||||
RecommendedSectionType.MOST_COMMENTED_AUDIO_SAFE,
|
||||
@@ -156,7 +153,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
listOf(snapshot(RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL, 10L))
|
||||
)
|
||||
|
||||
service.getRecommendations(member)
|
||||
service.getRecommendations(member, Lang.EN)
|
||||
|
||||
Mockito.verify(preferenceService).canViewAdultContent(member)
|
||||
Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, member.id, true, Lang.JA)
|
||||
@@ -180,7 +177,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
listOf(snapshot(RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL, 10L))
|
||||
)
|
||||
|
||||
service.getRecommendations(member)
|
||||
service.getRecommendations(member, Lang.EN)
|
||||
|
||||
verifyFallback(
|
||||
RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL,
|
||||
@@ -209,7 +206,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
eqValue(Lang.EN.code)
|
||||
)
|
||||
|
||||
val result = service.findNewAndHotAudios(member, offset = 20L, limit = 21)
|
||||
val result = service.findNewAndHotAudios(member, offset = 20L, limit = 21, lang = Lang.EN)
|
||||
|
||||
assertEquals(listOf(3L, 4L, 5L), result.map { it.audioContentId })
|
||||
verifyFallback(RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL, 20L, 21)
|
||||
@@ -261,6 +258,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
|
||||
private fun audioCard(id: Long): AudioCard {
|
||||
return AudioCard(
|
||||
creatorMemberId = id + 100L,
|
||||
audioContentId = id,
|
||||
title = "audio$id",
|
||||
duration = "00:01",
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.content.translation.ContentTranslation
|
||||
import kr.co.vividnext.sodalive.content.translation.ContentTranslationPayload
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesContent
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMember
|
||||
@@ -62,7 +63,7 @@ class DefaultCreatorChannelAudioQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creator, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val themes = repository.findAudioThemes(creator.id!!, now, canViewAdultContent = false, "en")
|
||||
|
||||
assertEquals(creator.id, record!!.creatorId)
|
||||
|
||||
+7
-6
@@ -45,7 +45,8 @@ class CreatorChannelAudioQueryServiceTest {
|
||||
themeId = 999L,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(ContentSort.LATEST, tab.sort)
|
||||
@@ -78,7 +79,7 @@ class CreatorChannelAudioQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val tab = service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||
val tab = service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0), Lang.EN)
|
||||
|
||||
assertEquals(0.0, tab.purchasedAudioContentRate)
|
||||
}
|
||||
@@ -91,7 +92,7 @@ class CreatorChannelAudioQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -105,7 +106,7 @@ class CreatorChannelAudioQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -119,7 +120,7 @@ class CreatorChannelAudioQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -191,7 +192,7 @@ private class FakeCreatorChannelAudioQueryPort : CreatorChannelAudioQueryPort {
|
||||
var themeCanViewAdultContent: Boolean? = null
|
||||
var themeLocale: String? = null
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelAudioCreatorRecord? = creator
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelAudioCreatorRecord? = creator
|
||||
|
||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||
|
||||
|
||||
+52
-21
@@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityComment
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLike
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberKind
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
@@ -46,8 +47,8 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
val inactiveCreator = saveMember("inactive-creator", MemberRole.CREATOR, isActive = false)
|
||||
flushAndClear()
|
||||
|
||||
val activeRecord = repository.findCreator(activeCreator.id!!, viewer.id!!)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!)
|
||||
val activeRecord = repository.findCreator(activeCreator.id!!, viewer.id!!, Lang.KO)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertNotNull(activeRecord)
|
||||
assertEquals(activeCreator.id, activeRecord!!.creatorId)
|
||||
@@ -92,7 +93,8 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val visiblePostIds = visiblePosts.map { it.postId }
|
||||
|
||||
@@ -125,14 +127,16 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val secondPage: List<CreatorChannelCommunityPostRecord> = repository.findCommunityPosts(
|
||||
creatorId = creator.id!!,
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 3,
|
||||
limit = 2
|
||||
limit = 2,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
@@ -168,7 +172,8 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val record = records.single { it.postId == post.id }
|
||||
val otherMemberOnlyLikedRecord = records.single { it.postId == otherMemberOnlyLikedPost.id }
|
||||
@@ -203,21 +208,24 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
).single()
|
||||
val writerRecord = repository.findCommunityPosts(
|
||||
creatorId = creator.id!!,
|
||||
viewerId = secretWriter.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
).single()
|
||||
val creatorRecord = repository.findCommunityPosts(
|
||||
creatorId = creator.id!!,
|
||||
viewerId = creator.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
).single()
|
||||
|
||||
assertEquals(1, viewerRecord.commentCount)
|
||||
@@ -247,7 +255,8 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val recordsById = records.associateBy { it.postId }
|
||||
|
||||
@@ -271,7 +280,8 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = creator.id!!,
|
||||
canViewAdultContent = true,
|
||||
offset = 0,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
).single()
|
||||
|
||||
assertTrue(record.existOrdered)
|
||||
@@ -297,14 +307,16 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
isPinned = true,
|
||||
canViewAdultContent = false,
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val normalPosts: List<CreatorChannelCommunityPostRecord> = repository.findHomeCommunityPosts(
|
||||
creatorId = creator.id!!,
|
||||
viewerId = viewer.id!!,
|
||||
isPinned = false,
|
||||
canViewAdultContent = false,
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(pinned.id), pinnedPosts.map { it.postId })
|
||||
@@ -337,14 +349,16 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
viewerId = viewer.id!!,
|
||||
isPinned = false,
|
||||
canViewAdultContent = true,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val adultBlockedPosts: List<CreatorChannelCommunityPostRecord> = repository.findHomeCommunityPosts(
|
||||
creatorId = creator.id!!,
|
||||
viewerId = viewer.id!!,
|
||||
isPinned = false,
|
||||
canViewAdultContent = false,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertTrue(inactivePurchasedPost.id in adultAllowedPosts.map { it.postId })
|
||||
@@ -368,9 +382,19 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
saveCommunityComment(viewer, paidPost, isActive = true)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCommunityPost(paidPost.id!!, viewer.id!!, canViewAdultContent = true)
|
||||
val blockedAdultRecord = repository.findCommunityPost(adultPost.id!!, viewer.id!!, canViewAdultContent = false)
|
||||
val inactiveRecord = repository.findCommunityPost(inactivePost.id!!, viewer.id!!, canViewAdultContent = true)
|
||||
val record = repository.findCommunityPost(paidPost.id!!, viewer.id!!, canViewAdultContent = true, lang = Lang.KO)
|
||||
val blockedAdultRecord = repository.findCommunityPost(
|
||||
adultPost.id!!,
|
||||
viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val inactiveRecord = repository.findCommunityPost(
|
||||
inactivePost.id!!,
|
||||
viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertNotNull(record)
|
||||
assertEquals(paidPost.id, record!!.postId)
|
||||
@@ -412,8 +436,15 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
|
||||
val viewerCount = repository.countCommunityComments(post.id!!, viewer.id!!, creator.id!!)
|
||||
val creatorCount = repository.countCommunityComments(post.id!!, creator.id!!, creator.id!!)
|
||||
val comments = repository.findCommunityComments(post.id!!, viewer.id!!, creator.id!!, offset = 0, limit = 10)
|
||||
val latestReplies = repository.findLatestRepliesByCommentIds(comments.map { it.commentId }, viewer.id!!)
|
||||
val comments = repository.findCommunityComments(
|
||||
post.id!!,
|
||||
viewer.id!!,
|
||||
creator.id!!,
|
||||
offset = 0,
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val latestReplies = repository.findLatestRepliesByCommentIds(comments.map { it.commentId }, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(2, viewerCount)
|
||||
assertEquals(4, creatorCount)
|
||||
@@ -448,7 +479,7 @@ class DefaultCreatorChannelCommunityQueryRepositoryTest @Autowired constructor(
|
||||
val invisibleSecretContext = repository.findRootCommentContext(secretRoot.id!!, viewer.id!!, canViewAdultContent = true)
|
||||
val replyContext = repository.findRootCommentContext(newReply.id!!, viewer.id!!, canViewAdultContent = true)
|
||||
val count = repository.countCommunityReplies(root.id!!, viewer.id!!)
|
||||
val replies = repository.findCommunityReplies(root.id!!, viewer.id!!, offset = 0, limit = 10)
|
||||
val replies = repository.findCommunityReplies(root.id!!, viewer.id!!, offset = 0, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertNotNull(context)
|
||||
assertEquals(post.id, context!!.postId)
|
||||
|
||||
+60
-24
@@ -47,7 +47,8 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(60, tab.communityPostCount)
|
||||
@@ -72,7 +73,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -86,7 +87,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -100,7 +101,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -129,7 +130,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val service = createService(port, audioContentCloudFront)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val posts = service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
val posts = service.getCommunityTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
.communityPosts
|
||||
|
||||
assertEquals("https://cdn.test/image/1.png", posts[0].imageUrl)
|
||||
@@ -165,7 +166,8 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
viewerId = 10L,
|
||||
isPinned = true,
|
||||
canViewAdultContent = false,
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1, posts.size)
|
||||
@@ -203,7 +205,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val posts = service.getCommunityTab(1L, createMember(id = 10L), 0, 20).communityPosts
|
||||
val posts = service.getCommunityTab(1L, createMember(id = 10L), 0, 20, lang = Lang.EN).communityPosts
|
||||
|
||||
assertEquals(
|
||||
listOf(
|
||||
@@ -230,7 +232,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val returnedPostIds = (1L..50L).toList()
|
||||
Mockito.`when`(translationService.findDisplayContents(returnedPostIds, "en")).thenReturn(emptyMap())
|
||||
|
||||
val tab = service.getCommunityTab(1L, createMember(id = 10L), page = 0, size = 50)
|
||||
val tab = service.getCommunityTab(1L, createMember(id = 10L), page = 0, size = 50, lang = Lang.EN)
|
||||
|
||||
assertEquals(50, tab.communityPosts.size)
|
||||
assertTrue(tab.hasNext)
|
||||
@@ -248,13 +250,13 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
Mockito.`when`(translationService.findDisplayContents(listOf(21L), "en"))
|
||||
.thenReturn(mapOf(21L to CreatorCommunityDisplayContent("translated pinned", true)))
|
||||
|
||||
val pinnedPosts = service.findHomeCommunityPosts(1L, 10L, true, false, 3)
|
||||
val pinnedPosts = service.findHomeCommunityPosts(1L, 10L, true, false, 3, Lang.EN)
|
||||
|
||||
port.homeCommunityPosts = listOf(communityPostRecord(22L, price = 0).copy(content = "source normal"))
|
||||
Mockito.`when`(translationService.findDisplayContents(listOf(22L), "en"))
|
||||
.thenReturn(mapOf(22L to CreatorCommunityDisplayContent("translated normal", true)))
|
||||
|
||||
val normalPosts = service.findHomeCommunityPosts(1L, 10L, false, false, 3)
|
||||
val normalPosts = service.findHomeCommunityPosts(1L, 10L, false, false, 3, Lang.EN)
|
||||
|
||||
assertEquals("translated pinned", pinnedPosts.single().content)
|
||||
assertEquals("translated normal", normalPosts.single().content)
|
||||
@@ -275,7 +277,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val detail = service.getCommunityPostDetail(1L, viewer, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
val detail = service.getCommunityPostDetail(1L, viewer, LocalDateTime.of(2026, 7, 6, 10, 0), Lang.KO)
|
||||
|
||||
assertEquals(1L, detail.post.postId)
|
||||
assertEquals(true, detail.post.isLiked)
|
||||
@@ -298,7 +300,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
Mockito.`when`(translationService.findDisplayContents(listOf(1L), "en"))
|
||||
.thenReturn(mapOf(1L to CreatorCommunityDisplayContent("content-1", true)))
|
||||
|
||||
service.getCommunityPostDetail(1L, createMember(id = 10L), LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
service.getCommunityPostDetail(1L, createMember(id = 10L), LocalDateTime.of(2026, 7, 6, 10, 0), Lang.KO)
|
||||
|
||||
Mockito.verify(translationService, Mockito.never()).requestTranslations(1L, "en")
|
||||
}
|
||||
@@ -311,7 +313,14 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
}
|
||||
val service = createService(port)
|
||||
|
||||
val comments = service.getCommunityComments(1L, createMember(id = 10L), -1, 100, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
val comments = service.getCommunityComments(
|
||||
1L,
|
||||
createMember(id = 10L),
|
||||
-1,
|
||||
100,
|
||||
LocalDateTime.of(2026, 7, 6, 10, 0),
|
||||
Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(0, comments.commentCount)
|
||||
assertEquals(0, comments.comments.size)
|
||||
@@ -332,7 +341,14 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
}
|
||||
val service = createService(port)
|
||||
|
||||
val comments = service.getCommunityComments(1L, createMember(id = 10L), -1, 100, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
val comments = service.getCommunityComments(
|
||||
1L,
|
||||
createMember(id = 10L),
|
||||
-1,
|
||||
100,
|
||||
LocalDateTime.of(2026, 7, 6, 10, 0),
|
||||
Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(0L, port.commentListOffset)
|
||||
assertEquals(51, port.commentListLimit)
|
||||
@@ -356,7 +372,14 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
}
|
||||
val service = createService(port)
|
||||
|
||||
val replies = service.getCommunityReplies(1L, createMember(id = 10L), -1, 100, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
val replies = service.getCommunityReplies(
|
||||
1L,
|
||||
createMember(id = 10L),
|
||||
-1,
|
||||
100,
|
||||
LocalDateTime.of(2026, 7, 6, 10, 0),
|
||||
Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(51, replies.replyCount)
|
||||
assertEquals(50, replies.replies.size)
|
||||
@@ -373,7 +396,7 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
val service = createService(port)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getCommunityReplies(1L, createMember(id = 10L), null, null, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
service.getCommunityReplies(1L, createMember(id = 10L), null, null, LocalDateTime.of(2026, 7, 6, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("creator.community.invalid_request_retry", exception.messageKey)
|
||||
@@ -389,7 +412,14 @@ class CreatorChannelCommunityQueryServiceTest {
|
||||
}
|
||||
val service = createService(port)
|
||||
|
||||
val replies = service.getCommunityReplies(1L, createMember(id = 10L), null, null, LocalDateTime.of(2026, 7, 6, 10, 0))
|
||||
val replies = service.getCommunityReplies(
|
||||
1L,
|
||||
createMember(id = 10L),
|
||||
null,
|
||||
null,
|
||||
LocalDateTime.of(2026, 7, 6, 10, 0),
|
||||
Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(0, replies.replyCount)
|
||||
assertEquals(0, replies.replies.size)
|
||||
@@ -484,7 +514,7 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
var homeCanViewAdultContent: Boolean? = null
|
||||
var homeLimit: Int? = null
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelCommunityCreatorRecord? = creator
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelCommunityCreatorRecord? = creator
|
||||
|
||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||
|
||||
@@ -502,7 +532,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
canViewAdultContent: Boolean,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityPostRecord> {
|
||||
listCanViewAdultContent = canViewAdultContent
|
||||
listOffset = offset
|
||||
@@ -515,7 +546,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
isPinned: Boolean,
|
||||
canViewAdultContent: Boolean,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityPostRecord> {
|
||||
homeCreatorId = creatorId
|
||||
homeViewerId = viewerId
|
||||
@@ -528,7 +560,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
override fun findCommunityPost(
|
||||
postId: Long,
|
||||
viewerId: Long,
|
||||
canViewAdultContent: Boolean
|
||||
canViewAdultContent: Boolean,
|
||||
lang: Lang
|
||||
): CreatorChannelCommunityPostRecord? = communityPost
|
||||
|
||||
override fun countCommunityComments(postId: Long, viewerId: Long, creatorId: Long): Int = communityCommentCount
|
||||
@@ -538,7 +571,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
creatorId: Long,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityCommentRecord> {
|
||||
commentListCalled = true
|
||||
commentListOffset = offset
|
||||
@@ -548,7 +582,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
|
||||
override fun findLatestRepliesByCommentIds(
|
||||
commentIds: List<Long>,
|
||||
viewerId: Long
|
||||
viewerId: Long,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityCommentRecord> {
|
||||
latestReplyCommentIds = commentIds
|
||||
return latestReplies
|
||||
@@ -566,7 +601,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
commentId: Long,
|
||||
viewerId: Long,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityCommentRecord> {
|
||||
replyListOffset = offset
|
||||
replyListLimit = limit
|
||||
|
||||
+7
-6
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel.donation.adapter.out.persist
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.explorer.profile.channelDonation.ChannelDonationMessage
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.DonationRankingPeriod
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
@@ -48,9 +49,9 @@ class DefaultCreatorChannelDonationQueryRepositoryTest @Autowired constructor(
|
||||
val nonCreator = saveMember("donation-non-creator", MemberRole.USER)
|
||||
flushAndClear()
|
||||
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!)
|
||||
val nonCreatorRecord = repository.findCreator(nonCreator.id!!, viewer.id!!)
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!, Lang.KO)
|
||||
val nonCreatorRecord = repository.findCreator(nonCreator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertNotNull(creatorRecord)
|
||||
assertEquals(creator.id, creatorRecord!!.creatorId)
|
||||
@@ -91,7 +92,7 @@ class DefaultCreatorChannelDonationQueryRepositoryTest @Autowired constructor(
|
||||
flushAndClear()
|
||||
|
||||
val count = repository.countChannelDonations(creator.id!!, creator.id!!, now)
|
||||
val records = repository.findChannelDonations(creator.id!!, creator.id!!, now, offset = 0, limit = 10)
|
||||
val records = repository.findChannelDonations(creator.id!!, creator.id!!, now, offset = 0, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(2, count)
|
||||
assertEquals(listOf(secret.can, monthStart.can), records.map { it.can })
|
||||
@@ -121,7 +122,7 @@ class DefaultCreatorChannelDonationQueryRepositoryTest @Autowired constructor(
|
||||
flushAndClear()
|
||||
|
||||
val count = repository.countChannelDonations(creator.id!!, viewer.id!!, now)
|
||||
val records = repository.findChannelDonations(creator.id!!, viewer.id!!, now, offset = 0, limit = 10)
|
||||
val records = repository.findChannelDonations(creator.id!!, viewer.id!!, now, offset = 0, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(2, count)
|
||||
assertEquals(listOf(ownSecretDonation.can, publicDonation.can), records.map { it.can })
|
||||
@@ -141,7 +142,7 @@ class DefaultCreatorChannelDonationQueryRepositoryTest @Autowired constructor(
|
||||
saveDonation(creator, donor, 300, sameCreatedAt.plusMinutes(1), additionalMessage = "newest")
|
||||
flushAndClear()
|
||||
|
||||
val records = repository.findChannelDonations(creator.id!!, viewer.id!!, now, offset = 1, limit = 2)
|
||||
val records = repository.findChannelDonations(creator.id!!, viewer.id!!, now, offset = 1, limit = 2, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(second.can, first.can), records.map { it.can })
|
||||
}
|
||||
|
||||
+21
-14
@@ -1,7 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.creator.channel.donation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.DonationRankingPeriod
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -34,7 +34,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(VIEWER_ID),
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
}
|
||||
|
||||
@@ -55,7 +56,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(VIEWER_ID),
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
}
|
||||
|
||||
@@ -74,7 +76,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(VIEWER_ID),
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
}
|
||||
|
||||
@@ -97,7 +100,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(VIEWER_ID),
|
||||
page = -1,
|
||||
size = 10,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(0L, queryPort.lastFindDonationRequest?.offset)
|
||||
@@ -138,7 +142,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(VIEWER_ID),
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals("donor", tab.donations[0].nickname)
|
||||
@@ -163,7 +168,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewer = createMember(CREATOR_ID),
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = NOW
|
||||
now = NOW,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(RankingRequest(CREATOR_ID, DonationRankingPeriod.WEEKLY, true), rankingPort.requests.single())
|
||||
@@ -186,7 +192,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
)
|
||||
),
|
||||
rankingPort = weeklyRankingPort
|
||||
).getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW)
|
||||
).getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW, Lang.KO)
|
||||
|
||||
val cumulativeRankingPort = FakeDonationRankingPort()
|
||||
createService(
|
||||
@@ -197,7 +203,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
)
|
||||
),
|
||||
rankingPort = cumulativeRankingPort
|
||||
).getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW)
|
||||
).getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW, Lang.KO)
|
||||
|
||||
assertEquals(RankingRequest(CREATOR_ID, DonationRankingPeriod.WEEKLY, false), weeklyRankingPort.requests.single())
|
||||
assertEquals(RankingRequest(CREATOR_ID, DonationRankingPeriod.CUMULATIVE, false), cumulativeRankingPort.requests.single())
|
||||
@@ -214,7 +220,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
rankingPort = rankingPort
|
||||
)
|
||||
|
||||
service.getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW)
|
||||
service.getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW, Lang.KO)
|
||||
|
||||
assertEquals(RankingRequest(CREATOR_ID, DonationRankingPeriod.CUMULATIVE, false), rankingPort.requests.single())
|
||||
}
|
||||
@@ -233,7 +239,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
val rankingPort = FakeDonationRankingPort()
|
||||
val service = createService(queryPort = queryPort, rankingPort = rankingPort)
|
||||
|
||||
val tab = service.getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW)
|
||||
val tab = service.getDonationTab(CREATOR_ID, createMember(VIEWER_ID), 0, 20, NOW, Lang.KO)
|
||||
|
||||
assertEquals(emptyList<RankingRequest>(), rankingPort.requests)
|
||||
assertEquals(emptyList<Any>(), tab.rankings)
|
||||
@@ -255,7 +261,6 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
rankingPort = rankingPort,
|
||||
queryPolicy = CreatorChannelDonationQueryPolicy(),
|
||||
messageSource = SodaMessageSource(),
|
||||
langContext = LangContext(),
|
||||
cloudFrontHost = "https://cdn.test"
|
||||
)
|
||||
}
|
||||
@@ -282,6 +287,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
createdAt: LocalDateTime = NOW
|
||||
): CreatorChannelDonationRecord {
|
||||
return CreatorChannelDonationRecord(
|
||||
memberId = VIEWER_ID,
|
||||
nickname = nickname,
|
||||
profileImagePath = profileImagePath,
|
||||
can = can,
|
||||
@@ -319,7 +325,7 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
var lastFindDonationRequest: FindDonationRequest? = null
|
||||
private set
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelDonationCreatorRecord? {
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelDonationCreatorRecord? {
|
||||
return creator
|
||||
}
|
||||
|
||||
@@ -337,7 +343,8 @@ class CreatorChannelDonationQueryServiceTest {
|
||||
viewerId: Long,
|
||||
now: LocalDateTime,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelDonationRecord> {
|
||||
lastFindDonationRequest = FindDonationRequest(creatorId, viewerId, now, offset, limit)
|
||||
return donations
|
||||
|
||||
+2
@@ -78,6 +78,7 @@ class CreatorChannelDonationQueryPolicyTest {
|
||||
donationCan = 100
|
||||
)
|
||||
val donation = CreatorChannelDonation(
|
||||
memberId = 10L,
|
||||
nickname = "donor",
|
||||
profileImageUrl = "https://cdn.test/donor.png",
|
||||
can = 50,
|
||||
@@ -99,6 +100,7 @@ class CreatorChannelDonationQueryPolicyTest {
|
||||
donationRankingPeriod = DonationRankingPeriod.CUMULATIVE
|
||||
)
|
||||
val donationRecord = CreatorChannelDonationRecord(
|
||||
memberId = 10L,
|
||||
nickname = "donor",
|
||||
profileImagePath = null,
|
||||
can = 50,
|
||||
|
||||
+9
-8
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.adapter.out.persiste
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMember
|
||||
@@ -41,9 +42,9 @@ class DefaultCreatorChannelFanTalkQueryRepositoryTest @Autowired constructor(
|
||||
val nonCreator = saveMember("fantalk-non-creator", MemberRole.USER)
|
||||
flushAndClear()
|
||||
|
||||
val activeRecord = repository.findCreator(activeCreator.id!!, viewer.id!!)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!)
|
||||
val nonCreatorRecord = repository.findCreator(nonCreator.id!!, viewer.id!!)
|
||||
val activeRecord = repository.findCreator(activeCreator.id!!, viewer.id!!, Lang.KO)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!, Lang.KO)
|
||||
val nonCreatorRecord = repository.findCreator(nonCreator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertNotNull(activeRecord)
|
||||
assertEquals(activeCreator.id, activeRecord!!.creatorId)
|
||||
@@ -90,8 +91,8 @@ class DefaultCreatorChannelFanTalkQueryRepositoryTest @Autowired constructor(
|
||||
flushAndClear()
|
||||
|
||||
val count = repository.countFanTalks(creator.id!!, viewer.id!!)
|
||||
val firstPage = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 0, limit = 1)
|
||||
val secondPage = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 1, limit = 2)
|
||||
val firstPage = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 0, limit = 1, lang = Lang.KO)
|
||||
val secondPage = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 1, limit = 2, lang = Lang.KO)
|
||||
|
||||
assertEquals(2, count)
|
||||
assertEquals(listOf(newer.id), firstPage.map { it.fanTalkId })
|
||||
@@ -114,7 +115,7 @@ class DefaultCreatorChannelFanTalkQueryRepositoryTest @Autowired constructor(
|
||||
val newest = saveCheers(writer, creator, "newest", isActive = true, createdAt = sameCreatedAt.plusMinutes(1))
|
||||
flushAndClear()
|
||||
|
||||
val records = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 0, limit = 10)
|
||||
val records = repository.findFanTalks(creator.id!!, viewer.id!!, offset = 0, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(newest.id, second.id, first.id), records.map { it.fanTalkId })
|
||||
}
|
||||
@@ -157,8 +158,8 @@ class DefaultCreatorChannelFanTalkQueryRepositoryTest @Autowired constructor(
|
||||
)
|
||||
flushAndClear()
|
||||
|
||||
val replies = repository.findCreatorReplies(creator.id!!, listOf(parent.id!!))
|
||||
val emptyReplies = repository.findCreatorReplies(creator.id!!, emptyList())
|
||||
val replies = repository.findCreatorReplies(creator.id!!, listOf(parent.id!!), Lang.KO)
|
||||
val emptyReplies = repository.findCreatorReplies(creator.id!!, emptyList(), Lang.KO)
|
||||
|
||||
assertEquals(listOf(olderReply.id, newerReply.id), replies.map { it.fanTalkId })
|
||||
assertEquals(parent.id, replies.first().parentFanTalkId)
|
||||
|
||||
+12
-13
@@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.v2.creator.channel.fantalk.application
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberProvider
|
||||
@@ -30,7 +29,7 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -44,7 +43,7 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -58,7 +57,7 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -85,7 +84,8 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
viewer = viewer,
|
||||
page = -1,
|
||||
size = 10,
|
||||
now = LocalDateTime.of(2026, 6, 21, 10, 0)
|
||||
now = LocalDateTime.of(2026, 6, 21, 10, 0),
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(60, tab.fanTalkCount)
|
||||
@@ -114,7 +114,7 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val tab = service.getFanTalkTab(1L, viewer, 3, 20, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
val tab = service.getFanTalkTab(1L, viewer, 3, 20, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
|
||||
assertEquals(5, tab.fanTalkCount)
|
||||
assertEquals(emptyList<Long>(), tab.fanTalks.map { it.fanTalkId })
|
||||
@@ -156,7 +156,7 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val fanTalks = service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0))
|
||||
val fanTalks = service.getFanTalkTab(1L, viewer, null, null, LocalDateTime.of(2026, 6, 21, 10, 0), Lang.EN)
|
||||
.fanTalks
|
||||
|
||||
assertEquals("fan", fanTalks[0].writerNickname)
|
||||
@@ -169,13 +169,10 @@ class CreatorChannelFanTalkQueryServiceTest {
|
||||
}
|
||||
|
||||
private fun createService(port: FakeCreatorChannelFanTalkQueryPort): CreatorChannelFanTalkQueryService {
|
||||
val langContext = LangContext()
|
||||
langContext.setLang(Lang.EN)
|
||||
return CreatorChannelFanTalkQueryService(
|
||||
queryPortProvider = FixedCreatorChannelFanTalkQueryPortProvider(port),
|
||||
queryPolicy = CreatorChannelFanTalkQueryPolicy(),
|
||||
messageSource = SodaMessageSource(),
|
||||
langContext = langContext,
|
||||
cloudFrontHost = "https://cdn.test"
|
||||
)
|
||||
}
|
||||
@@ -216,7 +213,7 @@ private class FakeCreatorChannelFanTalkQueryPort : CreatorChannelFanTalkQueryPor
|
||||
var listLimit: Int? = null
|
||||
var replyParentFanTalkIds: List<Long>? = null
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelFanTalkCreatorRecord? = creator
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelFanTalkCreatorRecord? = creator
|
||||
|
||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||
|
||||
@@ -226,7 +223,8 @@ private class FakeCreatorChannelFanTalkQueryPort : CreatorChannelFanTalkQueryPor
|
||||
creatorId: Long,
|
||||
viewerId: Long,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelFanTalkRecord> {
|
||||
listOffset = offset
|
||||
listLimit = limit
|
||||
@@ -235,7 +233,8 @@ private class FakeCreatorChannelFanTalkQueryPort : CreatorChannelFanTalkQueryPor
|
||||
|
||||
override fun findCreatorReplies(
|
||||
creatorId: Long,
|
||||
parentFanTalkIds: List<Long>
|
||||
parentFanTalkIds: List<Long>,
|
||||
lang: Lang
|
||||
): List<CreatorChannelFanTalkReplyRecord> {
|
||||
replyParentFanTalkIds = parentFanTalkIds
|
||||
return creatorReplies
|
||||
|
||||
+20
-19
@@ -18,6 +18,7 @@ import kr.co.vividnext.sodalive.creator.admin.content.series.Series
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesContent
|
||||
import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers
|
||||
import kr.co.vividnext.sodalive.explorer.profile.channelDonation.ChannelDonationMessage
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.live.room.GenderRestriction
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoom
|
||||
import kr.co.vividnext.sodalive.live.room.visit.LiveRoomVisit
|
||||
@@ -70,8 +71,8 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
val aiCreator = saveMember("ai-creator", MemberRole.CREATOR, memberKind = MemberKind.AI_CHARACTER)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val aiRecord = repository.findCreator(aiCreator.id!!, viewer.id!!)
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val aiRecord = repository.findCreator(aiCreator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertNotNull(record)
|
||||
assertEquals(2, record!!.followerCount)
|
||||
@@ -91,7 +92,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveCharacter(creator, isActive = false)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewerId = null)
|
||||
val record = repository.findCreator(creator.id!!, viewerId = null, lang = Lang.KO)
|
||||
|
||||
assertEquals(null, record!!.characterId)
|
||||
assertFalse(record.isAiChatAvailable)
|
||||
@@ -108,7 +109,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveFollowing(saveMember("inactive-member-follower", MemberRole.USER, isActive = false), creator, isActive = true)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewerId = null)
|
||||
val record = repository.findCreator(creator.id!!, viewerId = null, lang = Lang.KO)
|
||||
|
||||
assertEquals(5, record!!.followerCount)
|
||||
}
|
||||
@@ -119,7 +120,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
val user = saveMember("non-creator-target", MemberRole.USER)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(user.id!!, viewerId = null)
|
||||
val record = repository.findCreator(user.id!!, viewerId = null, lang = Lang.KO)
|
||||
|
||||
assertNotNull(record)
|
||||
assertEquals(MemberRole.USER, record!!.role)
|
||||
@@ -216,7 +217,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
updateUpdatedAt("LiveRoom", currentLive.id!!, now.minusHours(1))
|
||||
flushAndClear()
|
||||
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val currentLiveRecord = repository.findCurrentLive(
|
||||
creator.id!!,
|
||||
now,
|
||||
@@ -231,7 +232,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
canViewAdultContent = false,
|
||||
viewerId = viewer.id!!
|
||||
)
|
||||
val donations = repository.findChannelDonations(creator.id!!, viewer.id!!, now, limit = 8)
|
||||
val donations = repository.findChannelDonations(creator.id!!, viewer.id!!, now, limit = 8, lang = Lang.KO)
|
||||
val schedules = repository.findSchedules(
|
||||
creator.id!!,
|
||||
now,
|
||||
@@ -250,7 +251,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
limit = 9
|
||||
)
|
||||
val seriesRecords = repository.findSeries(creator.id!!, viewer.id!!, now, false, ContentType.ALL, limit = 8)
|
||||
val fanTalkSummary = repository.findFanTalkSummary(creator.id!!, viewer.id!!)
|
||||
val fanTalkSummary = repository.findFanTalkSummary(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val activity = repository.findActivity(creator.id!!, now)
|
||||
val sns = repository.findSns(creator.id!!)
|
||||
|
||||
@@ -289,7 +290,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveFollowing(viewer, creator, isActive = false, isNotify = true)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertFalse(record!!.isFollow)
|
||||
assertFalse(record.isNotify)
|
||||
@@ -770,7 +771,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveCheers(writer, creator, "reply", isActive = true, LocalDateTime.of(2026, 6, 12, 14, 0), parent = older)
|
||||
flushAndClear()
|
||||
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!)
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(2, summary.totalCount)
|
||||
assertEquals(latest.id, summary.latestFanTalk!!.fanTalkId)
|
||||
@@ -788,9 +789,9 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
val thirdParty = saveMember("kst-donation-third-party", MemberRole.USER)
|
||||
flushAndClear()
|
||||
|
||||
val creatorView = repository.findChannelDonations(creator.id!!, creator.id!!, now, limit = 8)
|
||||
val donorView = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8)
|
||||
val thirdPartyView = repository.findChannelDonations(creator.id!!, thirdParty.id!!, now, limit = 8)
|
||||
val creatorView = repository.findChannelDonations(creator.id!!, creator.id!!, now, limit = 8, lang = Lang.KO)
|
||||
val donorView = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8, lang = Lang.KO)
|
||||
val thirdPartyView = repository.findChannelDonations(creator.id!!, thirdParty.id!!, now, limit = 8, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(300), creatorView.map { it.can })
|
||||
assertEquals(listOf(300), donorView.map { it.can })
|
||||
@@ -821,7 +822,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
)
|
||||
flushAndClear()
|
||||
|
||||
val records = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8)
|
||||
val records = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(1000, 3), records.map { it.can })
|
||||
assertEquals("응원합니다", records.first().message)
|
||||
@@ -837,7 +838,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveDonation(creator, donor, 1000, now.minusMinutes(1), isSecret = true, additionalMessage = "cheer")
|
||||
flushAndClear()
|
||||
|
||||
val records = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8)
|
||||
val records = repository.findChannelDonations(creator.id!!, donor.id!!, now, limit = 8, lang = Lang.KO)
|
||||
|
||||
assertEquals("cheer", records.single().message)
|
||||
}
|
||||
@@ -852,7 +853,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(writer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!)
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(0, summary.totalCount)
|
||||
assertEquals(null, summary.latestFanTalk)
|
||||
@@ -1042,7 +1043,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(writerBlockedViewer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!)
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(1, summary.totalCount)
|
||||
assertEquals(visibleTalk.id, summary.latestFanTalk!!.fanTalkId)
|
||||
@@ -1057,7 +1058,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
saveCheers(writer, creator, "visible", isActive = true, LocalDateTime.of(2026, 6, 12, 12, 0))
|
||||
flushAndClear()
|
||||
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!)
|
||||
val summary = repository.findFanTalkSummary(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals("fan", summary.latestFanTalk!!.nickname)
|
||||
}
|
||||
@@ -1085,7 +1086,7 @@ class DefaultCreatorChannelHomeQueryRepositoryTest @Autowired constructor(
|
||||
updateUpdatedAt("LiveRoom", futureLive.id!!, now.plusDays(1).plusHours(1))
|
||||
flushAndClear()
|
||||
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewerId = null)
|
||||
val creatorRecord = repository.findCreator(creator.id!!, viewerId = null, lang = Lang.KO)
|
||||
val activity = repository.findActivity(creator.id!!, now)
|
||||
val sns = repository.findSns(creator.id!!)
|
||||
|
||||
|
||||
+30
-21
@@ -70,7 +70,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val viewer = createMember(id = 10L, gender = Gender.FEMALE, authGender = 1)
|
||||
val now = LocalDateTime.of(2026, 6, 13, 10, 0)
|
||||
|
||||
val home = service.getHome(creatorId = 1L, viewer = viewer, now = now)
|
||||
val home = service.getHome(creatorId = 1L, viewer = viewer, now = now, lang = Lang.KO)
|
||||
|
||||
assertEquals(1L, home.creator.creatorId)
|
||||
assertEquals("https://cdn.test/profile/creator.png", home.creator.profileImageUrl)
|
||||
@@ -115,7 +115,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port, lang = Lang.JA)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.JA)
|
||||
|
||||
assertEquals("ja", port.latestAudioLocale)
|
||||
assertEquals("ja", port.audioContentsLocale)
|
||||
@@ -130,7 +130,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 1L, gender = Gender.FEMALE, authGender = null, role = MemberRole.CREATOR)
|
||||
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
|
||||
assertTrue(port.currentLiveIsViewerCreator == true)
|
||||
assertTrue(port.schedulesIsViewerCreator == true)
|
||||
@@ -145,7 +145,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L, role = MemberRole.CREATOR)
|
||||
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
|
||||
assertTrue(port.currentLiveIsViewerCreator == true)
|
||||
assertTrue(port.schedulesIsViewerCreator == true)
|
||||
@@ -158,7 +158,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L, role = MemberRole.USER)
|
||||
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
|
||||
assertFalse(port.currentLiveIsViewerCreator == true)
|
||||
assertFalse(port.schedulesIsViewerCreator == true)
|
||||
@@ -173,7 +173,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port, communityPort, preferenceService = preferenceService)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
|
||||
assertEquals(false, port.currentLiveCanViewAdultContent)
|
||||
assertEquals(false, port.schedulesCanViewAdultContent)
|
||||
@@ -191,7 +191,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val home = service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
val home = service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
|
||||
assertEquals("donor", home.channelDonations.first().nickname)
|
||||
}
|
||||
@@ -206,7 +206,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getHome(creatorId = 999L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(999L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -222,7 +222,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -239,7 +239,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -256,7 +256,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getHome(creatorId = 1L, viewer = viewer, now = LocalDateTime.of(2026, 6, 13, 10, 0))
|
||||
service.getHome(1L, viewer, LocalDateTime.of(2026, 6, 13, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -408,6 +408,7 @@ class CreatorChannelHomeQueryServiceTest {
|
||||
),
|
||||
channelDonations = listOf(
|
||||
CreatorChannelDonation(
|
||||
memberId = 20L,
|
||||
nickname = "fan",
|
||||
profileImageUrl = "fan.png",
|
||||
can = 50,
|
||||
@@ -593,7 +594,7 @@ private class FakeCreatorChannelHomeQueryPort : CreatorChannelHomeQueryPort {
|
||||
var seriesLocale: String? = null
|
||||
var channelDonationNickname: String = "fan"
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelCreatorRecord? = creator
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelCreatorRecord? = creator
|
||||
|
||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||
|
||||
@@ -634,9 +635,11 @@ private class FakeCreatorChannelHomeQueryPort : CreatorChannelHomeQueryPort {
|
||||
creatorId: Long,
|
||||
viewerId: Long?,
|
||||
now: LocalDateTime,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelDonationRecord> = listOf(
|
||||
CreatorChannelDonationRecord(
|
||||
memberId = 20L,
|
||||
nickname = channelDonationNickname,
|
||||
profileImagePath = "profile/fan.png",
|
||||
can = 30,
|
||||
@@ -710,7 +713,7 @@ private class FakeCreatorChannelHomeQueryPort : CreatorChannelHomeQueryPort {
|
||||
)
|
||||
}
|
||||
|
||||
override fun findFanTalkSummary(creatorId: Long, viewerId: Long?): CreatorChannelFanTalkSummaryRecord {
|
||||
override fun findFanTalkSummary(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelFanTalkSummaryRecord {
|
||||
return CreatorChannelFanTalkSummaryRecord(
|
||||
totalCount = 1,
|
||||
latestFanTalk = CreatorChannelFanTalkRecord(
|
||||
@@ -798,7 +801,7 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
val homeCanViewAdultContentValues = mutableListOf<Boolean>()
|
||||
val homeLimits = mutableListOf<Int>()
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelCommunityCreatorRecord? {
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelCommunityCreatorRecord? {
|
||||
return CreatorChannelCommunityCreatorRecord(creatorId = creatorId, role = MemberRole.CREATOR, nickname = "creator")
|
||||
}
|
||||
|
||||
@@ -811,7 +814,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
canViewAdultContent: Boolean,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityPostRecord> = emptyList()
|
||||
|
||||
override fun findHomeCommunityPosts(
|
||||
@@ -819,7 +823,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
isPinned: Boolean,
|
||||
canViewAdultContent: Boolean,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<CreatorChannelCommunityPostRecord> {
|
||||
homeCreatorIds += creatorId
|
||||
homeViewerIds += viewerId
|
||||
@@ -850,7 +855,8 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
override fun findCommunityPost(
|
||||
postId: Long,
|
||||
viewerId: Long,
|
||||
canViewAdultContent: Boolean
|
||||
canViewAdultContent: Boolean,
|
||||
lang: Lang
|
||||
): CreatorChannelCommunityPostRecord? = null
|
||||
|
||||
override fun countCommunityComments(postId: Long, viewerId: Long, creatorId: Long): Int = 0
|
||||
@@ -860,12 +866,14 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
viewerId: Long,
|
||||
creatorId: Long,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
) = emptyList<kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityCommentRecord>()
|
||||
|
||||
override fun findLatestRepliesByCommentIds(
|
||||
commentIds: List<Long>,
|
||||
viewerId: Long
|
||||
viewerId: Long,
|
||||
lang: Lang
|
||||
) = emptyList<kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityCommentRecord>()
|
||||
|
||||
override fun findRootCommentContext(
|
||||
@@ -880,6 +888,7 @@ private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQuer
|
||||
commentId: Long,
|
||||
viewerId: Long,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
) = emptyList<kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityCommentRecord>()
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.content.order.OrderType
|
||||
import kr.co.vividnext.sodalive.content.theme.AudioContentTheme
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesContent
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.live.room.GenderRestriction
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoom
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
@@ -274,7 +275,7 @@ class DefaultCreatorChannelLiveQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creator, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(creator.id, record!!.creatorId)
|
||||
assertEquals(MemberRole.CREATOR, record.role)
|
||||
|
||||
+14
-14
@@ -2,7 +2,6 @@ package kr.co.vividnext.sodalive.v2.creator.channel.live.application
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
@@ -42,7 +41,8 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
sort = ContentSort.LATEST,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1L, port.findCreatorCreatorId)
|
||||
@@ -75,7 +75,8 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
sort = ContentSort.LATEST,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0)
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0),
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertTrue(port.currentLiveIsViewerCreator == true)
|
||||
@@ -96,7 +97,8 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
sort = ContentSort.LATEST,
|
||||
page = 0,
|
||||
size = 20,
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0)
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0),
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(30, tab.liveReplayContentCount)
|
||||
@@ -127,7 +129,8 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
sort = ContentSort.PRICE_LOW,
|
||||
page = 2,
|
||||
size = 20,
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0)
|
||||
now = LocalDateTime.of(2026, 6, 17, 10, 0),
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(30, tab.liveReplayContentCount)
|
||||
@@ -151,7 +154,7 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0))
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -167,7 +170,7 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0))
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -184,7 +187,7 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0))
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 20, LocalDateTime.of(2026, 6, 17, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -198,7 +201,7 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, -1, 20, LocalDateTime.of(2026, 6, 17, 10, 0))
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, -1, 20, LocalDateTime.of(2026, 6, 17, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||
@@ -211,7 +214,7 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 51, LocalDateTime.of(2026, 6, 17, 10, 0))
|
||||
service.getLiveTab(1L, viewer, ContentSort.LATEST, 0, 51, LocalDateTime.of(2026, 6, 17, 10, 0), Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||
@@ -240,14 +243,11 @@ class CreatorChannelLiveQueryServiceTest {
|
||||
preferenceService.canViewAdultContent(Mockito.any(Member::class.java) ?: createMember(id = 0L))
|
||||
).thenReturn(canViewAdultContent)
|
||||
val messageSource = SodaMessageSource()
|
||||
val langContext = LangContext()
|
||||
langContext.setLang(Lang.KO)
|
||||
return CreatorChannelLiveQueryService(
|
||||
queryPortProvider = portProvider,
|
||||
queryPolicy = CreatorChannelLiveReplayQueryPolicy(),
|
||||
memberContentPreferenceService = preferenceService,
|
||||
messageSource = messageSource,
|
||||
langContext = langContext,
|
||||
cloudFrontHost = "https://cdn.test"
|
||||
)
|
||||
}
|
||||
@@ -337,7 +337,7 @@ private class FakeCreatorChannelLiveQueryPort : CreatorChannelLiveQueryPort {
|
||||
var listOffset: Long? = null
|
||||
var listLimit: Int? = null
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelCreatorRecord? {
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelCreatorRecord? {
|
||||
findCreatorCreatorId = creatorId
|
||||
findCreatorViewerId = viewerId
|
||||
return creator
|
||||
|
||||
+3
-2
@@ -13,6 +13,7 @@ import kr.co.vividnext.sodalive.creator.admin.content.series.Series
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesContent
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesState
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMember
|
||||
@@ -50,8 +51,8 @@ class DefaultCreatorChannelSeriesQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creator, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!)
|
||||
val record = repository.findCreator(creator.id!!, viewer.id!!, Lang.KO)
|
||||
val inactiveRecord = repository.findCreator(inactiveCreator.id!!, viewer.id!!, Lang.KO)
|
||||
|
||||
assertEquals(creator.id, record!!.creatorId)
|
||||
assertEquals(MemberRole.CREATOR, record.role)
|
||||
|
||||
+8
-7
@@ -42,7 +42,8 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
sort = "UNKNOWN",
|
||||
page = -1,
|
||||
size = 100,
|
||||
now = now
|
||||
now = now,
|
||||
lang = Lang.EN
|
||||
)
|
||||
|
||||
assertEquals(ContentSort.LATEST, tab.sort)
|
||||
@@ -70,7 +71,7 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 1L)
|
||||
|
||||
val tab = service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0))
|
||||
val tab = service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0), Lang.EN)
|
||||
|
||||
assertNull(tab.series.first().purchasedContentCount)
|
||||
assertNull(tab.series.first().paidContentCount)
|
||||
@@ -86,7 +87,7 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
val service = createService(port)
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val tab = service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0))
|
||||
val tab = service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0), Lang.EN)
|
||||
|
||||
assertNull(tab.series.first().coverImageUrl)
|
||||
assertEquals(0, tab.series.first().purchasedPaidContentRate)
|
||||
@@ -100,7 +101,7 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0))
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||
@@ -114,7 +115,7 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0))
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||
@@ -128,7 +129,7 @@ class CreatorChannelSeriesQueryServiceTest {
|
||||
val viewer = createMember(id = 10L)
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0))
|
||||
service.getSeriesTab(1L, viewer, null, null, null, LocalDateTime.of(2026, 6, 20, 10, 0), Lang.EN)
|
||||
}
|
||||
|
||||
assertNull(exception.messageKey)
|
||||
@@ -192,7 +193,7 @@ private class FakeCreatorChannelSeriesQueryPort : CreatorChannelSeriesQueryPort
|
||||
var listLimit: Int? = null
|
||||
var listCanViewAdultContent: Boolean? = null
|
||||
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelSeriesCreatorRecord? = creator
|
||||
override fun findCreator(creatorId: Long, viewerId: Long?, lang: Lang): CreatorChannelSeriesCreatorRecord? = creator
|
||||
|
||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||
override fun countSeries(creatorId: Long, now: LocalDateTime, canViewAdultContent: Boolean): Int = seriesCount
|
||||
|
||||
+31
-21
@@ -2,8 +2,11 @@ package kr.co.vividnext.sodalive.v2.gift.application
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.support.LegacyCreatorNameTestConfiguration
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.Gift
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategory
|
||||
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategoryRepository
|
||||
@@ -35,14 +38,15 @@ import java.time.LocalDateTime
|
||||
"spring.datasource.url=jdbc:h2:mem:gift-query;MODE=MySQL;NON_KEYWORDS=VALUE"
|
||||
]
|
||||
)
|
||||
@Import(QueryDslConfig::class)
|
||||
@Import(QueryDslConfig::class, LegacyCreatorNameTestConfiguration::class)
|
||||
class GiftQueryServiceTest @Autowired constructor(
|
||||
private val categoryRepository: GiftCategoryRepository,
|
||||
private val sizePriceRepository: GiftSizePriceRepository,
|
||||
private val giftRepository: GiftRepository,
|
||||
private val deliveryRepository: GiftDeliveryRepository,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val giftMailboxRepository: GiftMailboxRepository
|
||||
private val giftMailboxRepository: GiftMailboxRepository,
|
||||
private val creatorLocalizedNameService: CreatorLocalizedNameService
|
||||
) {
|
||||
@Test
|
||||
fun `폼 옵션은 활성 카테고리와 활성 사이즈 가격만 반환한다`() {
|
||||
@@ -79,7 +83,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
memberId = sender.id!!,
|
||||
type = GiftListType.SENT,
|
||||
page = 0,
|
||||
size = 20
|
||||
size = 20,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1L, result.totalCount)
|
||||
@@ -122,7 +127,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
memberId = recipient.id!!,
|
||||
type = GiftListType.RECEIVED,
|
||||
page = 0,
|
||||
size = 20
|
||||
size = 20,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1L, result.totalCount)
|
||||
@@ -162,7 +168,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
memberId = member.id!!,
|
||||
type = GiftListType.ALL,
|
||||
page = 0,
|
||||
size = 20
|
||||
size = 20,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2L, result.totalCount)
|
||||
@@ -220,7 +227,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
memberId = member.id!!,
|
||||
type = GiftListType.ALL,
|
||||
page = 0,
|
||||
size = 20
|
||||
size = 20,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val items = result.items.associateBy { it.applicationNo }
|
||||
@@ -245,7 +253,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
memberId = sender.id!!,
|
||||
type = GiftListType.SENT,
|
||||
page = -1,
|
||||
size = 0
|
||||
size = 0,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(0, result.page)
|
||||
@@ -272,7 +281,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
delivery.recipientAddress = "서울시 중구"
|
||||
delivery.recipientAddressDetail = "202호"
|
||||
|
||||
val result = queryService().getGiftDetail(sender.id!!, gift.applicationNo)
|
||||
val result = queryService().getGiftDetail(sender.id!!, gift.applicationNo, Lang.KO)
|
||||
|
||||
assertEquals(GiftDirection.SENT, result.direction)
|
||||
assertEquals(recipient.nickname, result.giftInfo.recipientCreatorNickname)
|
||||
@@ -335,7 +344,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
)
|
||||
saveDelivery(gift).applyStatusTimes(status)
|
||||
|
||||
val result = service.getGiftDetail(sender.id!!, gift.applicationNo)
|
||||
val result = service.getGiftDetail(sender.id!!, gift.applicationNo, Lang.KO)
|
||||
|
||||
assertEquals("소다라이브 선물 담당자", result.mailbox?.name)
|
||||
assertEquals("01012345678", result.mailbox?.phoneNumber)
|
||||
@@ -370,7 +379,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
)
|
||||
saveDelivery(gift).applyStatusTimes(status)
|
||||
|
||||
val result = service.getGiftDetail(sender.id!!, gift.applicationNo)
|
||||
val result = service.getGiftDetail(sender.id!!, gift.applicationNo, Lang.KO)
|
||||
|
||||
assertNull(result.mailbox)
|
||||
}
|
||||
@@ -383,7 +392,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
)
|
||||
saveDelivery(receivedGift).applyStatusTimes(GiftStatus.TRACKING_REGISTERED)
|
||||
|
||||
val recipientResult = service.getGiftDetail(recipient.id!!, receivedGift.applicationNo)
|
||||
val recipientResult = service.getGiftDetail(recipient.id!!, receivedGift.applicationNo, Lang.KO)
|
||||
|
||||
assertNull(recipientResult.mailbox)
|
||||
}
|
||||
@@ -401,7 +410,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
)
|
||||
saveDelivery(gift).applyStatusTimes(GiftStatus.INSPECTION_COMPLETED)
|
||||
|
||||
val result = queryService().getGiftDetail(sender.id!!, gift.applicationNo)
|
||||
val result = queryService().getGiftDetail(sender.id!!, gift.applicationNo, Lang.KO)
|
||||
|
||||
assertNull(result.mailbox)
|
||||
}
|
||||
@@ -426,7 +435,7 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
recipientAddressDetail = "202호"
|
||||
}
|
||||
|
||||
val result = queryService().getGiftDetail(recipient.id!!, gift.applicationNo)
|
||||
val result = queryService().getGiftDetail(recipient.id!!, gift.applicationNo, Lang.KO)
|
||||
|
||||
assertEquals(GiftDirection.RECEIVED, result.direction)
|
||||
assertNull(result.giftInfo.recipientCreatorNickname)
|
||||
@@ -478,13 +487,13 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
val service = queryService()
|
||||
|
||||
val hiddenException = assertThrows(SodaException::class.java) {
|
||||
service.getGiftDetail(recipient.id!!, hiddenGift.applicationNo)
|
||||
service.getGiftDetail(recipient.id!!, hiddenGift.applicationNo, Lang.KO)
|
||||
}
|
||||
val unrelatedException = assertThrows(SodaException::class.java) {
|
||||
service.getGiftDetail(other.id!!, visibleGift.applicationNo)
|
||||
service.getGiftDetail(other.id!!, visibleGift.applicationNo, Lang.KO)
|
||||
}
|
||||
val missingDeliveryException = assertThrows(SodaException::class.java) {
|
||||
service.getGiftDetail(sender.id!!, missingDeliveryGift.applicationNo)
|
||||
service.getGiftDetail(sender.id!!, missingDeliveryGift.applicationNo, Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("common.error.invalid_request", hiddenException.messageKey)
|
||||
@@ -517,8 +526,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
}
|
||||
val service = queryService()
|
||||
|
||||
val pendingResult = service.getGiftDetail(recipient.id!!, pendingGift.applicationNo)
|
||||
val terminalResult = service.getGiftDetail(recipient.id!!, terminalGift.applicationNo)
|
||||
val pendingResult = service.getGiftDetail(recipient.id!!, pendingGift.applicationNo, Lang.KO)
|
||||
val terminalResult = service.getGiftDetail(recipient.id!!, terminalGift.applicationNo, Lang.KO)
|
||||
|
||||
assertEquals(true, pendingResult.recipientAddressRequired)
|
||||
assertNull(pendingResult.recipientAddress)
|
||||
@@ -551,8 +560,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
}
|
||||
val service = queryService()
|
||||
|
||||
val canceledResult = service.getGiftDetail(sender.id!!, canceledGift.applicationNo)
|
||||
val undeliverableResult = service.getGiftDetail(sender.id!!, undeliverableGift.applicationNo)
|
||||
val canceledResult = service.getGiftDetail(sender.id!!, canceledGift.applicationNo, Lang.KO)
|
||||
val undeliverableResult = service.getGiftDetail(sender.id!!, undeliverableGift.applicationNo, Lang.KO)
|
||||
|
||||
assertEquals(NOW.plusHours(1), canceledResult.delivery.canceledAt)
|
||||
assertNull(canceledResult.statusTimeline[1].occurredAt)
|
||||
@@ -639,7 +648,8 @@ class GiftQueryServiceTest @Autowired constructor(
|
||||
deliveryRepository,
|
||||
memberRepository,
|
||||
giftMailboxRepository,
|
||||
"https://cdn.test"
|
||||
"https://cdn.test",
|
||||
creatorLocalizedNameService
|
||||
)
|
||||
|
||||
private companion object {
|
||||
|
||||
+45
-23
@@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.content.theme.AudioContentTheme
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityComment
|
||||
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLike
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.live.room.GenderRestriction
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoom
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
@@ -62,7 +63,7 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
activeFollow.createdAt = LocalDateTime.of(2026, 6, 25, 0, 0)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findFollowingCreators(memberId = viewer.id!!, limit = 20)
|
||||
val creators = repository.findFollowingCreators(memberId = viewer.id!!, limit = 20, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(olderCreator.id!!, activeCreator.id!!), creators.map { it.creatorId })
|
||||
assertEquals("https://cdn.test/active.png", creators.last().creatorProfileImageUrl)
|
||||
@@ -82,7 +83,7 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creatorBlockedViewer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findFollowingCreators(memberId = viewer.id!!, limit = 20)
|
||||
val creators = repository.findFollowingCreators(memberId = viewer.id!!, limit = 20, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(visibleCreator.id!!), creators.map { it.creatorId })
|
||||
}
|
||||
@@ -110,7 +111,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
canViewAdultContent = false,
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
isViewerCreator = false,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(latest.id!!, older.id!!), lives.map { it.liveId })
|
||||
@@ -143,7 +145,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
canViewAdultContent = true,
|
||||
effectiveViewerGender = Gender.FEMALE,
|
||||
isViewerCreator = true,
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visible.id!!), lives.map { it.liveId })
|
||||
@@ -175,7 +178,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
isViewerCreator = false,
|
||||
now = LocalDateTime.of(2026, 6, 25, 12, 0),
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf("LIVE:${live.id!!}", "AUDIO:${audio.id!!}"), schedules.map { it.scheduleId })
|
||||
@@ -210,7 +214,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
isViewerCreator = false,
|
||||
now = LocalDateTime.of(2026, 6, 25, 0, 0),
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf("AUDIO:${scheduledAudio.id!!}"), schedules.map { it.scheduleId })
|
||||
@@ -233,7 +238,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
isViewerCreator = false,
|
||||
now = LocalDateTime.of(2026, 6, 25, 14, 30),
|
||||
limit = 3
|
||||
limit = 3,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertTrue(schedules.map { it.scheduleId }.contains("AUDIO:${sameKstDayEvening.id!!}"))
|
||||
@@ -259,7 +265,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
isViewerCreator = false,
|
||||
now = LocalDateTime.of(2026, 6, 25, 0, 0),
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
@@ -302,7 +309,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
effectiveViewerGender = Gender.FEMALE,
|
||||
isViewerCreator = true,
|
||||
now = LocalDateTime.of(2026, 6, 25, 0, 0),
|
||||
limit = 10
|
||||
limit = 10,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf("LIVE:${visibleLive.id!!}", "AUDIO:${audio.id!!}"), schedules.map { it.scheduleId })
|
||||
@@ -332,7 +340,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 9, 30),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(latestVisible.id!!.toString()), news.map { it.newsId })
|
||||
@@ -377,13 +386,15 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 14, 23, 59),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val afterLatestVisible = repository.findRecentNews(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 15, 0, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(oldSecondNews.id!!.toString(), oldFirstNews.id!!.toString()), beforeLatestVisible.map { it.newsId })
|
||||
@@ -412,7 +423,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 15, 0, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertTrue(news.none { it.type == FollowingNewsType.CREATOR_RANKING })
|
||||
@@ -475,7 +487,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 2
|
||||
limit = 2,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(latestFirst.id!!.toString(), latestSecond.id!!.toString()), news.map { it.newsId })
|
||||
@@ -516,7 +529,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 11, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visible.id!!.toString()), news.map { it.newsId })
|
||||
@@ -556,7 +570,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 11, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visible.id!!.toString()), news.map { it.newsId })
|
||||
@@ -577,7 +592,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 14, 30),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visibleNow.id!!.toString()), news.map { it.newsId })
|
||||
@@ -628,7 +644,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val communityNews = news.first { it.type == FollowingNewsType.COMMUNITY_POST }.communityPost!!
|
||||
@@ -668,7 +685,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertTrue(news.isEmpty())
|
||||
@@ -713,7 +731,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(negativeFreePost.id!!, freePost.id!!), news.map { it.communityPost?.postId })
|
||||
@@ -759,13 +778,15 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = false,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val visibleNews = repository.findRecentNews(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(emptyList<Long>(), hiddenNews.map { it.communityPost?.postId ?: it.audioContent?.contentId })
|
||||
@@ -824,7 +845,8 @@ class DefaultHomeFollowingQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
canViewAdultContent = true,
|
||||
nowUtc = LocalDateTime.of(2026, 6, 25, 10, 0),
|
||||
limit = 30
|
||||
limit = 30,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
|
||||
+14
-14
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.home.following.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
@@ -29,13 +28,11 @@ import java.util.TimeZone
|
||||
class HomeFollowingQueryServiceTest {
|
||||
private val queryPort = RecordingHomeFollowingQueryPort()
|
||||
private val memberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
private val langContext = LangContext()
|
||||
private val creatorCommunityTranslationService = Mockito.mock(CreatorCommunityTranslationService::class.java)
|
||||
private val now = LocalDateTime.of(2026, 6, 25, 12, 0)
|
||||
private val service = HomeFollowingQueryService(
|
||||
queryPort,
|
||||
memberContentPreferenceService,
|
||||
langContext,
|
||||
creatorCommunityTranslationService
|
||||
) { now }
|
||||
|
||||
@@ -45,7 +42,7 @@ class HomeFollowingQueryServiceTest {
|
||||
val member = member(10L)
|
||||
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(true)
|
||||
|
||||
val home = service.findHomeFollowing(member)
|
||||
val home = service.findHomeFollowing(member, Lang.KO)
|
||||
|
||||
assertEquals(listOf(HomeFollowingCreator(1L, "creator", "profile")), home.followingCreators)
|
||||
assertEquals(emptyList<Any>(), home.recentChats)
|
||||
@@ -63,7 +60,7 @@ class HomeFollowingQueryServiceTest {
|
||||
val member = member(11L)
|
||||
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(false)
|
||||
|
||||
service.findHomeFollowing(member)
|
||||
service.findHomeFollowing(member, Lang.KO)
|
||||
|
||||
assertEquals(false, queryPort.onAirCanViewAdultContent)
|
||||
assertEquals(false, queryPort.monthlySchedulesCanViewAdultContent)
|
||||
@@ -81,7 +78,7 @@ class HomeFollowingQueryServiceTest {
|
||||
}
|
||||
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(true)
|
||||
|
||||
service.findHomeFollowing(member)
|
||||
service.findHomeFollowing(member, Lang.KO)
|
||||
|
||||
assertEquals(Gender.FEMALE, queryPort.onAirEffectiveViewerGender)
|
||||
assertEquals(Gender.FEMALE, queryPort.monthlySchedulesEffectiveViewerGender)
|
||||
@@ -99,14 +96,13 @@ class HomeFollowingQueryServiceTest {
|
||||
val defaultService = HomeFollowingQueryService(
|
||||
defaultQueryPort,
|
||||
memberContentPreferenceService,
|
||||
langContext,
|
||||
creatorCommunityTranslationService
|
||||
)
|
||||
val member = member(12L)
|
||||
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(true)
|
||||
val beforeUtc = LocalDateTime.now(ZoneOffset.UTC).minusSeconds(1)
|
||||
|
||||
defaultService.findHomeFollowing(member)
|
||||
defaultService.findHomeFollowing(member, Lang.KO)
|
||||
|
||||
val afterUtc = LocalDateTime.now(ZoneOffset.UTC).plusSeconds(1)
|
||||
val capturedNow = defaultQueryPort.recentNewsNow!!
|
||||
@@ -121,9 +117,9 @@ class HomeFollowingQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("팔로잉 최근 소식은 커뮤니티 게시물만 영어 표시 본문으로 일괄 치환하고 다른 소식과 원문 폴백을 유지한다")
|
||||
fun shouldTranslateOnlyCommunityPostNewsInOneEnglishBatch() {
|
||||
langContext.setLang(Lang.EN)
|
||||
val translatedNews = communityNews("community-1", 101L, "original-1")
|
||||
val audioNews = HomeFollowingNews(
|
||||
creatorMemberId = 10L,
|
||||
newsId = "audio-1",
|
||||
type = FollowingNewsType.AUDIO_CONTENT,
|
||||
visibleFromAtUtc = "2026-06-25T11:59:00Z"
|
||||
@@ -138,7 +134,7 @@ class HomeFollowingQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val home = service.findHomeFollowing(member(14L))
|
||||
val home = service.findHomeFollowing(member(14L), Lang.EN)
|
||||
|
||||
assertEquals("translated-1-en", home.recentNews[0].communityPost?.content)
|
||||
assertEquals(audioNews, home.recentNews[1])
|
||||
@@ -153,6 +149,7 @@ class HomeFollowingQueryServiceTest {
|
||||
|
||||
private fun communityNews(newsId: String, postId: Long, content: String): HomeFollowingNews {
|
||||
return HomeFollowingNews(
|
||||
creatorMemberId = 10L,
|
||||
newsId = newsId,
|
||||
type = FollowingNewsType.COMMUNITY_POST,
|
||||
visibleFromAtUtc = "2026-06-25T12:00:00Z",
|
||||
@@ -186,7 +183,7 @@ class HomeFollowingQueryServiceTest {
|
||||
var recentNewsCanViewAdultContent: Boolean? = null
|
||||
var recentNews: List<HomeFollowingNews> = emptyList()
|
||||
|
||||
override fun findFollowingCreators(memberId: Long, limit: Int): List<HomeFollowingCreator> {
|
||||
override fun findFollowingCreators(memberId: Long, limit: Int, lang: Lang): List<HomeFollowingCreator> {
|
||||
this.memberId = memberId
|
||||
followingCreatorsLimit = limit
|
||||
return listOf(HomeFollowingCreator(1L, "creator", "profile"))
|
||||
@@ -197,7 +194,8 @@ class HomeFollowingQueryServiceTest {
|
||||
canViewAdultContent: Boolean,
|
||||
effectiveViewerGender: Gender,
|
||||
isViewerCreator: Boolean,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<HomeFollowingLive> {
|
||||
onAirCanViewAdultContent = canViewAdultContent
|
||||
onAirEffectiveViewerGender = effectiveViewerGender
|
||||
@@ -212,7 +210,8 @@ class HomeFollowingQueryServiceTest {
|
||||
effectiveViewerGender: Gender,
|
||||
isViewerCreator: Boolean,
|
||||
now: LocalDateTime,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<HomeFollowingSchedule> {
|
||||
monthlySchedulesCanViewAdultContent = canViewAdultContent
|
||||
monthlySchedulesEffectiveViewerGender = effectiveViewerGender
|
||||
@@ -226,7 +225,8 @@ class HomeFollowingQueryServiceTest {
|
||||
memberId: Long,
|
||||
canViewAdultContent: Boolean,
|
||||
nowUtc: LocalDateTime,
|
||||
limit: Int
|
||||
limit: Int,
|
||||
lang: Lang
|
||||
): List<HomeFollowingNews> {
|
||||
recentNewsCanViewAdultContent = canViewAdultContent
|
||||
recentNewsNow = nowUtc
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.ranking.adapter.out.persistence
|
||||
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingScoreSpec
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingType
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotRecord
|
||||
@@ -98,7 +99,7 @@ class DefaultCreatorRankingSnapshotRepositoryTest @Autowired constructor(
|
||||
)
|
||||
)
|
||||
|
||||
val latestVisible = adapter.findLatestVisibleSnapshots(CreatorRankingType.WEEKLY, NOW)
|
||||
val latestVisible = adapter.findLatestVisibleSnapshots(CreatorRankingType.WEEKLY, NOW, Lang.KO)
|
||||
|
||||
assertEquals(listOf(3L, 4L, 2L), latestVisible.map { it.creatorId })
|
||||
assertEquals(listOf(1, 2, 3), latestVisible.map { it.rankNo })
|
||||
|
||||
+12
-6
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.ranking.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingType
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingBlockPort
|
||||
import kr.co.vividnext.sodalive.v2.ranking.port.out.CreatorRankingSnapshotPort
|
||||
@@ -19,7 +20,11 @@ class CreatorRankingQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("fallback refresh 후 재조회가 같은 read-only transaction에 묶이지 않도록 조회 메서드에는 Transactional이 없다")
|
||||
fun shouldNotWrapQueryMethodWithTransactional() {
|
||||
val method = CreatorRankingQueryService::class.java.getDeclaredMethod("getCreatorRankings", java.lang.Long::class.java)
|
||||
val method = CreatorRankingQueryService::class.java.getDeclaredMethod(
|
||||
"getCreatorRankings",
|
||||
java.lang.Long::class.java,
|
||||
Lang::class.java
|
||||
)
|
||||
|
||||
assertFalse(method.isAnnotationPresent(Transactional::class.java))
|
||||
}
|
||||
@@ -32,7 +37,7 @@ class CreatorRankingQueryServiceTest {
|
||||
snapshotPort.latestResponses = ArrayDeque(listOf(emptyList(), listOf(snapshot(1, rankNo = 1))))
|
||||
val service = service(snapshotPort = snapshotPort, snapshotJobService = jobService)
|
||||
|
||||
val result = service.getCreatorRankings(viewerMemberId = null)
|
||||
val result = service.getCreatorRankings(viewerMemberId = null, lang = Lang.KO)
|
||||
|
||||
Mockito.verify(jobService).refreshLastCompletedWeekByFallback()
|
||||
assertEquals(2, snapshotPort.latestCallCount)
|
||||
@@ -48,7 +53,7 @@ class CreatorRankingQueryServiceTest {
|
||||
Mockito.doThrow(IllegalStateException("fallback failed")).`when`(jobService).refreshLastCompletedWeekByFallback()
|
||||
val service = service(snapshotPort = snapshotPort, snapshotJobService = jobService)
|
||||
|
||||
val result = service.getCreatorRankings(viewerMemberId = null)
|
||||
val result = service.getCreatorRankings(viewerMemberId = null, lang = Lang.KO)
|
||||
|
||||
assertFalse(result.showRankChange)
|
||||
assertTrue(result.items.isEmpty())
|
||||
@@ -66,7 +71,7 @@ class CreatorRankingQueryServiceTest {
|
||||
snapshotPort.previousSnapshots = listOf(snapshot(1, rankNo = 1), snapshot(2, rankNo = 2))
|
||||
val service = service(snapshotPort = snapshotPort, snapshotJobService = jobService)
|
||||
|
||||
val result = service.getCreatorRankings(viewerMemberId = null)
|
||||
val result = service.getCreatorRankings(viewerMemberId = null, lang = Lang.KO)
|
||||
|
||||
Mockito.verify(jobService, Mockito.never()).refreshLastCompletedWeekByFallback()
|
||||
assertTrue(result.showRankChange)
|
||||
@@ -86,7 +91,7 @@ class CreatorRankingQueryServiceTest {
|
||||
blockPort.blockedCreatorIds = setOf(2L)
|
||||
val service = service(snapshotPort = snapshotPort, blockPort = blockPort)
|
||||
|
||||
val result = service.getCreatorRankings(viewerMemberId = 99L)
|
||||
val result = service.getCreatorRankings(viewerMemberId = 99L, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(1, 2), result.items.map { it.rank })
|
||||
assertEquals(0L, result.items[1].creatorId)
|
||||
@@ -133,7 +138,8 @@ private class FakeCreatorRankingQuerySnapshotPort : CreatorRankingSnapshotPort {
|
||||
|
||||
override fun findLatestVisibleSnapshots(
|
||||
rankingType: CreatorRankingType,
|
||||
nowUtc: LocalDateTime
|
||||
nowUtc: LocalDateTime,
|
||||
lang: Lang
|
||||
): List<CreatorRankingSnapshotRecord> {
|
||||
latestCallCount++
|
||||
return if (latestResponses.size > 1) {
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.ranking.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.home.following.application.HomeFollowingNewsPublishService
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingScoreSpec
|
||||
import kr.co.vividnext.sodalive.v2.ranking.domain.CreatorRankingSnapshotCandidate
|
||||
@@ -120,7 +121,7 @@ private class FakeCreatorRankingSnapshotPort : CreatorRankingSnapshotPort {
|
||||
) = snapshots
|
||||
override fun findLatestSnapshots() = snapshots
|
||||
override fun findPreviousCompletedSnapshots() = snapshots
|
||||
override fun findLatestVisibleSnapshots(rankingType: CreatorRankingType, nowUtc: LocalDateTime) = snapshots
|
||||
override fun findLatestVisibleSnapshots(rankingType: CreatorRankingType, nowUtc: LocalDateTime, lang: Lang) = snapshots
|
||||
override fun findPreviousVisibleSnapshots(
|
||||
rankingType: CreatorRankingType,
|
||||
currentAggregationStartAtUtc: LocalDateTime,
|
||||
|
||||
+84
-52
@@ -89,7 +89,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
}
|
||||
flushAndClear()
|
||||
|
||||
val lives = repository.findLiveRecommendations(limit = 20, includeAdultLives = false)
|
||||
val lives = repository.findLiveRecommendations(limit = 20, includeAdultLives = false, lang = Lang.KO)
|
||||
|
||||
assertEquals(20, lives.size)
|
||||
assertEquals(true, lives.zipWithNext().all { it.first.liveRoomId > it.second.liveRoomId })
|
||||
@@ -109,8 +109,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val oldest = saveLiveRoom(creator, baseAt, channelName = "paged-live-oldest", isAdult = false)
|
||||
flushAndClear()
|
||||
|
||||
val page0 = repository.findLiveRecommendations(offset = 0L, limit = 3, includeAdultLives = false)
|
||||
val page1 = repository.findLiveRecommendations(offset = 2L, limit = 3, includeAdultLives = false)
|
||||
val page0 = repository.findLiveRecommendations(offset = 0L, limit = 3, includeAdultLives = false, lang = Lang.KO)
|
||||
val page1 = repository.findLiveRecommendations(offset = 2L, limit = 3, includeAdultLives = false, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(newest.id, middle.id, oldest.id), page0.map { it.liveRoomId })
|
||||
assertEquals(listOf(oldest.id), page1.map { it.liveRoomId })
|
||||
@@ -135,7 +135,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
offset = 0,
|
||||
limit = 1,
|
||||
memberId = viewer.id,
|
||||
includeAdultLives = true
|
||||
includeAdultLives = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(live.id), lives.map { it.liveRoomId })
|
||||
@@ -170,7 +171,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
offset = 0,
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
includeAdultLives = false
|
||||
includeAdultLives = false,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(newerVisibleLive.id, olderVisibleLive.id), lives.map { it.liveRoomId })
|
||||
@@ -191,7 +193,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creatorBlockedViewer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val lives = repository.findLiveRecommendations(limit = 10, memberId = viewer.id)
|
||||
val lives = repository.findLiveRecommendations(limit = 10, memberId = viewer.id, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(visibleLive.id), lives.map { it.liveRoomId })
|
||||
}
|
||||
@@ -221,7 +223,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
isViewerCreator = true,
|
||||
effectiveViewerGender = Gender.NONE
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(ownerLive.id, availableLive.id), lives.map { it.liveRoomId })
|
||||
@@ -244,7 +247,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
isViewerCreator = false,
|
||||
effectiveViewerGender = Gender.NONE
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(restrictedLive.id), lives.map { it.liveRoomId })
|
||||
@@ -281,7 +285,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
isViewerCreator = true,
|
||||
effectiveViewerGender = Gender.MALE
|
||||
effectiveViewerGender = Gender.MALE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(ownerLive.id, allLive.id, maleOnlyLive.id), lives.map { it.liveRoomId })
|
||||
@@ -311,7 +316,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
isViewerCreator = true,
|
||||
effectiveViewerGender = Gender.FEMALE
|
||||
effectiveViewerGender = Gender.FEMALE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(ownerLive.id, femaleOnlyLive.id), lives.map { it.liveRoomId })
|
||||
@@ -341,7 +347,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val lives = repository.findLiveRecommendations(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
effectiveViewerGender = Gender.FEMALE
|
||||
effectiveViewerGender = Gender.FEMALE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(femaleOnlyLive.id, allLive.id), lives.map { it.liveRoomId })
|
||||
@@ -371,12 +378,14 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val noneGenderLives = repository.findLiveRecommendations(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
effectiveViewerGender = Gender.NONE
|
||||
effectiveViewerGender = Gender.NONE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val nullGenderLives = repository.findLiveRecommendations(
|
||||
limit = 10,
|
||||
memberId = viewer.id,
|
||||
effectiveViewerGender = null
|
||||
effectiveViewerGender = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val expectedIds = listOf(allLive.id, femaleOnlyLive.id, maleOnlyLive.id)
|
||||
@@ -659,7 +668,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("CreatorCommunity", community.id!!, baseAt.minusHours(3))
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10)
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10, lang = Lang.KO)
|
||||
val byCreatorNickname = creators.associateBy { it.creatorNickname }
|
||||
|
||||
assertEquals(4, creators.size)
|
||||
@@ -699,7 +708,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveLiveRoom(emptyChannelCreator, baseAt, channelName = "", isActive = false)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10)
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(inactiveLiveCreator.nickname), creators.map { it.creatorNickname })
|
||||
assertEquals(inactiveLiveCreator.id, creators.single().creatorId)
|
||||
@@ -723,8 +732,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("CreatorCommunity", adultCommunity.id!!, baseAt)
|
||||
flushAndClear()
|
||||
|
||||
val hiddenCreators = repository.findRecentlyActiveCreators(limit = 10, includeAdultActivities = false)
|
||||
val visibleCreators = repository.findRecentlyActiveCreators(limit = 10, includeAdultActivities = true)
|
||||
val hiddenCreators = repository.findRecentlyActiveCreators(limit = 10, includeAdultActivities = false, lang = Lang.KO)
|
||||
val visibleCreators = repository.findRecentlyActiveCreators(limit = 10, includeAdultActivities = true, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(normalLiveCreator.nickname), hiddenCreators.map { it.creatorNickname })
|
||||
assertEquals(
|
||||
@@ -762,7 +771,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creatorBlockedViewer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10, memberId = viewer.id)
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10, memberId = viewer.id, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(visibleCreator.nickname), creators.map { it.creatorNickname })
|
||||
assertEquals(CreatorActivityType.COMMUNITY, creators.single().activityType)
|
||||
@@ -779,7 +788,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("CreatorCommunity", community.id!!, baseAt.plusMinutes(1))
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10)
|
||||
val creators = repository.findRecentlyActiveCreators(limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(visibleCreator.nickname), creators.map { it.creatorNickname })
|
||||
assertEquals(CreatorActivityType.COMMUNITY, creators.single().activityType)
|
||||
@@ -1597,7 +1606,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("Member", newHighScoreCreator.id!!, now.minusDays(60))
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10)
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(newHighScoreCreator.id, newLowScoreCreator.id), creators.map { it.creatorId })
|
||||
}
|
||||
@@ -1623,7 +1632,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10)
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(endedLiveCreator.id), creators.map { it.creatorId })
|
||||
}
|
||||
@@ -1647,7 +1656,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("AudioContentLike", baseLike2.id!!, now.minusDays(1))
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 2)
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 2, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(boostedCreator.id, baseCreator.id), creators.map { it.creatorId })
|
||||
}
|
||||
@@ -1671,8 +1680,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
updateCreatedAt("AudioContentLike", like.id!!, now.minusHours(1))
|
||||
flushAndClear()
|
||||
|
||||
val page0 = repository.findRecentDebutCreators(now, offset = 0L, limit = 2, includeAdultContents = false)
|
||||
val page1 = repository.findRecentDebutCreators(now, offset = 1L, limit = 2, includeAdultContents = false)
|
||||
val page0 = repository.findRecentDebutCreators(now, offset = 0L, limit = 2, includeAdultContents = false, lang = Lang.KO)
|
||||
val page1 = repository.findRecentDebutCreators(now, offset = 1L, limit = 2, includeAdultContents = false, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(normalNewest.id, normalOldest.id), page0.map { it.creatorId })
|
||||
assertEquals(listOf(normalOldest.id), page1.map { it.creatorId })
|
||||
@@ -1693,7 +1702,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveBlock(creatorBlockedViewer, viewer)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10, memberId = viewer.id)
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10, memberId = viewer.id, lang = Lang.KO)
|
||||
|
||||
assertEquals(listOf(visibleCreator.id), creators.map { it.creatorId })
|
||||
}
|
||||
@@ -1710,9 +1719,9 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveAudioContent(creator3, now.minusDays(5), isActive = true)
|
||||
flushAndClear()
|
||||
|
||||
val page0 = repository.findRecentDebutCreators(now, offset = 0L, limit = 1, includeAdultContents = false)
|
||||
val page1 = repository.findRecentDebutCreators(now, offset = 1L, limit = 1, includeAdultContents = false)
|
||||
val page2 = repository.findRecentDebutCreators(now, offset = 2L, limit = 1, includeAdultContents = false)
|
||||
val page0 = repository.findRecentDebutCreators(now, offset = 0L, limit = 1, includeAdultContents = false, lang = Lang.KO)
|
||||
val page1 = repository.findRecentDebutCreators(now, offset = 1L, limit = 1, includeAdultContents = false, lang = Lang.KO)
|
||||
val page2 = repository.findRecentDebutCreators(now, offset = 2L, limit = 1, includeAdultContents = false, lang = Lang.KO)
|
||||
|
||||
val pagedCreatorIds = (page0 + page1 + page2).map { it.creatorId }
|
||||
assertEquals(setOf(creator1.id, creator2.id, creator3.id), pagedCreatorIds.toSet())
|
||||
@@ -1729,7 +1738,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
saveAudioContent(creator2, now.minusDays(5), isActive = true)
|
||||
flushAndClear()
|
||||
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10)
|
||||
val creators = repository.findRecentDebutCreators(now, limit = 10, lang = Lang.KO)
|
||||
|
||||
assertEquals(2, creators.size)
|
||||
assertEquals(setOf(creator1.id, creator2.id), creators.map { it.creatorId }.toSet())
|
||||
@@ -2111,7 +2120,10 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val inactiveCreator = saveMember("cheer-detail-inactive", MemberRole.CREATOR, isActive = false)
|
||||
flushAndClear()
|
||||
|
||||
val details = repository.findCheerCreatorRecommendationDetails(listOf(activeCreator.id!!, inactiveCreator.id!!, 999L))
|
||||
val details = repository.findCheerCreatorRecommendationDetails(
|
||||
listOf(activeCreator.id!!, inactiveCreator.id!!, 999L),
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val detailById = details.associateBy { it.creatorId }
|
||||
assertEquals(setOf(activeCreator.id), detailById.keys)
|
||||
@@ -2131,7 +2143,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
|
||||
val details = repository.findCheerCreatorRecommendationDetails(
|
||||
listOf(viewerBlockedCreator.id!!, creatorBlockedViewer.id!!, visibleCreator.id!!),
|
||||
memberId = viewer.id
|
||||
memberId = viewer.id,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visibleCreator.id), details.map { it.creatorId })
|
||||
@@ -2150,7 +2163,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
|
||||
val details = repository.findCheerCreatorRecommendationDetails(
|
||||
listOf(viewer.id!!, activeFollowedCreator.id!!, inactiveFollowedCreator.id!!, visibleCreator.id!!),
|
||||
memberId = viewer.id
|
||||
memberId = viewer.id,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(inactiveFollowedCreator.id, visibleCreator.id), details.map { it.creatorId })
|
||||
@@ -2167,7 +2181,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
|
||||
val details = repository.findCheerCreatorRecommendationDetails(
|
||||
listOf(viewer.id!!, activeFollowedCreator.id!!, visibleCreator.id!!),
|
||||
memberId = null
|
||||
memberId = null,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(viewer.id, activeFollowedCreator.id, visibleCreator.id), details.map { it.creatorId })
|
||||
@@ -2178,7 +2193,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
fun shouldReturnEmptyCheerCreatorRecommendationDetailsWhenIdsAreEmpty() {
|
||||
assertEquals(
|
||||
emptyList<HomeCheerCreatorRecommendationRecord>(),
|
||||
repository.findCheerCreatorRecommendationDetails(emptyList())
|
||||
repository.findCheerCreatorRecommendationDetails(emptyList(), lang = Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2216,7 +2231,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val details = repository.findPopularCommunityRecommendationDetails(
|
||||
listOf(eligible.id!!, paid.id!!, fixed.id!!, adult.id!!, inactivePost.id!!, inactiveCreatorPost.id!!, 999L),
|
||||
memberId = member.id,
|
||||
includeAdultCommunities = false
|
||||
includeAdultCommunities = false,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val detailById = details.associateBy { it.communityId }
|
||||
@@ -2244,7 +2260,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val details = repository.findPopularCommunityRecommendationDetails(
|
||||
listOf(free.id!!),
|
||||
memberId = null,
|
||||
includeAdultCommunities = false
|
||||
includeAdultCommunities = false,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(free.id), details.map { it.communityId })
|
||||
@@ -2265,7 +2282,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
|
||||
val details = repository.findPopularCommunityRecommendationDetails(
|
||||
listOf(adult.id!!),
|
||||
includeAdultCommunities = true
|
||||
includeAdultCommunities = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
val detailById = details.associateBy { it.communityId }
|
||||
@@ -2290,7 +2308,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
val details = repository.findPopularCommunityRecommendationDetails(
|
||||
listOf(viewerBlockedPost.id!!, creatorBlockedPost.id!!, visiblePost.id!!),
|
||||
memberId = viewer.id,
|
||||
includeAdultCommunities = false
|
||||
includeAdultCommunities = false,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(visiblePost.id), details.map { it.communityId })
|
||||
@@ -2301,7 +2320,7 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
fun shouldReturnEmptyPopularCommunityRecommendationDetailsWhenIdsAreEmpty() {
|
||||
assertEquals(
|
||||
emptyList<HomePopularCommunityRecommendationRecord>(),
|
||||
repository.findPopularCommunityRecommendationDetails(emptyList(), includeAdultCommunities = false)
|
||||
repository.findPopularCommunityRecommendationDetails(emptyList(), includeAdultCommunities = false, lang = Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2347,7 +2366,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2, recommendations.size)
|
||||
@@ -2377,7 +2397,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(theme.id), recommendations.map { it.genreId })
|
||||
@@ -2417,7 +2438,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(fallbackTheme.id), recommendations.map { it.genreId })
|
||||
@@ -2446,7 +2468,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val creatorIds = recommendations.single().creators.map { it.creatorId }
|
||||
|
||||
@@ -2477,7 +2500,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val creatorIds = recommendations.single().creators.map { it.creatorId }
|
||||
|
||||
@@ -2500,7 +2524,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(theme.id, recommendations.single().genreId)
|
||||
@@ -2551,7 +2576,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(2, recommendations.size)
|
||||
@@ -2589,7 +2615,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(true, recommendations.size >= 5)
|
||||
@@ -2633,7 +2660,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = viewer.id!!,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(true, recommendations.size >= 5)
|
||||
@@ -2664,7 +2692,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(3, recommendations.size)
|
||||
@@ -2695,7 +2724,8 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 1,
|
||||
creatorLimit = 2
|
||||
creatorLimit = 2,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(1, recommendations.size)
|
||||
@@ -2724,13 +2754,15 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val visible = repository.findGenreCreatorRecommendations(
|
||||
memberId = null,
|
||||
includeAdultGenres = true,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(false, hidden.any { it.genreId == adultTheme.id })
|
||||
|
||||
+55
-48
@@ -1,7 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.recommendation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Gender
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.community.translation.application.CreatorCommunityDisplayContent
|
||||
@@ -32,12 +31,10 @@ import java.time.ZoneOffset
|
||||
class HomeRecommendationQueryServiceTest {
|
||||
private val port = FakeHomeRecommendationQueryPort()
|
||||
private val snapshotPort = FakeHomeRecommendationSnapshotPort()
|
||||
private val langContext = LangContext()
|
||||
private val creatorCommunityTranslationService = Mockito.mock(CreatorCommunityTranslationService::class.java)
|
||||
private val service = HomeRecommendationQueryService(
|
||||
port,
|
||||
snapshotPort,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
|
||||
@@ -79,7 +76,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("홈 라이브 추천은 기본 20개를 최신순 조회 포트에 위임한다")
|
||||
fun shouldFindLatestLiveRecommendationsWithDefaultLimit() {
|
||||
val recommendations = service.findLiveRecommendations(memberId = 100L)
|
||||
val recommendations = service.findLiveRecommendations(memberId = 100L, lang = Lang.KO)
|
||||
|
||||
assertEquals(20, port.liveLimit)
|
||||
assertEquals(100L, port.liveMemberId)
|
||||
@@ -95,7 +92,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = 100L,
|
||||
includeAdultLives = true,
|
||||
isViewerCreator = true,
|
||||
effectiveViewerGender = Gender.MALE
|
||||
effectiveViewerGender = Gender.MALE,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(40, port.liveOffset)
|
||||
@@ -131,7 +129,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("최근 활동 크리에이터는 기본 10개를 최신 활동 조회 포트에 위임한다")
|
||||
fun shouldFindRecentlyActiveCreatorsWithDefaultLimit() {
|
||||
val creators = service.findRecentlyActiveCreators(memberId = 100L)
|
||||
val creators = service.findRecentlyActiveCreators(memberId = 100L, lang = Lang.KO)
|
||||
|
||||
assertEquals(10, port.activeCreatorLimit)
|
||||
assertEquals(100L, port.activeCreatorMemberId)
|
||||
@@ -142,7 +140,12 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("최근 활동 크리에이터는 성인 활동 노출 여부를 조회 포트에 위임한다")
|
||||
fun shouldFindRecentlyActiveCreatorsWithAdultVisibilityPolicy() {
|
||||
val creators = service.findRecentlyActiveCreators(limit = 8, memberId = 101L, includeAdultActivities = true)
|
||||
val creators = service.findRecentlyActiveCreators(
|
||||
limit = 8,
|
||||
memberId = 101L,
|
||||
includeAdultActivities = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(8, port.activeCreatorLimit)
|
||||
assertEquals(101L, port.activeCreatorMemberId)
|
||||
@@ -155,7 +158,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
fun shouldFindRecentDebutCreatorsWithDefaultLimitAndNow() {
|
||||
val now = LocalDateTime.of(2026, 5, 31, 10, 0)
|
||||
|
||||
val creators = service.findRecentDebutCreators(now, memberId = 102L)
|
||||
val creators = service.findRecentDebutCreators(now, memberId = 102L, lang = Lang.KO)
|
||||
|
||||
assertEquals(now, port.recentDebutNow)
|
||||
assertEquals(102L, port.recentDebutMemberId)
|
||||
@@ -168,7 +171,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
fun shouldFindFirstAudioContentsWithDefaultLimitAndNow() {
|
||||
val now = LocalDateTime.of(2026, 5, 31, 10, 0)
|
||||
|
||||
val contents = service.findFirstAudioContents(now, memberId = 103L)
|
||||
val contents = service.findFirstAudioContents(now, memberId = 103L, lang = Lang.KO)
|
||||
|
||||
assertEquals(now, port.firstAudioNow)
|
||||
assertEquals(103L, port.firstAudioMemberId)
|
||||
@@ -185,7 +188,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val oldSnapshotAt = LocalDateTime.of(2026, 5, 28, 23, 59, 59)
|
||||
@@ -293,7 +295,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
port.aiCharacterDetails = listOf(
|
||||
@@ -324,7 +325,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
|
||||
@@ -346,7 +346,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -375,7 +374,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
@@ -408,7 +406,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
fallback,
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
@@ -435,7 +432,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
@@ -459,7 +455,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L)
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L, lang = Lang.KO)
|
||||
|
||||
assertEquals(null, fallback.offset)
|
||||
assertEquals(null, fallback.limit)
|
||||
@@ -480,7 +476,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
port.cheerCreatorDetails = listOf(
|
||||
@@ -491,7 +486,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L)
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L, lang = Lang.KO)
|
||||
|
||||
assertEquals(0L, fallback.offset)
|
||||
assertEquals(16, fallback.limit)
|
||||
@@ -511,7 +506,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val staleSnapshotAt = LocalDateTime.of(2026, 7, 8, 14, 59, 59)
|
||||
@@ -528,7 +522,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L)
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L, lang = Lang.KO)
|
||||
|
||||
assertEquals(0L, fallback.offset)
|
||||
assertEquals(16, fallback.limit)
|
||||
@@ -548,7 +542,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
cheerCreatorSnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -557,7 +550,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
emptyList()
|
||||
)
|
||||
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L)
|
||||
val creators = service.findCheerCreatorRecommendations(memberId = 104L, lang = Lang.KO)
|
||||
|
||||
assertEquals(null, fallback.offset)
|
||||
assertEquals(null, fallback.limit)
|
||||
@@ -572,7 +565,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
@@ -631,7 +623,11 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val communities = service.findPopularCommunityRecommendations(memberId = 105L, includeAdultCommunities = true)
|
||||
val communities = service.findPopularCommunityRecommendations(
|
||||
memberId = 105L,
|
||||
includeAdultCommunities = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals((1L..11L).toList(), port.popularCommunityDetailIds)
|
||||
assertEquals(105L, port.popularCommunityMemberId)
|
||||
@@ -652,7 +648,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
@@ -681,7 +676,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
}
|
||||
|
||||
val communities = service.findPopularCommunityRecommendations()
|
||||
val communities = service.findPopularCommunityRecommendations(lang = Lang.KO)
|
||||
|
||||
assertEquals(20, port.popularCommunityDetailIds.size)
|
||||
assertEquals(10, communities.size)
|
||||
@@ -692,7 +687,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
@Test
|
||||
@DisplayName("인기 커뮤니티 추천은 최종 노출 게시물만 일본어 표시 본문으로 일괄 치환하고 원문 폴백을 유지한다")
|
||||
fun shouldTranslateOnlyFinalPopularCommunityRecommendationsInOneJapaneseBatch() {
|
||||
langContext.setLang(Lang.JA)
|
||||
val snapshotAt = LocalDateTime.of(2026, 7, 9, 14, 59, 59)
|
||||
snapshotPort.replaceSnapshots(
|
||||
RecommendedSectionType.POPULAR_COMMUNITY,
|
||||
@@ -718,11 +712,10 @@ class HomeRecommendationQueryServiceTest {
|
||||
port,
|
||||
snapshotPort,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
|
||||
val communities = translatedService.findPopularCommunityRecommendations(limit = 2)
|
||||
val communities = translatedService.findPopularCommunityRecommendations(limit = 2, lang = Lang.JA)
|
||||
|
||||
assertEquals(listOf(1L, 3L), communities.map { it.communityId })
|
||||
assertEquals(listOf("translated-1-ja", "current-original-3"), communities.map { it.content })
|
||||
@@ -741,7 +734,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
popularCommunitySnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
val staleSnapshotAt = LocalDateTime.of(2026, 7, 8, 14, 59, 59)
|
||||
@@ -768,7 +760,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
)
|
||||
)
|
||||
|
||||
val communities = service.findPopularCommunityRecommendations(memberId = 105L)
|
||||
val communities = service.findPopularCommunityRecommendations(memberId = 105L, lang = Lang.KO)
|
||||
|
||||
assertEquals(0L, fallback.offset)
|
||||
assertEquals(20, fallback.limit)
|
||||
@@ -788,7 +780,6 @@ class HomeRecommendationQueryServiceTest {
|
||||
snapshotPort,
|
||||
popularCommunitySnapshotFallbackService = fallback,
|
||||
clock = fixedClock(),
|
||||
langContext = langContext,
|
||||
creatorCommunityTranslationService = creatorCommunityTranslationService
|
||||
)
|
||||
snapshotPort.replaceSnapshots(
|
||||
@@ -797,7 +788,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
emptyList()
|
||||
)
|
||||
|
||||
val communities = service.findPopularCommunityRecommendations(memberId = 105L)
|
||||
val communities = service.findPopularCommunityRecommendations(memberId = 105L, lang = Lang.KO)
|
||||
|
||||
assertEquals(null, fallback.offset)
|
||||
assertEquals(null, fallback.limit)
|
||||
@@ -809,8 +800,11 @@ class HomeRecommendationQueryServiceTest {
|
||||
@DisplayName("최신 스냅샷이 없으면 AI 캐릭터/최근 응원/인기 커뮤니티 추천은 빈 배열을 반환한다")
|
||||
fun shouldReturnEmptyListWhenLatestSnapshotsDoNotExist() {
|
||||
assertEquals(emptyList<HomeAiCharacterRecommendationRecord>(), service.findAiCharacterRecommendations())
|
||||
assertEquals(emptyList<HomeCheerCreatorRecommendationRecord>(), service.findCheerCreatorRecommendations())
|
||||
assertEquals(emptyList<HomePopularCommunityRecommendationRecord>(), service.findPopularCommunityRecommendations())
|
||||
assertEquals(emptyList<HomeCheerCreatorRecommendationRecord>(), service.findCheerCreatorRecommendations(lang = Lang.KO))
|
||||
assertEquals(
|
||||
emptyList<HomePopularCommunityRecommendationRecord>(),
|
||||
service.findPopularCommunityRecommendations(lang = Lang.KO)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -858,7 +852,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
|
||||
val recommendations = service.findGenreCreatorRecommendations(
|
||||
memberId = 100L,
|
||||
includeAdultGenres = true
|
||||
includeAdultGenres = true,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(100L, port.genreCreatorMemberId)
|
||||
@@ -912,7 +907,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = 100L,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L, 3L), recommendations.map { it.genreId })
|
||||
@@ -958,7 +954,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L, 3L), recommendations.map { it.genreId })
|
||||
@@ -1009,7 +1006,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = null,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L, 3L), recommendations.map { it.genreId })
|
||||
@@ -1038,7 +1036,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = 100L,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 5,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L), recommendations.map { it.genreId })
|
||||
@@ -1085,7 +1084,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId = 100L,
|
||||
includeAdultGenres = false,
|
||||
genreLimit = 2,
|
||||
creatorLimit = 8
|
||||
creatorLimit = 8,
|
||||
lang = Lang.KO
|
||||
)
|
||||
|
||||
assertEquals(listOf(1L, 2L), recommendations.map { it.genreId })
|
||||
@@ -1130,6 +1130,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
var genreCreatorCreatorLimit: Int? = null
|
||||
val liveRecommendations = listOf(
|
||||
HomeLiveRecommendationRecord(
|
||||
creatorMemberId = 10L,
|
||||
liveRoomId = 1L,
|
||||
creatorNickname = "creator",
|
||||
creatorProfileImage = "profile.png",
|
||||
@@ -1196,7 +1197,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId: Long?,
|
||||
includeAdultLives: Boolean,
|
||||
isViewerCreator: Boolean,
|
||||
effectiveViewerGender: Gender?
|
||||
effectiveViewerGender: Gender?,
|
||||
lang: Lang
|
||||
): List<HomeLiveRecommendationRecord> {
|
||||
liveOffset = offset
|
||||
liveLimit = limit
|
||||
@@ -1223,7 +1225,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
override fun findRecentlyActiveCreators(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultActivities: Boolean
|
||||
includeAdultActivities: Boolean,
|
||||
lang: Lang
|
||||
): List<RecentlyActiveCreatorRecord> {
|
||||
activeCreatorLimit = limit
|
||||
activeCreatorMemberId = memberId
|
||||
@@ -1236,7 +1239,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultContents: Boolean
|
||||
includeAdultContents: Boolean,
|
||||
lang: Lang
|
||||
): List<RecentDebutCreatorRecord> {
|
||||
recentDebutNow = now
|
||||
recentDebutOffset = offset
|
||||
@@ -1299,7 +1303,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
|
||||
override fun findCheerCreatorRecommendationDetails(
|
||||
creatorIds: List<Long>,
|
||||
memberId: Long?
|
||||
memberId: Long?,
|
||||
lang: Lang
|
||||
): List<HomeCheerCreatorRecommendationRecord> {
|
||||
cheerCreatorDetailIds = creatorIds
|
||||
cheerCreatorMemberId = memberId
|
||||
@@ -1309,7 +1314,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
override fun findPopularCommunityRecommendationDetails(
|
||||
communityIds: List<Long>,
|
||||
memberId: Long?,
|
||||
includeAdultCommunities: Boolean
|
||||
includeAdultCommunities: Boolean,
|
||||
lang: Lang
|
||||
): List<HomePopularCommunityRecommendationRecord> {
|
||||
popularCommunityDetailIds = communityIds
|
||||
popularCommunityMemberId = memberId
|
||||
@@ -1321,7 +1327,8 @@ class HomeRecommendationQueryServiceTest {
|
||||
memberId: Long?,
|
||||
includeAdultGenres: Boolean,
|
||||
genreLimit: Int,
|
||||
creatorLimit: Int
|
||||
creatorLimit: Int,
|
||||
lang: Lang
|
||||
): List<HomeGenreCreatorRecommendationGroup> {
|
||||
genreCreatorMemberId = memberId
|
||||
genreCreatorIncludeAdultGenres = includeAdultGenres
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
package kr.co.vividnext.sodalive.v2.usercreatorchat
|
||||
|
||||
import kr.co.vividnext.sodalive.chat.character.ChatCharacter
|
||||
import kr.co.vividnext.sodalive.chat.room.ChatMessage
|
||||
import kr.co.vividnext.sodalive.chat.room.ChatParticipant
|
||||
import kr.co.vividnext.sodalive.chat.room.ChatRoom
|
||||
import kr.co.vividnext.sodalive.chat.room.ParticipantType
|
||||
import kr.co.vividnext.sodalive.chat.room.repository.ChatRoomRepository
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.following.CreatorFollowing
|
||||
import kr.co.vividnext.sodalive.v2.chat.service.ChatRoomListService
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatMessageRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatParticipantRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatRoomRepository
|
||||
import org.hibernate.SessionFactory
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.EnumSource
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.context.annotation.Import
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import java.time.LocalDateTime
|
||||
import javax.persistence.EntityManager
|
||||
|
||||
@DataJpaTest(properties = ["spring.cache.type=none", "spring.jpa.properties.hibernate.generate_statistics=true"])
|
||||
@Import(QueryDslConfig::class)
|
||||
class UserCreatorChatNameJoinRepositoryTest @Autowired constructor(
|
||||
private val roomRepository: UserCreatorChatRoomRepository,
|
||||
private val messageRepository: UserCreatorChatMessageRepository,
|
||||
private val participantRepository: UserCreatorChatParticipantRepository,
|
||||
private val aiRoomRepository: ChatRoomRepository,
|
||||
private val entityManager: EntityManager,
|
||||
private val jdbcTemplate: JdbcTemplate
|
||||
) {
|
||||
@ParameterizedTest
|
||||
@EnumSource(Lang::class)
|
||||
@DisplayName("DM 목록·히스토리·상대 프로필은 요청 Lang을 조인하고 USER·미등록·비활성 행을 유지한다")
|
||||
fun shouldJoinRequestedNamesWithoutStandaloneNameQueries(lang: Lang) {
|
||||
val viewer = member("viewer", MemberRole.USER)
|
||||
val opponents = listOf(
|
||||
member("creator", MemberRole.CREATOR),
|
||||
member("inactive", MemberRole.CREATOR, false),
|
||||
member("missing", MemberRole.CREATOR, null),
|
||||
member("user", MemberRole.USER)
|
||||
)
|
||||
val rooms = opponents.map { dmRoom(viewer, it) }
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
val statistics = entityManager.entityManagerFactory.unwrap(SessionFactory::class.java).statistics
|
||||
statistics.clear()
|
||||
|
||||
val listed = roomRepository.findDmChatListRooms(
|
||||
viewer.id!!,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
lang,
|
||||
PageRequest.of(0, 20)
|
||||
)
|
||||
|
||||
val expectedCreator = if (lang == Lang.KO) "creator" else "${lang.name}-creator"
|
||||
assertEquals(setOf(expectedCreator, "inactive", "missing", "user"), listed.map { it.targetName }.toSet())
|
||||
assertEquals(4, listed.size)
|
||||
assertEquals(1L, statistics.queryExecutionCount)
|
||||
assertEquals(0L, statistics.entityLoadCount)
|
||||
rooms.zip(opponents).forEach { (room, opponent) ->
|
||||
statistics.clear()
|
||||
val expectedName = if (opponent.id == opponents.first().id) expectedCreator else opponent.nickname
|
||||
val messages = messageRepository.findMessageHistory(room, null, lang, PageRequest.of(0, 20))
|
||||
assertEquals(listOf(expectedName, "viewer"), messages.map { it.senderNickname })
|
||||
assertEquals(listOf("opponent body", "viewer body"), messages.map { it.textMessage })
|
||||
assertEquals(1L, statistics.queryExecutionCount)
|
||||
assertEquals(0L, statistics.entityLoadCount)
|
||||
|
||||
statistics.clear()
|
||||
val previous = messageRepository.findMessageHistory(room, messages.first().messageId, lang, PageRequest.of(0, 20))
|
||||
assertEquals(listOf(messages.last().messageId), previous.map { it.messageId })
|
||||
assertEquals(1L, statistics.queryExecutionCount)
|
||||
|
||||
statistics.clear()
|
||||
val profile = participantRepository.findActiveOpponentProfile(room.id!!, viewer.id!!, lang)
|
||||
assertEquals(expectedName, profile!!.nickname)
|
||||
assertEquals(1L, statistics.queryExecutionCount)
|
||||
assertEquals(0L, statistics.entityLoadCount)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("통합 채팅 목록은 DM만 EN 별칭을 조인하고 AI 캐릭터 이름·팔로우 필터·커서를 유지한다")
|
||||
fun shouldKeepAiCharacterNameAndFollowingCursorWhenJoiningDmNames() {
|
||||
val viewer = member("viewer", MemberRole.USER)
|
||||
val creator = member("creator", MemberRole.CREATOR)
|
||||
val room = dmRoom(viewer, creator)
|
||||
val character = ChatCharacter("join-character", "AI character", "description", systemPrompt = "prompt").apply {
|
||||
creatorMember = creator
|
||||
}
|
||||
entityManager.persist(character)
|
||||
val aiRoom = ChatRoom("join-ai-session", "AI room")
|
||||
entityManager.persist(aiRoom)
|
||||
entityManager.persist(ChatParticipant(aiRoom, ParticipantType.USER, member = viewer))
|
||||
val characterParticipant = ChatParticipant(aiRoom, ParticipantType.CHARACTER, character = character)
|
||||
entityManager.persist(characterParticipant)
|
||||
entityManager.persist(ChatMessage("AI body", aiRoom, characterParticipant))
|
||||
entityManager.persist(
|
||||
CreatorFollowing().apply {
|
||||
member = viewer
|
||||
this.creator = creator
|
||||
}
|
||||
)
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
val statistics = entityManager.entityManagerFactory.unwrap(SessionFactory::class.java).statistics
|
||||
statistics.clear()
|
||||
val service = ChatRoomListService(aiRoomRepository, roomRepository, "https://cdn.test")
|
||||
|
||||
val first = service.getRooms(viewer, Lang.EN, limit = 1, followedCreatorsOnly = true)
|
||||
val second = service.getRooms(viewer, Lang.EN, cursor = first.nextCursor, limit = 1, followedCreatorsOnly = true)
|
||||
|
||||
assertEquals(true, first.hasMore)
|
||||
assertEquals(false, second.hasMore)
|
||||
assertEquals(listOf("AI character", "EN-creator"), (first.rooms + second.rooms).map { it.targetName })
|
||||
assertEquals(listOf(aiRoom.id, room.id), (first.rooms + second.rooms).map { it.roomId })
|
||||
assertEquals(4L, statistics.queryExecutionCount, statistics.queries.joinToString("\n"))
|
||||
assertEquals(0L, statistics.entityLoadCount)
|
||||
}
|
||||
|
||||
private fun member(nickname: String, role: MemberRole, activeAlias: Boolean? = true): Member {
|
||||
val member = Member(password = "pw", nickname = nickname, role = role)
|
||||
entityManager.persist(member)
|
||||
if (activeAlias != null) {
|
||||
listOf(Lang.JA, Lang.EN).forEach { lang ->
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at) " +
|
||||
"VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
|
||||
member.id!!,
|
||||
lang.name,
|
||||
"${lang.name}-$nickname",
|
||||
activeAlias
|
||||
)
|
||||
}
|
||||
}
|
||||
return member
|
||||
}
|
||||
|
||||
private fun dmRoom(viewer: Member, opponent: Member): UserCreatorChatRoom {
|
||||
val room = roomRepository.save(UserCreatorChatRoom())
|
||||
val mine = participantRepository.save(UserCreatorChatParticipant(room, viewer))
|
||||
val theirs = participantRepository.save(UserCreatorChatParticipant(room, opponent))
|
||||
val now = LocalDateTime.now()
|
||||
messageRepository.save(UserCreatorChatMessage(room, mine, UserCreatorChatMessageType.TEXT, "viewer body"))
|
||||
.createdAt = now.minusMinutes(2)
|
||||
messageRepository.save(UserCreatorChatMessage(room, theirs, UserCreatorChatMessageType.TEXT, "opponent body"))
|
||||
.createdAt = now.minusMinutes(1)
|
||||
messageRepository.save(
|
||||
UserCreatorChatMessage(room, theirs, UserCreatorChatMessageType.TEXT, "inactive body", isActive = false)
|
||||
)
|
||||
return room
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.usercreatorchat
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberKind
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
@@ -112,7 +113,7 @@ class UserCreatorChatServiceIntegrationTest @Autowired constructor(
|
||||
entityManager.clear()
|
||||
|
||||
val exception = assertThrows(SodaException::class.java) {
|
||||
service.sendTextMessageByWebSocket(user.id!!, room.id!!, "hello")
|
||||
service.sendTextMessageByWebSocket(user.id!!, room.id!!, "hello", Lang.KO)
|
||||
}
|
||||
|
||||
assertEquals("message.error.recipient_not_found", exception.messageKey)
|
||||
|
||||
+40
-13
@@ -6,11 +6,16 @@ import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||
import kr.co.vividnext.sodalive.fcm.FcmDeepLinkValue
|
||||
import kr.co.vividnext.sodalive.fcm.FcmEvent
|
||||
import kr.co.vividnext.sodalive.fcm.FcmEventType
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.dto.UserCreatorChatMessageItemDto
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.dto.UserCreatorChatMessageRow
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.dto.UserCreatorChatOpponentProfile
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatMessageRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatParticipantRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatRoomRepository
|
||||
@@ -70,6 +75,8 @@ class UserCreatorChatServiceTest {
|
||||
applicationEventPublisher = eventPublisher,
|
||||
objectMapper = ObjectMapper(),
|
||||
s3Uploader = s3Uploader,
|
||||
localizedNameService = Mockito.mock(CreatorLocalizedNameService::class.java),
|
||||
langContext = LangContext(),
|
||||
bucket = "test-bucket",
|
||||
cloudFrontHost = "https://cdn.test"
|
||||
)
|
||||
@@ -140,13 +147,15 @@ class UserCreatorChatServiceTest {
|
||||
}
|
||||
val room = room(10L)
|
||||
val userParticipant = participant(100L, room, user)
|
||||
val creatorParticipant = participant(101L, room, creator)
|
||||
Mockito.`when`(roomRepository.findByIdAndIsActiveTrue(10L)).thenReturn(room)
|
||||
Mockito.`when`(participantRepository.findActiveByRoomIdAndMemberId(10L, 1L)).thenReturn(userParticipant)
|
||||
Mockito.`when`(participantRepository.findActiveOpponent(10L, 1L)).thenReturn(creatorParticipant)
|
||||
Mockito.`when`(participantRepository.findActiveOpponentProfile(10L, 1L, Lang.KO))
|
||||
.thenReturn(UserCreatorChatOpponentProfile(creator.nickname, creator.profileImage))
|
||||
Mockito.`when`(
|
||||
messageRepository.findByChatRoomAndIsActiveTrueOrderByIdDesc(
|
||||
messageRepository.findMessageHistory(
|
||||
room,
|
||||
null,
|
||||
Lang.KO,
|
||||
PageRequest.of(0, 20)
|
||||
)
|
||||
).thenReturn(emptyList())
|
||||
@@ -159,7 +168,7 @@ class UserCreatorChatServiceTest {
|
||||
assertEquals(emptyList<UserCreatorChatMessageItemDto>(), response.messages)
|
||||
assertFalse(response.hasMore)
|
||||
assertEquals(null, response.nextCursor)
|
||||
Mockito.verify(participantRepository).findActiveOpponent(10L, 1L)
|
||||
Mockito.verify(participantRepository).findActiveOpponentProfile(10L, 1L, Lang.KO)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -169,13 +178,15 @@ class UserCreatorChatServiceTest {
|
||||
val creator = member(2L, "creator")
|
||||
val room = room(10L)
|
||||
val userParticipant = participant(100L, room, user)
|
||||
val creatorParticipant = participant(101L, room, creator)
|
||||
Mockito.`when`(roomRepository.findByIdAndIsActiveTrue(10L)).thenReturn(room)
|
||||
Mockito.`when`(participantRepository.findActiveByRoomIdAndMemberId(10L, 1L)).thenReturn(userParticipant)
|
||||
Mockito.`when`(participantRepository.findActiveOpponent(10L, 1L)).thenReturn(creatorParticipant)
|
||||
Mockito.`when`(participantRepository.findActiveOpponentProfile(10L, 1L, Lang.KO))
|
||||
.thenReturn(UserCreatorChatOpponentProfile(creator.nickname, creator.profileImage))
|
||||
Mockito.`when`(
|
||||
messageRepository.findByChatRoomAndIsActiveTrueOrderByIdDesc(
|
||||
messageRepository.findMessageHistory(
|
||||
room,
|
||||
null,
|
||||
Lang.KO,
|
||||
PageRequest.of(0, 20)
|
||||
)
|
||||
).thenReturn(emptyList())
|
||||
@@ -202,7 +213,7 @@ class UserCreatorChatServiceTest {
|
||||
(invocation.arguments[0] as UserCreatorChatMessage).apply { id = 203L }
|
||||
}
|
||||
|
||||
val response = service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello")
|
||||
val response = service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello", lang = Lang.KO)
|
||||
|
||||
assertEquals(203L, response.messageId)
|
||||
assertEquals("hello", response.textMessage)
|
||||
@@ -230,7 +241,7 @@ class UserCreatorChatServiceTest {
|
||||
(invocation.arguments[0] as UserCreatorChatMessage).apply { id = 204L }
|
||||
}
|
||||
|
||||
service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello")
|
||||
service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello", lang = Lang.KO)
|
||||
|
||||
val eventCaptor = ArgumentCaptor.forClass(FcmEvent::class.java)
|
||||
Mockito.verify(eventPublisher).publishEvent(eventCaptor.capture())
|
||||
@@ -263,7 +274,7 @@ class UserCreatorChatServiceTest {
|
||||
(invocation.arguments[0] as UserCreatorChatMessage).apply { id = 207L }
|
||||
}
|
||||
|
||||
val response = service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello")
|
||||
val response = service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello", lang = Lang.KO)
|
||||
|
||||
assertEquals(207L, response.messageId)
|
||||
val eventCaptor = ArgumentCaptor.forClass(FcmEvent::class.java)
|
||||
@@ -421,12 +432,13 @@ class UserCreatorChatServiceTest {
|
||||
Mockito.`when`(roomRepository.findByIdAndIsActiveTrue(10L)).thenReturn(room)
|
||||
Mockito.`when`(participantRepository.findActiveByRoomIdAndMemberId(10L, 1L)).thenReturn(userParticipant)
|
||||
Mockito.`when`(
|
||||
messageRepository.findByChatRoomAndIdLessThanAndIsActiveTrueOrderByIdDesc(
|
||||
messageRepository.findMessageHistory(
|
||||
room,
|
||||
300L,
|
||||
Lang.KO,
|
||||
PageRequest.of(0, 20)
|
||||
)
|
||||
).thenReturn(listOf(newerMessage, olderMessage))
|
||||
).thenReturn(listOf(messageRow(newerMessage), messageRow(olderMessage)))
|
||||
Mockito.`when`(messageRepository.existsByChatRoomAndIsActiveTrueAndIdLessThan(room, 298L)).thenReturn(true)
|
||||
|
||||
val response = service.getMessages(user, roomId = 10L, cursor = 300L)
|
||||
@@ -435,15 +447,30 @@ class UserCreatorChatServiceTest {
|
||||
assertEquals(listOf("older", "newer"), response.messages.map { it.textMessage })
|
||||
assertTrue(response.hasMore)
|
||||
assertEquals(298L, response.nextCursor)
|
||||
Mockito.verify(messageRepository).findByChatRoomAndIdLessThanAndIsActiveTrueOrderByIdDesc(
|
||||
Mockito.verify(messageRepository).findMessageHistory(
|
||||
room,
|
||||
300L,
|
||||
Lang.KO,
|
||||
PageRequest.of(0, 20)
|
||||
)
|
||||
}
|
||||
|
||||
private fun member(id: Long, nickname: String) = Member(password = "pw", nickname = nickname).apply { this.id = id }
|
||||
|
||||
private fun messageRow(message: UserCreatorChatMessage): UserCreatorChatMessageRow {
|
||||
val sender = message.participant.member
|
||||
return UserCreatorChatMessageRow(
|
||||
message.id!!,
|
||||
message.messageType,
|
||||
message.createdAt,
|
||||
message.textMessage,
|
||||
message.voiceMessage,
|
||||
sender.id!!,
|
||||
sender.nickname,
|
||||
sender.profileImage
|
||||
)
|
||||
}
|
||||
|
||||
private fun anyMessageItem(): UserCreatorChatMessageItemDto {
|
||||
return Mockito.any(UserCreatorChatMessageItemDto::class.java) ?: UserCreatorChatMessageItemDto(
|
||||
messageId = 0L,
|
||||
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
|
||||
|
||||
import com.amazonaws.services.s3.model.ObjectMetadata
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||
import kr.co.vividnext.sodalive.fcm.FcmService
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.jwt.TokenProvider
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.token.MemberTokenRepository
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatMessage
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.UserCreatorChatMessageType
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatMessageRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatParticipantRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.repository.UserCreatorChatRoomRepository
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.service.UserCreatorChatService
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertAll
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.CsvSource
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.mock.mockito.MockBean
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate
|
||||
import org.springframework.boot.test.web.server.LocalServerPort
|
||||
import org.springframework.http.HttpEntity
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpMethod
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.server.ServletServerHttpRequest
|
||||
import org.springframework.http.server.ServletServerHttpResponse
|
||||
import org.springframework.jdbc.core.JdbcTemplate
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.mock.web.MockMultipartFile
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.transaction.support.TransactionTemplate
|
||||
import org.springframework.web.context.request.RequestContextHolder
|
||||
import org.springframework.web.context.request.ServletRequestAttributes
|
||||
import org.springframework.web.socket.TextMessage
|
||||
import org.springframework.web.socket.WebSocketHttpHeaders
|
||||
import org.springframework.web.socket.WebSocketSession
|
||||
import org.springframework.web.socket.client.standard.StandardWebSocketClient
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.net.URI
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@SpringBootTest(
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = [
|
||||
"spring.cache.type=none",
|
||||
"jwt.secret=MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWYwMTIzNDU2Nzg5YWJjZGVmMDEyMzQ1Njc4OWFiY2RlZg=="
|
||||
]
|
||||
)
|
||||
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
|
||||
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
|
||||
class UserCreatorChatLocalizedNameIntegrationTest @Autowired constructor(
|
||||
private val tokenProvider: TokenProvider,
|
||||
private val tokenRepository: MemberTokenRepository,
|
||||
private val authInterceptor: UserCreatorChatWebSocketAuthInterceptor,
|
||||
private val handler: UserCreatorChatWebSocketHandler,
|
||||
private val service: UserCreatorChatService,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val roomRepository: UserCreatorChatRoomRepository,
|
||||
private val participantRepository: UserCreatorChatParticipantRepository,
|
||||
private val messageRepository: UserCreatorChatMessageRepository,
|
||||
private val objectMapper: ObjectMapper,
|
||||
private val jdbcTemplate: JdbcTemplate,
|
||||
private val transactionTemplate: TransactionTemplate,
|
||||
private val restTemplate: TestRestTemplate,
|
||||
private val langContext: LangContext
|
||||
) {
|
||||
@LocalServerPort
|
||||
private var port: Int = 0
|
||||
|
||||
@MockBean
|
||||
private lateinit var fcmService: FcmService
|
||||
|
||||
@MockBean
|
||||
private lateinit var s3Uploader: S3Uploader
|
||||
|
||||
private lateinit var creator: Member
|
||||
private lateinit var recipient: Member
|
||||
private lateinit var creatorToken: String
|
||||
private lateinit var recipientToken: String
|
||||
private var roomId: Long = 0
|
||||
private val connections = mutableListOf<ClientConnection>()
|
||||
|
||||
@BeforeEach
|
||||
fun createCommittedFixture() {
|
||||
transactionTemplate.executeWithoutResult {
|
||||
val suffix = UUID.randomUUID().toString()
|
||||
creator = memberRepository.saveAndFlush(
|
||||
Member(
|
||||
email = "creator-$suffix@localized-ws.test",
|
||||
password = "pw",
|
||||
nickname = "original-creator",
|
||||
role = MemberRole.CREATOR
|
||||
)
|
||||
)
|
||||
recipient = memberRepository.saveAndFlush(
|
||||
Member(email = "recipient-$suffix@localized-ws.test", password = "pw", nickname = "original-user")
|
||||
)
|
||||
jdbcTemplate.update(
|
||||
"INSERT INTO creator_localized_name (member_id, lang, display_name, is_active, created_at, updated_at) " +
|
||||
"VALUES (?, 'JA', '日本のクリエイター', true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)",
|
||||
creator.id!!
|
||||
)
|
||||
roomId = service.createOrGetRoom(creator, recipient.id!!).roomId
|
||||
}
|
||||
creatorToken = token(creator)
|
||||
recipientToken = token(recipient)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun closeConnectionsAndRemoveTokens() {
|
||||
connections.forEach { it.session.close() }
|
||||
tokenRepository.deleteById(creator.id!!)
|
||||
tokenRepository.deleteById(recipient.id!!)
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource("ja-JP, JA", "ko-KR, KO", "en-US, EN", "fr-FR, KO")
|
||||
@DisplayName("실제 JWT handshake는 Accept-Language를 Lang 세션 속성으로 저장한다")
|
||||
fun shouldStoreExplicitLanguageOnAuthenticatedHandshake(header: String, expected: Lang) {
|
||||
val request = MockHttpServletRequest().apply {
|
||||
addHeader(HttpHeaders.AUTHORIZATION, "Bearer $recipientToken")
|
||||
addHeader(HttpHeaders.ACCEPT_LANGUAGE, header)
|
||||
}
|
||||
val attributes = mutableMapOf<String, Any>()
|
||||
|
||||
val accepted = authInterceptor.beforeHandshake(
|
||||
ServletServerHttpRequest(request),
|
||||
ServletServerHttpResponse(MockHttpServletResponse()),
|
||||
handler,
|
||||
attributes
|
||||
)
|
||||
|
||||
assertTrue(accepted)
|
||||
assertEquals(recipient.id, attributes[UserCreatorChatWebSocketAuthInterceptor.MEMBER_ID_ATTRIBUTE])
|
||||
assertEquals(expected, attributes["lang"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Accept-Language가 없는 실제 인증 handshake는 KO 세션으로 연결한다")
|
||||
fun shouldDefaultHandshakeLanguageToKoreanWhenHeaderIsMissing() {
|
||||
val request = MockHttpServletRequest().apply { addHeader(HttpHeaders.AUTHORIZATION, "Bearer $recipientToken") }
|
||||
val attributes = mutableMapOf<String, Any>()
|
||||
|
||||
val accepted = authInterceptor.beforeHandshake(
|
||||
ServletServerHttpRequest(request),
|
||||
ServletServerHttpResponse(MockHttpServletResponse()),
|
||||
handler,
|
||||
attributes
|
||||
)
|
||||
|
||||
assertTrue(accepted)
|
||||
assertEquals(Lang.KO, attributes["lang"])
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("localhost WS와 Redis를 거친 같은 회원의 KO JA 세션은 이름만 다르고 원본 본문과 ID를 공유한다")
|
||||
fun shouldDeliverDifferentNamesToSimultaneousSessionsOfTheSameRecipient() {
|
||||
val korean = connect(recipientToken, "ko-KR")
|
||||
val japanese = connect(recipientToken, "ja-JP")
|
||||
val sender = connect(creatorToken, "ja-JP")
|
||||
join(korean)
|
||||
join(japanese)
|
||||
join(sender)
|
||||
sendText(sender, "original-creator 본문", "send-multilang")
|
||||
|
||||
val koreanMessage = receive(korean, "MESSAGE")["payload"]
|
||||
val japaneseMessage = receive(japanese, "MESSAGE")["payload"]
|
||||
val ack = receive(sender, "SEND_ACK")
|
||||
|
||||
assertAll(
|
||||
{ assertEquals("original-creator", koreanMessage["senderNickname"].asText()) },
|
||||
{ assertEquals("日本のクリエイター", japaneseMessage["senderNickname"].asText()) },
|
||||
{ assertEquals("original-creator 본문", koreanMessage["textMessage"].asText()) },
|
||||
{ assertEquals("original-creator 본문", japaneseMessage["textMessage"].asText()) },
|
||||
{ assertEquals(koreanMessage["messageId"], japaneseMessage["messageId"]) },
|
||||
{ assertEquals(creator.id!!, japaneseMessage["senderId"].asLong()) },
|
||||
{ assertEquals(false, japaneseMessage["mine"].asBoolean()) },
|
||||
{ assertEquals("send-multilang", ack["requestId"].asText()) },
|
||||
{ assertEquals("original-creator", memberRepository.findById(creator.id!!).orElseThrow().nickname) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("JA 발신자 SEND_ACK는 KO 수신자 전달과 독립적으로 현지화하고 mine과 requestId를 유지한다")
|
||||
fun shouldRenderSenderAckInSenderSessionLanguageIndependentlyOfRecipient() {
|
||||
val receiver = connect(recipientToken, "ko-KR")
|
||||
val sender = connect(creatorToken, "ja-JP")
|
||||
join(receiver)
|
||||
join(sender)
|
||||
sendText(sender, "ACK 본문", "sender-ja")
|
||||
|
||||
val received = receive(receiver, "MESSAGE")["payload"]
|
||||
val ack = receive(sender, "SEND_ACK")
|
||||
|
||||
assertAll(
|
||||
{ assertEquals("日本のクリエイター", ack["payload"]["senderNickname"].asText()) },
|
||||
{ assertEquals("original-creator", received["senderNickname"].asText()) },
|
||||
{ assertEquals(true, ack["payload"]["mine"].asBoolean()) },
|
||||
{ assertEquals(false, received["mine"].asBoolean()) },
|
||||
{ assertEquals(received["messageId"], ack["payload"]["messageId"]) },
|
||||
{ assertEquals("sender-ja", ack["requestId"].asText()) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("HTTP open과 메시지 페이지는 현재 요청 언어를 사용하고 이전 JA 응답을 후속 KO 조회가 바꾸지 않는다")
|
||||
fun shouldRenderHttpRoomAndMessageNamesAtEachRequestBoundary() {
|
||||
transactionTemplate.executeWithoutResult {
|
||||
val room = roomRepository.findById(roomId).orElseThrow()
|
||||
val participant = participantRepository.findActiveByRoomIdAndMemberId(roomId, creator.id!!)!!
|
||||
messageRepository.saveAndFlush(
|
||||
UserCreatorChatMessage(
|
||||
chatRoom = room,
|
||||
participant = participant,
|
||||
messageType = UserCreatorChatMessageType.TEXT,
|
||||
textMessage = "original-creator text"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val japanese = getRoomResource("open", "ja-JP")
|
||||
val korean = getRoomResource("open", "ko-KR")
|
||||
val messages = getRoomResource("messages", "ja-JP")
|
||||
|
||||
assertAll(
|
||||
{ assertEquals("日本のクリエイター", japanese["opponentNickname"].asText()) },
|
||||
{ assertEquals("日本のクリエイター", japanese["messages"][0]["senderNickname"].asText()) },
|
||||
{ assertEquals("original-creator", korean["opponentNickname"].asText()) },
|
||||
{ assertEquals("original-creator", korean["messages"][0]["senderNickname"].asText()) },
|
||||
{ assertEquals("日本のクリエイター", messages["messages"][0]["senderNickname"].asText()) },
|
||||
{ assertEquals("original-creator text", japanese["messages"][0]["textMessage"].asText()) }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("음성 REST 응답의 JA 이름과 KO WebSocket 전달은 같은 저장 메시지를 독립 렌더링한다")
|
||||
fun shouldLocalizeVoiceHttpResponseWithoutLocalizingNeutralPublishedPayload() {
|
||||
val receiver = connect(recipientToken, "ko-KR")
|
||||
join(receiver)
|
||||
Mockito.`when`(
|
||||
s3Uploader.upload(
|
||||
Mockito.any(InputStream::class.java) ?: ByteArrayInputStream(byteArrayOf()),
|
||||
Mockito.anyString(),
|
||||
Mockito.anyString(),
|
||||
Mockito.any(ObjectMetadata::class.java)
|
||||
)
|
||||
).thenReturn("voice/localized.aac")
|
||||
RequestContextHolder.setRequestAttributes(ServletRequestAttributes(MockHttpServletRequest()))
|
||||
try {
|
||||
langContext.setLang(Lang.JA)
|
||||
val response = service.sendVoiceMessage(
|
||||
creator,
|
||||
roomId,
|
||||
MockMultipartFile("voiceMessageFile", "voice.aac", "audio/aac", byteArrayOf(1, 2)),
|
||||
"{}"
|
||||
)
|
||||
val delivered = receive(receiver, "MESSAGE")["payload"]
|
||||
|
||||
assertEquals("日本のクリエイター", response.message.senderNickname)
|
||||
assertEquals("original-creator", delivered["senderNickname"].asText())
|
||||
assertEquals(response.message.messageId, delivered["messageId"].asLong())
|
||||
assertEquals(response.message.voiceMessageUrl, delivered["voiceMessageUrl"].asText())
|
||||
assertTrue(response.deliveredRealtime)
|
||||
assertEquals(false, response.pushSent)
|
||||
} finally {
|
||||
RequestContextHolder.resetRequestAttributes()
|
||||
}
|
||||
}
|
||||
|
||||
private fun token(member: Member): String {
|
||||
val principal = MemberAdapter(member)
|
||||
return tokenProvider.createToken(
|
||||
UsernamePasswordAuthenticationToken(principal, "pw", principal.authorities),
|
||||
member.id!!
|
||||
)
|
||||
}
|
||||
|
||||
private fun connect(token: String, language: String): ClientConnection {
|
||||
val messages = LinkedBlockingQueue<JsonNode>()
|
||||
val clientHandler = object : TextWebSocketHandler() {
|
||||
override fun handleTextMessage(session: WebSocketSession, message: TextMessage) {
|
||||
messages.add(objectMapper.readTree(message.payload))
|
||||
}
|
||||
}
|
||||
val headers = WebSocketHttpHeaders().apply {
|
||||
setBearerAuth(token)
|
||||
set(HttpHeaders.ACCEPT_LANGUAGE, language)
|
||||
}
|
||||
val session = StandardWebSocketClient().doHandshake(
|
||||
clientHandler,
|
||||
headers,
|
||||
URI("ws://localhost:$port${UserCreatorChatWebSocketConfig.ENDPOINT}")
|
||||
).get(5, TimeUnit.SECONDS)
|
||||
return ClientConnection(session, messages).also { connections.add(it) }
|
||||
}
|
||||
|
||||
private fun join(connection: ClientConnection) {
|
||||
connection.session.sendMessage(TextMessage("""{"type":"JOIN_ROOM","roomId":$roomId,"payload":{}}"""))
|
||||
receive(connection, "JOINED")
|
||||
}
|
||||
|
||||
private fun sendText(connection: ClientConnection, text: String, requestId: String) {
|
||||
connection.session.sendMessage(
|
||||
TextMessage(
|
||||
objectMapper.writeValueAsString(
|
||||
mapOf(
|
||||
"type" to "SEND_TEXT",
|
||||
"requestId" to requestId,
|
||||
"roomId" to roomId,
|
||||
"payload" to mapOf("textMessage" to text)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun receive(connection: ClientConnection, expectedType: String): JsonNode {
|
||||
val envelope = connection.messages.poll(5, TimeUnit.SECONDS)
|
||||
assertNotNull(envelope, "Expected $expectedType from localhost WebSocket")
|
||||
assertEquals(expectedType, envelope!!["type"].asText(), envelope.toString())
|
||||
return envelope
|
||||
}
|
||||
|
||||
private fun getRoomResource(resource: String, language: String): JsonNode {
|
||||
val headers = HttpHeaders().apply {
|
||||
setBearerAuth(recipientToken)
|
||||
set(HttpHeaders.ACCEPT_LANGUAGE, language)
|
||||
}
|
||||
val response = restTemplate.exchange(
|
||||
"http://localhost:$port/api/v2/user-creator-chat/rooms/$roomId/$resource",
|
||||
HttpMethod.GET,
|
||||
HttpEntity<Void>(headers),
|
||||
String::class.java
|
||||
)
|
||||
assertEquals(HttpStatus.OK, response.statusCode, response.body)
|
||||
val body = objectMapper.readTree(response.body)
|
||||
assertTrue(body["success"].asBoolean(), response.body)
|
||||
return body["data"]
|
||||
}
|
||||
|
||||
private data class ClientConnection(val session: WebSocketSession, val messages: LinkedBlockingQueue<JsonNode>)
|
||||
}
|
||||
+5
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisTestConfiguration
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
@@ -14,6 +15,7 @@ import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.mock.mockito.MockBean
|
||||
import org.springframework.data.redis.core.StringRedisTemplate
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
import org.springframework.test.context.TestPropertySource
|
||||
@@ -35,6 +37,9 @@ import java.util.concurrent.TimeUnit
|
||||
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
|
||||
@TestPropertySource(properties = ["user-creator-chat.websocket.server-id=redis-test-server"])
|
||||
class UserCreatorChatRedisIntegrationTest {
|
||||
@MockBean
|
||||
private lateinit var localizedNameService: CreatorLocalizedNameService
|
||||
|
||||
@Autowired
|
||||
private lateinit var stringRedisTemplate: StringRedisTemplate
|
||||
|
||||
|
||||
+3
-1
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import kr.co.vividnext.sodalive.v2.creatorname.application.CreatorLocalizedNameService
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -25,7 +26,8 @@ class UserCreatorChatRoomMessageBrokerTest {
|
||||
stringRedisTemplate = stringRedisTemplate,
|
||||
sessionRegistry = registry,
|
||||
objectMapper = objectMapper,
|
||||
listenerContainer = listenerContainer
|
||||
listenerContainer = listenerContainer,
|
||||
localizedNameService = Mockito.mock(CreatorLocalizedNameService::class.java)
|
||||
)
|
||||
|
||||
@Test
|
||||
|
||||
+4
-2
@@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.v2.usercreatorchat.websocket
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.dto.UserCreatorChatMessageItemDto
|
||||
import kr.co.vividnext.sodalive.v2.usercreatorchat.service.UserCreatorChatService
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
@@ -66,7 +67,7 @@ class UserCreatorChatWebSocketHandlerTest {
|
||||
@DisplayName("SEND_TEXT는 메시지 저장 후 sender에게 SEND_ACK를 응답한다")
|
||||
fun shouldSendAckToSenderWhenTextMessageIsSaved() {
|
||||
val session = session("session-1", memberId = 1L)
|
||||
Mockito.`when`(service.sendTextMessageByWebSocket(memberId = 1L, roomId = 10L, textMessage = "hello"))
|
||||
Mockito.`when`(service.sendTextMessageByWebSocket(1L, 10L, "hello", Lang.KO))
|
||||
.thenReturn(messageItem())
|
||||
handler.handleMessage(session, textMessage("JOIN_ROOM", "join-1", 10L, "{}"))
|
||||
Mockito.clearInvocations(session)
|
||||
@@ -103,7 +104,8 @@ class UserCreatorChatWebSocketHandlerTest {
|
||||
Mockito.verify(service, Mockito.never()).sendTextMessageByWebSocket(
|
||||
Mockito.anyLong(),
|
||||
Mockito.anyLong(),
|
||||
Mockito.anyString()
|
||||
Mockito.anyString(),
|
||||
Mockito.eq(Lang.KO) ?: Lang.KO
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user