From 45337663e5080fdb50179dd8b76a08cd103dd9b5 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sun, 21 Jun 2026 23:20:36 +0900 Subject: [PATCH] =?UTF-8?q?test(creator-channel):=20=ED=99=88=20=EC=BB=A4?= =?UTF-8?q?=EB=AE=A4=EB=8B=88=ED=8B=B0=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=EC=9D=84=20=EA=B2=80=EC=A6=9D=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/CreatorChannelHomeControllerTest.kt | 15 +- .../CreatorChannelHomeFacadeTest.kt | 15 +- .../CreatorChannelHomeQueryServiceTest.kt | 130 ++++++++++++++---- 3 files changed, 121 insertions(+), 39 deletions(-) diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt index 96f2e05f..74793e78 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/adapter/in/web/CreatorChannelHomeControllerTest.kt @@ -10,8 +10,8 @@ import kr.co.vividnext.sodalive.v2.api.creator.channel.home.application.CreatorC import kr.co.vividnext.sodalive.v2.api.creator.channel.home.dto.CreatorChannelHomeResponse import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent +import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPost import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelActivity -import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCommunityPost import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCreator import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelDonation import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelFanTalk @@ -132,6 +132,9 @@ class CreatorChannelHomeControllerTest @Autowired constructor( .andExpect(jsonPath("$.data.channelDonations[0].donationId").doesNotExist()) .andExpect(jsonPath("$.data.channelDonations[0].memberId").doesNotExist()) .andExpect(jsonPath("$.data.channelDonations[0].isSecret").doesNotExist()) + .andExpect(jsonPath("$.data.notices[0].dateUtc").value("2026-06-12T04:00:00Z")) + .andExpect(jsonPath("$.data.notices[0].imageUrl").doesNotExist()) + .andExpect(jsonPath("$.data.notices[0].audioUrl").doesNotExist()) .andExpect(jsonPath("$.data.series[0].isNew").value(true)) .andExpect(jsonPath("$.data.series[0].isOriginal").value(true)) @@ -159,14 +162,16 @@ class CreatorChannelHomeControllerTest @Autowired constructor( creatorId = 1L, creatorNickname = "creator", creatorProfileUrl = "profile.png", - imageUrl = "image.png", - audioUrl = "audio.mp3", + imageUrl = null, + audioUrl = null, content = "notice", price = 10, - date = LocalDateTime.of(2026, 6, 12, 4, 0), + createdAt = LocalDateTime.of(2026, 6, 12, 4, 0), existOrdered = true, + isCommentAvailable = true, likeCount = 2, - commentCount = 3 + commentCount = 3, + isPinned = true ) return CreatorChannelHome( diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/application/CreatorChannelHomeFacadeTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/application/CreatorChannelHomeFacadeTest.kt index 8b5751eb..eddf9c56 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/application/CreatorChannelHomeFacadeTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/creator/channel/home/application/CreatorChannelHomeFacadeTest.kt @@ -4,9 +4,9 @@ import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent +import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPost import kr.co.vividnext.sodalive.v2.creator.channel.home.application.CreatorChannelHomeQueryService import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelActivity -import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCommunityPost import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCreator import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelDonation import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelFanTalk @@ -18,6 +18,7 @@ import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSer import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSns import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -58,6 +59,8 @@ class CreatorChannelHomeFacadeTest { assertFalse(response.latestAudioContent?.isRented == true) assertEquals("thanks", response.channelDonations.first().message) assertEquals(301L, response.notices.first().postId) + assertEquals("2026-06-12T04:00:00Z", response.notices.first().dateUtc) + assertNull(response.notices.first().imageUrl) assertEquals(501L, response.schedules.first().targetId) assertEquals(202L, response.audioContents.first().audioContentId) assertFalse(response.audioContents.first().isOwned) @@ -89,14 +92,16 @@ class CreatorChannelHomeFacadeTest { creatorId = 1L, creatorNickname = "creator", creatorProfileUrl = "profile.png", - imageUrl = "image.png", - audioUrl = "audio.mp3", + imageUrl = null, + audioUrl = null, content = "notice", price = 10, - date = LocalDateTime.of(2026, 6, 12, 4, 0), + createdAt = LocalDateTime.of(2026, 6, 12, 4, 0), existOrdered = true, + isCommentAvailable = true, likeCount = 2, - commentCount = 3 + commentCount = 3, + isPinned = true ) return CreatorChannelHome( diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/home/application/CreatorChannelHomeQueryServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/home/application/CreatorChannelHomeQueryServiceTest.kt index 07d8be61..2a32e3b0 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/home/application/CreatorChannelHomeQueryServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/creator/channel/home/application/CreatorChannelHomeQueryServiceTest.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.v2.creator.channel.home.application import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import kr.co.vividnext.sodalive.aws.cloudfront.AudioContentCloudFront import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.ContentType import kr.co.vividnext.sodalive.i18n.Lang @@ -16,8 +17,13 @@ import kr.co.vividnext.sodalive.member.contentpreference.ViewerContentPreference import kr.co.vividnext.sodalive.v2.api.creator.channel.home.dto.CreatorChannelHomeResponse import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent +import kr.co.vividnext.sodalive.v2.creator.channel.community.application.CreatorChannelCommunityQueryService +import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityPost +import kr.co.vividnext.sodalive.v2.creator.channel.community.domain.CreatorChannelCommunityQueryPolicy +import kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityCreatorRecord +import kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityPostRecord +import kr.co.vividnext.sodalive.v2.creator.channel.community.port.out.CreatorChannelCommunityQueryPort import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelActivity -import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCommunityPost import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelCreator import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelDonation import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelFanTalk @@ -30,7 +36,6 @@ import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSer import kr.co.vividnext.sodalive.v2.creator.channel.home.domain.CreatorChannelSns import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelActivityRecord import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelAudioContentRecord -import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelCommunityPostRecord import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelCreatorRecord import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelDonationRecord import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelFanTalkRecord @@ -49,6 +54,7 @@ import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.mockito.Mockito +import org.springframework.beans.factory.ObjectProvider import java.time.LocalDateTime class CreatorChannelHomeQueryServiceTest { @@ -58,7 +64,8 @@ class CreatorChannelHomeQueryServiceTest { @DisplayName("크리에이터 채널 홈 서비스는 모든 섹션을 조립하고 최종 정책을 적용한다") fun shouldAssembleCreatorChannelHomeWithFinalPolicies() { val port = FakeCreatorChannelHomeQueryPort() - val service = createService(port, canViewAdultContent = false) + val communityPort = FakeCreatorChannelCommunityQueryPort() + val service = createService(port, communityPort, canViewAdultContent = false) val viewer = createMember(id = 10L, gender = Gender.FEMALE, authGender = 1) val now = LocalDateTime.of(2026, 6, 13, 10, 0) @@ -76,7 +83,13 @@ class CreatorChannelHomeQueryServiceTest { assertEquals(listOf(402L, 401L, 404L), home.schedules.map { it.targetId }) assertFalse(home.schedules.any { it.isAdult }) assertEquals("https://cdn.test/profile/fan.png", home.channelDonations.first().profileImageUrl) - assertEquals("https://cdn.test/community.png", home.notices.first().imageUrl) + assertNull(home.notices.first().imageUrl) + assertNull(home.notices.first().audioUrl) + assertEquals(listOf(1L, 1L), communityPort.homeCreatorIds) + assertEquals(listOf(10L, 10L), communityPort.homeViewerIds) + assertEquals(listOf(true, false), communityPort.homeIsPinnedValues) + assertEquals(listOf(false, false), communityPort.homeCanViewAdultContentValues) + assertEquals(listOf(3, 3), communityPort.homeLimits) assertEquals("https://cdn.test/series.png", home.series.first().coverImageUrl) assertEquals("introduce", home.introduce) assertEquals(Gender.MALE, port.currentLiveEffectiveViewerGender) @@ -272,10 +285,12 @@ class CreatorChannelHomeQueryServiceTest { audioUrl = "audio.mp3", content = "notice", price = 10, - date = LocalDateTime.of(2026, 6, 12, 4, 0), + createdAt = LocalDateTime.of(2026, 6, 12, 4, 0), existOrdered = true, + isCommentAvailable = true, likeCount = 2, - commentCount = 3 + commentCount = 3, + isPinned = true ) return CreatorChannelHome( @@ -392,6 +407,7 @@ class CreatorChannelHomeQueryServiceTest { private fun createService( port: FakeCreatorChannelHomeQueryPort, + communityPort: FakeCreatorChannelCommunityQueryPort = FakeCreatorChannelCommunityQueryPort(), canViewAdultContent: Boolean = true ): CreatorChannelHomeQueryService { val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java) @@ -408,8 +424,20 @@ class CreatorChannelHomeQueryServiceTest { val messageSource = SodaMessageSource() val langContext = LangContext() langContext.setLang(Lang.KO) + val audioContentCloudFront = Mockito.mock(AudioContentCloudFront::class.java) + Mockito.`when`(audioContentCloudFront.generateSignedURL(Mockito.anyString(), Mockito.anyLong())) + .thenAnswer { invocation -> "https://signed.test/${invocation.getArgument(0)}" } return CreatorChannelHomeQueryService( queryPort = port, + communityQueryService = CreatorChannelCommunityQueryService( + queryPortProvider = FixedCreatorChannelCommunityQueryPortProvider(communityPort), + queryPolicy = CreatorChannelCommunityQueryPolicy(), + memberContentPreferenceService = preferenceService, + audioContentCloudFront = audioContentCloudFront, + messageSource = messageSource, + langContext = langContext, + cloudFrontHost = "https://cdn.test" + ), queryPolicy = CreatorChannelHomeQueryPolicy(), memberContentPreferenceService = preferenceService, messageSource = messageSource, @@ -517,29 +545,6 @@ private class FakeCreatorChannelHomeQueryPort : CreatorChannelHomeQueryPort { ) ) - override fun findCommunityPosts( - creatorId: Long, - viewerId: Long?, - isFixed: Boolean, - canViewAdultContent: Boolean, - limit: Int - ): List = listOf( - CreatorChannelCommunityPostRecord( - postId = if (isFixed) 301L else 302L, - creatorId = creatorId, - creatorNickname = "creator", - creatorProfilePath = "profile/creator.png", - imagePath = "community.png", - audioPath = "community.mp3", - content = if (isFixed) "notice" else "community", - price = 0, - date = LocalDateTime.of(2026, 6, 13, 7, 0), - existOrdered = false, - likeCount = 3, - commentCount = 4 - ) - ) - override fun findSchedules( creatorId: Long, now: LocalDateTime, @@ -666,3 +671,70 @@ private class FakeCreatorChannelHomeQueryPort : CreatorChannelHomeQueryPort { ) } } +private class FixedCreatorChannelCommunityQueryPortProvider( + private val port: CreatorChannelCommunityQueryPort +) : ObjectProvider { + override fun getObject(vararg args: Any?): CreatorChannelCommunityQueryPort = port + + override fun getIfAvailable(): CreatorChannelCommunityQueryPort = port + + override fun getIfUnique(): CreatorChannelCommunityQueryPort = port + + override fun getObject(): CreatorChannelCommunityQueryPort = port +} + +private class FakeCreatorChannelCommunityQueryPort : CreatorChannelCommunityQueryPort { + val homeCreatorIds = mutableListOf() + val homeViewerIds = mutableListOf() + val homeIsPinnedValues = mutableListOf() + val homeCanViewAdultContentValues = mutableListOf() + val homeLimits = mutableListOf() + + override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelCommunityCreatorRecord? { + return CreatorChannelCommunityCreatorRecord(creatorId = creatorId, role = MemberRole.CREATOR, nickname = "creator") + } + + override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = false + + override fun countCommunityPosts(creatorId: Long, viewerId: Long, canViewAdultContent: Boolean): Int = 0 + + override fun findCommunityPosts( + creatorId: Long, + viewerId: Long, + canViewAdultContent: Boolean, + offset: Long, + limit: Int + ): List = emptyList() + + override fun findHomeCommunityPosts( + creatorId: Long, + viewerId: Long, + isPinned: Boolean, + canViewAdultContent: Boolean, + limit: Int + ): List { + homeCreatorIds += creatorId + homeViewerIds += viewerId + homeIsPinnedValues += isPinned + homeCanViewAdultContentValues += canViewAdultContent + homeLimits += limit + return listOf( + CreatorChannelCommunityPostRecord( + postId = if (isPinned) 301L else 302L, + creatorId = creatorId, + creatorNickname = "creator", + creatorProfilePath = "profile/creator.png", + imagePath = if (isPinned) "image/301.png" else "image/302.png", + audioPath = if (isPinned) "audio/301.mp3" else "audio/302.mp3", + content = if (isPinned) "notice" else "community", + price = 100, + createdAt = LocalDateTime.of(2026, 6, 13, 7, 0), + existOrdered = false, + isCommentAvailable = true, + likeCount = 3, + commentCount = 4, + isPinned = isPinned + ) + ) + } +}