feat(recommendation): 추천 배너 언어 필터를 적용한다
This commit is contained in:
+16
@@ -207,6 +207,22 @@ class MemberContentPreferenceIntegrationTest @Autowired constructor(
|
||||
assertEquals("KR", service.resolveCountryCode(member))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("비로그인 사용자의 국가 코드는 접속 국가 헤더를 정규화하고 없으면 KR로 계산된다")
|
||||
fun shouldResolveCountryCodeForAnonymousUser() {
|
||||
countryContext.setCountryCode("JP")
|
||||
assertEquals("JP", service.resolveCountryCode(null))
|
||||
|
||||
countryContext.setCountryCode(" jp ")
|
||||
assertEquals("JP", service.resolveCountryCode(null))
|
||||
|
||||
countryContext.setCountryCode(null)
|
||||
assertEquals("KR", service.resolveCountryCode(null))
|
||||
|
||||
countryContext.setCountryCode(" ")
|
||||
assertEquals("KR", service.resolveCountryCode(null))
|
||||
}
|
||||
|
||||
private fun saveMember(seed: String): Member {
|
||||
return memberRepository.saveAndFlush(
|
||||
Member(
|
||||
|
||||
+26
-1
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryService
|
||||
@@ -56,6 +57,27 @@ class HomeRecommendationFacadeTest {
|
||||
assertTrue(queryPort.bannerIncludeAdultBanners)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 추천은 JP 국가 판정이면 JA 배너 조회를 요청한다")
|
||||
fun shouldPassJaToHomeBannerQueryForJapan() {
|
||||
val member = Member(password = "password", nickname = "jp-member").apply { id = 11L }
|
||||
Mockito.doReturn("JP").`when`(preferenceService).resolveCountryCode(member)
|
||||
|
||||
facade.getHomeRecommendations(member)
|
||||
|
||||
assertTrue(queryPort.bannerLang == Lang.JA)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 추천은 JP 이외 국가 판정이면 KO 배너 조회를 요청한다")
|
||||
fun shouldPassKoToHomeBannerQueryForNonJapan() {
|
||||
Mockito.doReturn("KR").`when`(preferenceService).resolveCountryCode(null)
|
||||
|
||||
facade.getHomeRecommendations(null)
|
||||
|
||||
assertTrue(queryPort.bannerLang == Lang.KO)
|
||||
}
|
||||
|
||||
private fun firstAudio(price: Int, isPointAvailable: Boolean): HomeFirstAudioContentRecord {
|
||||
return HomeFirstAudioContentRecord(
|
||||
contentId = price.toLong() + 1,
|
||||
@@ -74,6 +96,7 @@ class HomeRecommendationFacadeTest {
|
||||
private class FakeHomeRecommendationQueryPort : HomeRecommendationQueryPort {
|
||||
var firstAudioContents: List<HomeFirstAudioContentRecord> = emptyList()
|
||||
var bannerIncludeAdultBanners: Boolean = false
|
||||
var bannerLang: Lang? = null
|
||||
|
||||
override fun findLiveRecommendations(
|
||||
offset: Long,
|
||||
@@ -85,9 +108,11 @@ class HomeRecommendationFacadeTest {
|
||||
override fun findHomeBanners(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultBanners: Boolean
|
||||
includeAdultBanners: Boolean,
|
||||
lang: Lang
|
||||
): List<HomeBannerRecommendationRecord> {
|
||||
bannerIncludeAdultBanners = includeAdultBanners
|
||||
bannerLang = lang
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
||||
+36
-1
@@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.content.main.tab.AudioContentMainTab
|
||||
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.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMember
|
||||
@@ -96,6 +97,38 @@ class DefaultAudioRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
assertEquals(visibleCreator.id, safeBanners.first().creatorId)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("콘텐츠 추천 배너는 언어 필터를 limit보다 먼저 적용한다")
|
||||
fun shouldFilterBannersByLangBeforeLimit() {
|
||||
val recommendationTab = saveContentRecommendationTab()
|
||||
val koBanner = saveBanner(
|
||||
"ko-audio-banner.png",
|
||||
AudioContentBannerType.LINK,
|
||||
1,
|
||||
link = "https://ko.test",
|
||||
tab = recommendationTab,
|
||||
lang = Lang.KO
|
||||
)
|
||||
val jaBanner = saveBanner(
|
||||
"ja-audio-banner.png",
|
||||
AudioContentBannerType.LINK,
|
||||
2,
|
||||
link = "https://ja.test",
|
||||
tab = recommendationTab,
|
||||
lang = Lang.JA
|
||||
)
|
||||
flushAndClear()
|
||||
|
||||
assertEquals(
|
||||
listOf("https://cdn.test/${koBanner.thumbnailImage}"),
|
||||
repository.findBanners(1, null, false, Lang.KO).map { it.imageUrl }
|
||||
)
|
||||
assertEquals(
|
||||
listOf("https://cdn.test/${jaBanner.thumbnailImage}"),
|
||||
repository.findBanners(1, null, false, Lang.JA).map { it.imageUrl }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("오리지널 시리즈는 활성 원본 시리즈를 최신순으로 반환하고 성인/차단 조건을 적용한다")
|
||||
fun shouldFindOriginalSeriesWithVisibilityConditions() {
|
||||
@@ -404,11 +437,13 @@ class DefaultAudioRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
isAdult: Boolean = false,
|
||||
creator: Member? = null,
|
||||
link: String? = null,
|
||||
tab: AudioContentMainTab? = null
|
||||
tab: AudioContentMainTab? = null,
|
||||
lang: Lang = Lang.KO
|
||||
): AudioContentBanner {
|
||||
val banner = AudioContentBanner(
|
||||
thumbnailImage = thumbnailImage,
|
||||
type = type,
|
||||
lang = lang,
|
||||
isAdult = isAdult,
|
||||
isActive = isActive,
|
||||
orders = orders
|
||||
|
||||
+4
-1
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.content.recommendation.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
|
||||
@@ -77,7 +78,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
0,
|
||||
AudioRecommendationQueryService.RECOMMENDED_AUDIO_LIMIT
|
||||
)
|
||||
Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false)
|
||||
Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false, Lang.KO)
|
||||
Mockito.verify(queryPort).findLatestAudios(
|
||||
eqValue(AudioRecommendationQueryService.LATEST_AUDIO_LIMIT),
|
||||
Mockito.isNull(),
|
||||
@@ -140,6 +141,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
fun shouldUseStoredPreferenceForMemberAdultVisibility() {
|
||||
val member = member(id = 10L)
|
||||
Mockito.doReturn(true).`when`(preferenceService).canViewAdultContent(member)
|
||||
Mockito.doReturn("JP").`when`(preferenceService).resolveCountryCode(member)
|
||||
stubFallback(
|
||||
RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL,
|
||||
0,
|
||||
@@ -150,6 +152,7 @@ class AudioRecommendationQueryServiceTest {
|
||||
service.getRecommendations(member)
|
||||
|
||||
Mockito.verify(preferenceService).canViewAdultContent(member)
|
||||
Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, member.id, true, Lang.JA)
|
||||
Mockito.verify(preferenceService, Mockito.never()).initializeDefaultPreference(member)
|
||||
verifyFallback(
|
||||
RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL,
|
||||
|
||||
+20
-2
@@ -262,6 +262,23 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
assertEquals(listOf(homeBanner.thumbnailImage), banners.map { it.thumbnailImage })
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 배너는 언어 필터를 limit보다 먼저 적용한다")
|
||||
fun shouldFilterHomeBannersByLangBeforeLimit() {
|
||||
val koBanner = saveBanner("ko-home-banner.png", AudioContentBannerType.LINK, 1, true, lang = Lang.KO)
|
||||
val jaBanner = saveBanner("ja-home-banner.png", AudioContentBannerType.LINK, 2, true, lang = Lang.JA)
|
||||
flushAndClear()
|
||||
|
||||
assertEquals(
|
||||
listOf(koBanner.thumbnailImage),
|
||||
repository.findHomeBanners(limit = 1, lang = Lang.KO).map { it.thumbnailImage }
|
||||
)
|
||||
assertEquals(
|
||||
listOf(jaBanner.thumbnailImage),
|
||||
repository.findHomeBanners(limit = 1, lang = Lang.JA).map { it.thumbnailImage }
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 배너는 성인 콘텐츠 조회가 불가능하면 비성인 배너만 반환한다")
|
||||
fun shouldExcludeAdultHomeBannersWhenAdultContentIsNotVisible() {
|
||||
@@ -2693,12 +2710,13 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
||||
event: Event? = null,
|
||||
series: Series? = null,
|
||||
tab: AudioContentMainTab? = null,
|
||||
link: String? = null
|
||||
link: String? = null,
|
||||
lang: Lang = Lang.KO
|
||||
): AudioContentBanner {
|
||||
val banner = AudioContentBanner(
|
||||
thumbnailImage = thumbnailImage,
|
||||
type = type,
|
||||
lang = Lang.KO,
|
||||
lang = lang,
|
||||
isAdult = isAdult,
|
||||
isActive = isActive,
|
||||
orders = orders
|
||||
|
||||
+15
-1
@@ -1,5 +1,6 @@
|
||||
package kr.co.vividnext.sodalive.v2.recommendation.application
|
||||
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeAiCharacterRecommendationRecord
|
||||
@@ -93,6 +94,16 @@ class HomeRecommendationQueryServiceTest {
|
||||
assertEquals(20, port.bannerLimit)
|
||||
assertEquals(100L, port.bannerMemberId)
|
||||
assertEquals(true, port.bannerIncludeAdultBanners)
|
||||
assertEquals(Lang.KO, port.bannerLang)
|
||||
assertEquals(port.banners, banners)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 배너 추천은 언어 조건을 조회 포트에 위임한다")
|
||||
fun shouldDelegateHomeBannerLang() {
|
||||
val banners = service.findHomeBanners(lang = Lang.JA)
|
||||
|
||||
assertEquals(Lang.JA, port.bannerLang)
|
||||
assertEquals(port.banners, banners)
|
||||
}
|
||||
|
||||
@@ -966,6 +977,7 @@ class HomeRecommendationQueryServiceTest {
|
||||
var bannerLimit: Int? = null
|
||||
var bannerMemberId: Long? = null
|
||||
var bannerIncludeAdultBanners: Boolean? = null
|
||||
var bannerLang: Lang? = null
|
||||
var activeCreatorLimit: Int? = null
|
||||
var activeCreatorMemberId: Long? = null
|
||||
var activeCreatorIncludeAdultActivities: Boolean? = null
|
||||
@@ -1068,11 +1080,13 @@ class HomeRecommendationQueryServiceTest {
|
||||
override fun findHomeBanners(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultBanners: Boolean
|
||||
includeAdultBanners: Boolean,
|
||||
lang: Lang
|
||||
): List<HomeBannerRecommendationRecord> {
|
||||
bannerLimit = limit
|
||||
bannerMemberId = memberId
|
||||
bannerIncludeAdultBanners = includeAdultBanners
|
||||
bannerLang = lang
|
||||
return banners
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user