feat(home): 크리에이터 채널 홈 정책을 보강한다
This commit is contained in:
@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository
|
||||
import kr.co.vividnext.sodalive.content.order.LimitedEditionOrderRepository
|
||||
import kr.co.vividnext.sodalive.content.order.OrderRepository
|
||||
import kr.co.vividnext.sodalive.content.order.OrderType
|
||||
import kr.co.vividnext.sodalive.content.pin.PinContent
|
||||
import kr.co.vividnext.sodalive.content.pin.PinContentRepository
|
||||
import kr.co.vividnext.sodalive.content.theme.AudioContentTheme
|
||||
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
|
||||
@@ -20,6 +21,7 @@ import kr.co.vividnext.sodalive.i18n.LangContext
|
||||
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||
import kr.co.vividnext.sodalive.i18n.translation.ResourceTranslationJobScheduler
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||
import kr.co.vividnext.sodalive.v2.home.following.application.HomeFollowingNewsPublishService
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.application.CreatorContentViewHistoryService
|
||||
@@ -52,6 +54,7 @@ class AudioContentServiceTest {
|
||||
private lateinit var commentRepository: AudioContentCommentRepository
|
||||
private lateinit var audioContentLikeRepository: AudioContentLikeRepository
|
||||
private lateinit var pinContentRepository: PinContentRepository
|
||||
private lateinit var memberRepository: MemberRepository
|
||||
private lateinit var resourceTranslationJobScheduler: ResourceTranslationJobScheduler
|
||||
private lateinit var contentTranslationRepository: ContentTranslationRepository
|
||||
private lateinit var s3Uploader: S3Uploader
|
||||
@@ -76,6 +79,7 @@ class AudioContentServiceTest {
|
||||
commentRepository = Mockito.mock(AudioContentCommentRepository::class.java)
|
||||
audioContentLikeRepository = Mockito.mock(AudioContentLikeRepository::class.java)
|
||||
pinContentRepository = Mockito.mock(PinContentRepository::class.java)
|
||||
memberRepository = Mockito.mock(MemberRepository::class.java)
|
||||
resourceTranslationJobScheduler = Mockito.mock(ResourceTranslationJobScheduler::class.java)
|
||||
contentTranslationRepository = Mockito.mock(ContentTranslationRepository::class.java)
|
||||
s3Uploader = Mockito.mock(S3Uploader::class.java)
|
||||
@@ -97,6 +101,7 @@ class AudioContentServiceTest {
|
||||
commentRepository = commentRepository,
|
||||
audioContentLikeRepository = audioContentLikeRepository,
|
||||
pinContentRepository = pinContentRepository,
|
||||
memberRepository = memberRepository,
|
||||
resourceTranslationJobScheduler = resourceTranslationJobScheduler,
|
||||
contentTranslationRepository = contentTranslationRepository,
|
||||
s3Uploader = s3Uploader,
|
||||
@@ -450,6 +455,123 @@ class AudioContentServiceTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("오디오 상세의 상단 고정 가능 여부는 활성 고정 9개 상한을 따른다")
|
||||
fun shouldExposeAvailablePinByNineActivePinLimit() {
|
||||
val creator = createMember(id = 2400L, nickname = "pin-limit-creator")
|
||||
val audioContent = createAudioContent(creator = creator)
|
||||
stubSuccessfulDetailDependencies(creator, creator, audioContent)
|
||||
Mockito.`when`(pinContentRepository.getPinContentList(memberId = creator.id!!, active = true))
|
||||
.thenReturn(createPinContents(8))
|
||||
.thenReturn(createPinContents(9))
|
||||
|
||||
val availableResponse = service.getDetail(
|
||||
id = audioContent.id!!,
|
||||
member = creator,
|
||||
isAdultContentVisible = false,
|
||||
timezone = "Asia/Seoul"
|
||||
)
|
||||
val unavailableResponse = service.getDetail(
|
||||
id = audioContent.id!!,
|
||||
member = creator,
|
||||
isAdultContentVisible = false,
|
||||
timezone = "Asia/Seoul"
|
||||
)
|
||||
|
||||
assertTrue(availableResponse.isAvailablePin)
|
||||
assertEquals(false, unavailableResponse.isAvailablePin)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("10번째 상단 고정은 가장 오래된 활성 고정을 새 콘텐츠로 교체한다")
|
||||
fun shouldReuseOldestActivePinWhenPinningTenthContent() {
|
||||
val creator = createMember(id = 2410L, nickname = "pin-reuse-creator")
|
||||
val audioContent = createAudioContent(creator = creator)
|
||||
val oldestPinContent = createPinContents(1).single()
|
||||
Mockito.`when`(repository.findByIdAndCreatorId(contentId = audioContent.id!!, creatorId = creator.id!!))
|
||||
.thenReturn(audioContent)
|
||||
Mockito.`when`(memberRepository.findByIdForUpdate(creator.id!!)).thenReturn(creator)
|
||||
Mockito.`when`(
|
||||
pinContentRepository.findByContentIdAndMemberId(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = creator.id!!
|
||||
)
|
||||
).thenReturn(null)
|
||||
Mockito.`when`(pinContentRepository.getPinContentList(memberId = creator.id!!, active = true))
|
||||
.thenReturn(listOf(oldestPinContent) + createPinContents(8))
|
||||
|
||||
service.pinToTheTop(contentId = audioContent.id!!, member = creator)
|
||||
|
||||
Mockito.inOrder(memberRepository, repository, pinContentRepository).apply {
|
||||
verify(memberRepository).findByIdForUpdate(creator.id!!)
|
||||
verify(repository).findByIdAndCreatorId(contentId = audioContent.id!!, creatorId = creator.id!!)
|
||||
verify(pinContentRepository).findByContentIdAndMemberId(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = creator.id!!
|
||||
)
|
||||
verify(pinContentRepository).getPinContentList(memberId = creator.id!!, active = true)
|
||||
}
|
||||
assertTrue(oldestPinContent.isActive)
|
||||
assertEquals(creator, oldestPinContent.member)
|
||||
assertEquals(audioContent, oldestPinContent.content)
|
||||
Mockito.verify(pinContentRepository).save(oldestPinContent)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("상단 고정 해제는 고정 행 조회 전에 크리에이터를 잠근다")
|
||||
fun shouldLockCreatorBeforeFindingPinWhenUnpinningContent() {
|
||||
val creator = createMember(id = 2415L, nickname = "pin-unpin-lock-creator")
|
||||
val audioContent = createAudioContent(creator = creator)
|
||||
val pinContent = PinContent(isActive = true)
|
||||
pinContent.member = creator
|
||||
pinContent.content = audioContent
|
||||
Mockito.`when`(memberRepository.findByIdForUpdate(creator.id!!)).thenReturn(creator)
|
||||
Mockito.`when`(
|
||||
pinContentRepository.findByContentIdAndMemberId(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = creator.id!!
|
||||
)
|
||||
).thenReturn(pinContent)
|
||||
|
||||
service.unpinAtTheTop(contentId = audioContent.id!!, member = creator)
|
||||
|
||||
Mockito.inOrder(memberRepository, pinContentRepository).apply {
|
||||
verify(memberRepository).findByIdForUpdate(creator.id!!)
|
||||
verify(pinContentRepository).findByContentIdAndMemberId(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = creator.id!!
|
||||
)
|
||||
}
|
||||
assertEquals(false, pinContent.isActive)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("비활성 고정을 다시 활성화할 때도 활성 고정은 9개를 넘지 않는다")
|
||||
fun shouldKeepNineActivePinsWhenReactivatingInactivePin() {
|
||||
val creator = createMember(id = 2420L, nickname = "pin-reactivate-creator")
|
||||
val audioContent = createAudioContent(creator = creator)
|
||||
val inactivePinContent = PinContent(isActive = false)
|
||||
inactivePinContent.member = creator
|
||||
inactivePinContent.content = audioContent
|
||||
val oldestActivePinContent = createPinContents(1).single()
|
||||
Mockito.`when`(repository.findByIdAndCreatorId(contentId = audioContent.id!!, creatorId = creator.id!!))
|
||||
.thenReturn(audioContent)
|
||||
Mockito.`when`(memberRepository.findByIdForUpdate(creator.id!!)).thenReturn(creator)
|
||||
Mockito.`when`(
|
||||
pinContentRepository.findByContentIdAndMemberId(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = creator.id!!
|
||||
)
|
||||
).thenReturn(inactivePinContent)
|
||||
Mockito.`when`(pinContentRepository.getPinContentList(memberId = creator.id!!, active = true))
|
||||
.thenReturn(listOf(oldestActivePinContent) + createPinContents(8))
|
||||
|
||||
service.pinToTheTop(contentId = audioContent.id!!, member = creator)
|
||||
|
||||
assertEquals(false, oldestActivePinContent.isActive)
|
||||
assertTrue(inactivePinContent.isActive)
|
||||
}
|
||||
|
||||
private fun createMember(id: Long, nickname: String): Member {
|
||||
val member = Member(
|
||||
email = "$nickname@test.com",
|
||||
@@ -496,6 +618,10 @@ class AudioContentServiceTest {
|
||||
return audioContent
|
||||
}
|
||||
|
||||
private fun createPinContents(count: Int): List<PinContent> {
|
||||
return (1..count).map { PinContent() }
|
||||
}
|
||||
|
||||
private fun stubSuccessfulDetailDependencies(viewer: Member, creator: Member, audioContent: AudioContent) {
|
||||
Mockito.`when`(repository.findById(audioContent.id!!)).thenReturn(Optional.of(audioContent))
|
||||
Mockito.`when`(explorerQueryRepository.getMember(creator.id!!)).thenReturn(creator)
|
||||
|
||||
Reference in New Issue
Block a user