feat(content-banner): 오디오 콘텐츠 배너를 언어별로 등록하고 노출한다
This commit is contained in:
41
docs/20260402_audio_content_banner_lang_ddl.sql
Normal file
41
docs/20260402_audio_content_banner_lang_ddl.sql
Normal file
@@ -0,0 +1,41 @@
|
||||
SET @schema_name := DATABASE();
|
||||
|
||||
SET @lang_column_exists := (
|
||||
SELECT COUNT(1)
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @schema_name
|
||||
AND table_name = 'content_banner'
|
||||
AND column_name = 'lang'
|
||||
);
|
||||
|
||||
SET @add_lang_column_sql := IF(
|
||||
@lang_column_exists = 0,
|
||||
'ALTER TABLE content_banner ADD COLUMN lang VARCHAR(10) NULL COMMENT ''배너 노출 언어'' AFTER type',
|
||||
'SELECT ''content_banner.lang already exists'' AS message'
|
||||
);
|
||||
|
||||
PREPARE add_lang_column_stmt FROM @add_lang_column_sql;
|
||||
EXECUTE add_lang_column_stmt;
|
||||
DEALLOCATE PREPARE add_lang_column_stmt;
|
||||
|
||||
UPDATE content_banner
|
||||
SET lang = 'KO'
|
||||
WHERE lang IS NULL;
|
||||
|
||||
SET @lang_column_nullable := (
|
||||
SELECT IS_NULLABLE
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = @schema_name
|
||||
AND table_name = 'content_banner'
|
||||
AND column_name = 'lang'
|
||||
);
|
||||
|
||||
SET @alter_lang_column_sql := IF(
|
||||
@lang_column_nullable = 'YES',
|
||||
'ALTER TABLE content_banner MODIFY COLUMN lang VARCHAR(10) NOT NULL DEFAULT ''KO'' COMMENT ''배너 노출 언어 (KO 기본, EN/JA 추가 가능)''',
|
||||
'SELECT ''content_banner.lang already normalized'' AS message'
|
||||
);
|
||||
|
||||
PREPARE alter_lang_column_stmt FROM @alter_lang_column_sql;
|
||||
EXECUTE alter_lang_column_stmt;
|
||||
DEALLOCATE PREPARE alter_lang_column_stmt;
|
||||
11
docs/20260402_오디오콘텐츠배너언어적용.md
Normal file
11
docs/20260402_오디오콘텐츠배너언어적용.md
Normal file
@@ -0,0 +1,11 @@
|
||||
- [x] 오디오 콘텐츠 배너 등록·조회 경로와 언어 처리 기준을 확인한다.
|
||||
- [x] 배너 등록 API에 `lang` 파라미터를 추가하고 지원 언어를 `Lang` 기준으로 저장하도록 수정한다.
|
||||
- [x] 관리자 배너 목록은 전체 언어 배너를 유지하고, HomeService `fetchData`는 사용자 언어와 일치하는 배너만 조회하도록 수정한다.
|
||||
- [x] 변경 파일 기준으로 검증을 수행하고 결과를 기록한다.
|
||||
|
||||
## 검증 기록
|
||||
|
||||
### 1차 구현
|
||||
- 무엇을: 오디오 콘텐츠 배너 엔티티와 등록 요청에 `lang`을 추가하고, 홈 `fetchData`에서 현재 사용자 언어를 넘겨 해당 언어 배너만 조회하도록 수정했다. 운영 반영용으로 `content_banner.lang` 컬럼 DDL도 추가했다.
|
||||
- 왜: 관리자 등록 시 언어별 배너를 구분해 저장해야 하고, 홈에서는 사용자 언어와 맞는 배너만 노출되어야 하기 때문이다. 관리자 목록 API는 기존처럼 언어 전체 배너를 그대로 조회해야 한다.
|
||||
- 어떻게: Kotlin LSP가 없어 정적 진단은 Gradle 컴파일/테스트로 대체했고, `./gradlew test --tests "kr.co.vividnext.sodalive.admin.content.banner.AdminContentBannerServiceTest" --tests "kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerRepositoryTest" --tests "kr.co.vividnext.sodalive.api.home.HomeServiceTest"`로 등록 언어 저장, 언어별 배너 조회, 홈 언어 전달을 검증했다. 이어서 `./gradlew ktlintCheck`를 실행해 스타일 검증까지 확인했고 두 명령 모두 `BUILD SUCCESSFUL`이다.
|
||||
@@ -72,7 +72,7 @@ class AdminContentBannerService(
|
||||
null
|
||||
}
|
||||
|
||||
val audioContentBanner = AudioContentBanner(type = request.type)
|
||||
val audioContentBanner = AudioContentBanner(type = request.type, lang = request.lang)
|
||||
audioContentBanner.link = request.link
|
||||
audioContentBanner.isAdult = request.isAdult
|
||||
audioContentBanner.event = event
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package kr.co.vividnext.sodalive.admin.content.banner
|
||||
|
||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
|
||||
data class CreateContentBannerRequest(
|
||||
val type: AudioContentBannerType,
|
||||
val lang: Lang,
|
||||
val tabId: Long?,
|
||||
val eventId: Long?,
|
||||
val creatorId: Long?,
|
||||
|
||||
@@ -124,7 +124,8 @@ class HomeService(
|
||||
val bannerList = bannerService.getBannerList(
|
||||
tabId = 1,
|
||||
memberId = member?.id,
|
||||
isAdult = isAdult
|
||||
isAdult = isAdult,
|
||||
lang = langContext.lang
|
||||
)
|
||||
|
||||
val originalAudioDramaList = seriesService.getOriginalAudioDramaList(
|
||||
|
||||
@@ -4,6 +4,7 @@ import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.content.main.tab.AudioContentMainTab
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
|
||||
import kr.co.vividnext.sodalive.event.Event
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import javax.persistence.Column
|
||||
import javax.persistence.Entity
|
||||
@@ -22,6 +23,9 @@ data class AudioContentBanner(
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var type: AudioContentBannerType,
|
||||
@Column(nullable = false)
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
var lang: Lang = Lang.KO,
|
||||
@Column(nullable = false)
|
||||
var isAdult: Boolean = false,
|
||||
@Column(nullable = false)
|
||||
var isActive: Boolean = true,
|
||||
|
||||
@@ -4,19 +4,20 @@ import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.content.main.banner.QAudioContentBanner.audioContentBanner
|
||||
import kr.co.vividnext.sodalive.content.main.tab.QAudioContentMainTab.audioContentMainTab
|
||||
import kr.co.vividnext.sodalive.event.QEvent.event
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.QMember.member
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface AudioContentBannerRepository : JpaRepository<AudioContentBanner, Long>, AudioContentBannerQueryRepository
|
||||
|
||||
interface AudioContentBannerQueryRepository {
|
||||
fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean): List<AudioContentBanner>
|
||||
fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean, lang: Lang? = null): List<AudioContentBanner>
|
||||
}
|
||||
|
||||
class AudioContentBannerQueryRepositoryImpl(
|
||||
private val queryFactory: JPAQueryFactory
|
||||
) : AudioContentBannerQueryRepository {
|
||||
override fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean): List<AudioContentBanner> {
|
||||
override fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean, lang: Lang?): List<AudioContentBanner> {
|
||||
var where = audioContentBanner.isActive.isTrue
|
||||
|
||||
where = if (tabId == 1L) {
|
||||
@@ -29,6 +30,10 @@ class AudioContentBannerQueryRepositoryImpl(
|
||||
where = where.and(audioContentBanner.isAdult.isFalse)
|
||||
}
|
||||
|
||||
if (lang != null) {
|
||||
where = where.and(audioContentBanner.lang.eq(lang))
|
||||
}
|
||||
|
||||
return queryFactory
|
||||
.selectFrom(audioContentBanner)
|
||||
.leftJoin(audioContentBanner.tab, audioContentMainTab)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package kr.co.vividnext.sodalive.content.main.banner
|
||||
|
||||
import kr.co.vividnext.sodalive.event.EventItem
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.stereotype.Service
|
||||
@@ -13,8 +14,8 @@ class AudioContentBannerService(
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val imageHost: String
|
||||
) {
|
||||
fun getBannerList(tabId: Long, memberId: Long?, isAdult: Boolean): List<GetAudioContentBannerResponse> {
|
||||
return repository.getAudioContentMainBannerList(tabId, isAdult)
|
||||
fun getBannerList(tabId: Long, memberId: Long?, isAdult: Boolean, lang: Lang? = null): List<GetAudioContentBannerResponse> {
|
||||
return repository.getAudioContentMainBannerList(tabId, isAdult, lang)
|
||||
.filter {
|
||||
if (it.type == AudioContentBannerType.CREATOR && it.creator != null && memberId != null) {
|
||||
!isBlockedBetweenMembers(memberId = memberId, creatorId = it.creator!!.id!!)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package kr.co.vividnext.sodalive.admin.content.banner
|
||||
|
||||
import com.amazonaws.services.s3.AmazonS3Client
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import kr.co.vividnext.sodalive.admin.content.series.AdminContentSeriesRepository
|
||||
import kr.co.vividnext.sodalive.admin.content.tab.AdminContentMainTabRepository
|
||||
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBanner
|
||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType
|
||||
import kr.co.vividnext.sodalive.event.EventRepository
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.mock.web.MockMultipartFile
|
||||
import java.net.URL
|
||||
|
||||
class AdminContentBannerServiceTest {
|
||||
private lateinit var amazonS3Client: AmazonS3Client
|
||||
private lateinit var s3Uploader: S3Uploader
|
||||
private lateinit var repository: AdminContentBannerRepository
|
||||
private lateinit var memberRepository: MemberRepository
|
||||
private lateinit var seriesRepository: AdminContentSeriesRepository
|
||||
private lateinit var eventRepository: EventRepository
|
||||
private lateinit var contentMainTabRepository: AdminContentMainTabRepository
|
||||
private lateinit var service: AdminContentBannerService
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
amazonS3Client = Mockito.mock(AmazonS3Client::class.java)
|
||||
s3Uploader = S3Uploader(amazonS3Client)
|
||||
repository = Mockito.mock(AdminContentBannerRepository::class.java)
|
||||
memberRepository = Mockito.mock(MemberRepository::class.java)
|
||||
seriesRepository = Mockito.mock(AdminContentSeriesRepository::class.java)
|
||||
eventRepository = Mockito.mock(EventRepository::class.java)
|
||||
contentMainTabRepository = Mockito.mock(AdminContentMainTabRepository::class.java)
|
||||
service = AdminContentBannerService(
|
||||
s3Uploader = s3Uploader,
|
||||
repository = repository,
|
||||
memberRepository = memberRepository,
|
||||
seriesRepository = seriesRepository,
|
||||
eventRepository = eventRepository,
|
||||
contentMainTabRepository = contentMainTabRepository,
|
||||
objectMapper = jacksonObjectMapper(),
|
||||
bucket = "test-bucket"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("배너 등록 요청의 lang 값을 저장한다")
|
||||
fun shouldSaveRequestedLangWhenCreatingBanner() {
|
||||
val image = MockMultipartFile("image", "banner.png", "image/png", "image".toByteArray())
|
||||
val requestString = """
|
||||
{"type":"LINK","lang":"ja","tabId":null,"eventId":null,"creatorId":null,"seriesId":null,"link":"https://example.com","isAdult":false}
|
||||
""".trimIndent()
|
||||
val savedBannerCaptor = ArgumentCaptor.forClass(AudioContentBanner::class.java)
|
||||
|
||||
Mockito.`when`(repository.save(Mockito.any(AudioContentBanner::class.java)))
|
||||
.thenAnswer {
|
||||
(it.arguments[0] as AudioContentBanner).also { banner ->
|
||||
banner.id = 1L
|
||||
}
|
||||
}
|
||||
Mockito.doAnswer { URL("https://cdn.test/${it.arguments[1]}") }
|
||||
.`when`(amazonS3Client)
|
||||
.getUrl(Mockito.eq("test-bucket"), Mockito.anyString())
|
||||
|
||||
service.createAudioContentMainBanner(image, requestString)
|
||||
|
||||
Mockito.verify(repository).save(savedBannerCaptor.capture())
|
||||
assertEquals(AudioContentBannerType.LINK, savedBannerCaptor.value.type)
|
||||
assertEquals(Lang.JA, savedBannerCaptor.value.lang)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
package kr.co.vividnext.sodalive.api.home
|
||||
|
||||
import kr.co.vividnext.sodalive.audition.AuditionService
|
||||
import kr.co.vividnext.sodalive.chat.character.service.ChatCharacterService
|
||||
import kr.co.vividnext.sodalive.content.AudioContentService
|
||||
import kr.co.vividnext.sodalive.content.ContentType
|
||||
import kr.co.vividnext.sodalive.content.SortType
|
||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerService
|
||||
import kr.co.vividnext.sodalive.content.series.ContentSeriesService
|
||||
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeService
|
||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
|
||||
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoomService
|
||||
import kr.co.vividnext.sodalive.live.room.LiveRoomStatus
|
||||
import kr.co.vividnext.sodalive.query.recommend.RecommendChannelQueryService
|
||||
import kr.co.vividnext.sodalive.rank.ContentRankingSortType
|
||||
import kr.co.vividnext.sodalive.rank.RankingRepository
|
||||
import kr.co.vividnext.sodalive.rank.RankingService
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.data.domain.Pageable
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
|
||||
class HomeServiceTest {
|
||||
private lateinit var liveRoomService: LiveRoomService
|
||||
private lateinit var auditionService: AuditionService
|
||||
private lateinit var seriesService: ContentSeriesService
|
||||
private lateinit var contentService: AudioContentService
|
||||
private lateinit var bannerService: AudioContentBannerService
|
||||
private lateinit var contentThemeService: AudioContentThemeService
|
||||
private lateinit var recommendChannelService: RecommendChannelQueryService
|
||||
private lateinit var characterService: ChatCharacterService
|
||||
private lateinit var rankingService: RankingService
|
||||
private lateinit var rankingRepository: RankingRepository
|
||||
private lateinit var explorerQueryRepository: ExplorerQueryRepository
|
||||
private lateinit var service: HomeService
|
||||
private val timezone = "Asia/Seoul"
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
liveRoomService = Mockito.mock(LiveRoomService::class.java)
|
||||
auditionService = Mockito.mock(AuditionService::class.java)
|
||||
seriesService = Mockito.mock(ContentSeriesService::class.java)
|
||||
contentService = Mockito.mock(AudioContentService::class.java)
|
||||
bannerService = Mockito.mock(AudioContentBannerService::class.java)
|
||||
contentThemeService = Mockito.mock(AudioContentThemeService::class.java)
|
||||
recommendChannelService = Mockito.mock(RecommendChannelQueryService::class.java)
|
||||
characterService = Mockito.mock(ChatCharacterService::class.java)
|
||||
rankingService = Mockito.mock(RankingService::class.java)
|
||||
rankingRepository = Mockito.mock(RankingRepository::class.java)
|
||||
explorerQueryRepository = Mockito.mock(ExplorerQueryRepository::class.java)
|
||||
service = HomeService(
|
||||
liveRoomService = liveRoomService,
|
||||
auditionService = auditionService,
|
||||
seriesService = seriesService,
|
||||
contentService = contentService,
|
||||
bannerService = bannerService,
|
||||
contentThemeService = contentThemeService,
|
||||
recommendChannelService = recommendChannelService,
|
||||
characterService = characterService,
|
||||
rankingService = rankingService,
|
||||
rankingRepository = rankingRepository,
|
||||
explorerQueryRepository = explorerQueryRepository,
|
||||
langContext = LangContext().apply { setLang(Lang.JA) },
|
||||
memberContentPreferenceService = Mockito.mock(
|
||||
kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService::class.java
|
||||
),
|
||||
imageHost = "https://cdn.test"
|
||||
)
|
||||
|
||||
val systemTime = LocalDateTime.now()
|
||||
val zonedDateTime = systemTime
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.withZoneSameInstant(ZoneId.of(timezone))
|
||||
val expectedDayOfWeek = when (zonedDateTime.dayOfWeek) {
|
||||
DayOfWeek.MONDAY -> SeriesPublishedDaysOfWeek.MON
|
||||
DayOfWeek.TUESDAY -> SeriesPublishedDaysOfWeek.TUE
|
||||
DayOfWeek.WEDNESDAY -> SeriesPublishedDaysOfWeek.WED
|
||||
DayOfWeek.THURSDAY -> SeriesPublishedDaysOfWeek.THU
|
||||
DayOfWeek.FRIDAY -> SeriesPublishedDaysOfWeek.FRI
|
||||
DayOfWeek.SATURDAY -> SeriesPublishedDaysOfWeek.SAT
|
||||
DayOfWeek.SUNDAY -> SeriesPublishedDaysOfWeek.SUN
|
||||
null -> SeriesPublishedDaysOfWeek.RANDOM
|
||||
}
|
||||
val currentDateTime = LocalDateTime.now()
|
||||
val rankingStartDate = currentDateTime
|
||||
.withHour(15)
|
||||
.withMinute(0)
|
||||
.withSecond(0)
|
||||
.minusWeeks(1)
|
||||
.with(java.time.temporal.TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
|
||||
val rankingEndDate = rankingStartDate.plusDays(6)
|
||||
|
||||
Mockito.doReturn(emptyList<Any>()).`when`(liveRoomService)
|
||||
.getRoomList(null, LiveRoomStatus.NOW, Pageable.ofSize(10), null, timezone)
|
||||
Mockito.`when`(rankingRepository.getCreatorRankings(null)).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentThemeService.getActiveThemeOfContent(
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
ContentType.ALL,
|
||||
listOf("다시듣기")
|
||||
)
|
||||
).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentThemeService.getActiveThemeOfContent(
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
ContentType.ALL,
|
||||
emptyList()
|
||||
)
|
||||
).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
0,
|
||||
20,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
0,
|
||||
50,
|
||||
SortType.NEWEST,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
50,
|
||||
100,
|
||||
SortType.NEWEST,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
150,
|
||||
150,
|
||||
SortType.NEWEST,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
0,
|
||||
50,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
50,
|
||||
100,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
150,
|
||||
150,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
0,
|
||||
50,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
50,
|
||||
100,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
contentService.getLatestContentByTheme(
|
||||
null,
|
||||
emptyList(),
|
||||
ContentType.ALL,
|
||||
150,
|
||||
150,
|
||||
SortType.NEWEST,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
emptyList()
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(bannerService.getBannerList(1L, null, false, Lang.JA)).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
seriesService.getOriginalAudioDramaList(null, false, ContentType.ALL, 0, 20)
|
||||
).thenReturn(emptyList())
|
||||
Mockito.`when`(auditionService.getInProgressAuditionList(false)).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
seriesService.getDayOfWeekSeriesList(null, false, ContentType.ALL, expectedDayOfWeek, 0, 10)
|
||||
).thenReturn(emptyList())
|
||||
Mockito.`when`(characterService.getPopularCharacters("ja", 20)).thenReturn(emptyList())
|
||||
Mockito.`when`(
|
||||
rankingService.getContentRanking(
|
||||
null,
|
||||
false,
|
||||
ContentType.ALL,
|
||||
rankingStartDate.minusDays(1),
|
||||
rankingEndDate,
|
||||
0,
|
||||
12,
|
||||
ContentRankingSortType.REVENUE,
|
||||
""
|
||||
)
|
||||
)
|
||||
.thenReturn(emptyList())
|
||||
Mockito.`when`(recommendChannelService.getRecommendChannel(null, false, ContentType.ALL)).thenReturn(emptyList())
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 fetchData는 현재 요청 언어를 배너 조회에 전달한다")
|
||||
fun shouldPassCurrentLangToBannerServiceWhenFetchingHome() {
|
||||
service.fetchData(timezone = timezone, member = null)
|
||||
|
||||
Mockito.verify(bannerService).getBannerList(1L, null, false, Lang.JA)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package kr.co.vividnext.sodalive.content.main.banner
|
||||
|
||||
import kr.co.vividnext.sodalive.configs.QueryDslConfig
|
||||
import kr.co.vividnext.sodalive.i18n.Lang
|
||||
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.orm.jpa.DataJpaTest
|
||||
import org.springframework.context.annotation.Import
|
||||
|
||||
@DataJpaTest
|
||||
@Import(QueryDslConfig::class)
|
||||
class AudioContentBannerRepositoryTest @Autowired constructor(
|
||||
private val repository: AudioContentBannerRepository
|
||||
) {
|
||||
@Test
|
||||
@DisplayName("사용자 배너 조회는 요청 언어와 일치하는 배너만 반환한다")
|
||||
fun shouldReturnOnlyRequestedLanguageBanners() {
|
||||
repository.saveAndFlush(
|
||||
AudioContentBanner(
|
||||
thumbnailImage = "banner/ko.png",
|
||||
type = AudioContentBannerType.LINK,
|
||||
lang = Lang.KO
|
||||
).apply {
|
||||
link = "https://ko.example.com"
|
||||
}
|
||||
)
|
||||
repository.saveAndFlush(
|
||||
AudioContentBanner(
|
||||
thumbnailImage = "banner/ja.png",
|
||||
type = AudioContentBannerType.LINK,
|
||||
lang = Lang.JA
|
||||
).apply {
|
||||
link = "https://ja.example.com"
|
||||
}
|
||||
)
|
||||
|
||||
val banners = repository.getAudioContentMainBannerList(tabId = 1L, isAdult = false, lang = Lang.JA)
|
||||
|
||||
assertEquals(1, banners.size)
|
||||
assertEquals(Lang.JA, banners.first().lang)
|
||||
assertEquals("https://ja.example.com", banners.first().link)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user