feat(content): 콘텐츠 조회 이력 실패 로그를 남긴다
This commit is contained in:
@@ -40,6 +40,7 @@ import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
|||||||
import kr.co.vividnext.sodalive.member.contentpreference.isAdultVisibleByPolicy
|
import kr.co.vividnext.sodalive.member.contentpreference.isAdultVisibleByPolicy
|
||||||
import kr.co.vividnext.sodalive.utils.generateFileName
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
||||||
import kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryService
|
import kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryService
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.cache.annotation.Cacheable
|
import org.springframework.cache.annotation.Cacheable
|
||||||
import org.springframework.context.ApplicationEventPublisher
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
@@ -91,6 +92,8 @@ class AudioContentService(
|
|||||||
@Value("\${cloud.aws.cloud-front.host}")
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
private val coverImageHost: String
|
private val coverImageHost: String
|
||||||
) {
|
) {
|
||||||
|
private val log = LoggerFactory.getLogger(javaClass)
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
fun audioContentLike(request: PutAudioContentLikeRequest, member: Member): PutAudioContentLikeResponse {
|
fun audioContentLike(request: PutAudioContentLikeRequest, member: Member): PutAudioContentLikeResponse {
|
||||||
var audioContentLike = audioContentLikeRepository.findByMemberIdAndContentId(
|
var audioContentLike = audioContentLikeRepository.findByMemberIdAndContentId(
|
||||||
@@ -820,6 +823,14 @@ class AudioContentService(
|
|||||||
memberId = member.id!!,
|
memberId = member.id!!,
|
||||||
contentId = audioContent.id!!
|
contentId = audioContent.id!!
|
||||||
)
|
)
|
||||||
|
}.onFailure { ex ->
|
||||||
|
log.warn(
|
||||||
|
"event=creator_content_view_history_record_failure memberId={} contentId={} error={}",
|
||||||
|
member.id,
|
||||||
|
audioContent.id,
|
||||||
|
ex.message,
|
||||||
|
ex
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetAudioContentDetailResponse(
|
return GetAudioContentDetailResponse(
|
||||||
|
|||||||
@@ -29,10 +29,15 @@ import org.junit.jupiter.api.Assertions.assertTrue
|
|||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import org.mockito.Mockito
|
import org.mockito.Mockito
|
||||||
|
import org.springframework.boot.test.system.CapturedOutput
|
||||||
|
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||||
import org.springframework.context.ApplicationEventPublisher
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
|
import java.time.LocalDateTime
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
|
@ExtendWith(OutputCaptureExtension::class)
|
||||||
class AudioContentServiceTest {
|
class AudioContentServiceTest {
|
||||||
private lateinit var repository: AudioContentRepository
|
private lateinit var repository: AudioContentRepository
|
||||||
private lateinit var explorerQueryRepository: ExplorerQueryRepository
|
private lateinit var explorerQueryRepository: ExplorerQueryRepository
|
||||||
@@ -240,6 +245,34 @@ class AudioContentServiceTest {
|
|||||||
assertEquals(audioContent.id!!, recordViewInvocation.arguments[1])
|
assertEquals(audioContent.id!!, recordViewInvocation.arguments[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("콘텐츠 조회 이력 기록 실패는 상세 응답을 실패시키지 않고 로그로 남긴다")
|
||||||
|
fun shouldLogViewHistoryFailureWithoutFailingDetail(output: CapturedOutput) {
|
||||||
|
val viewer = createMember(id = 1003L, nickname = "history-failure-viewer")
|
||||||
|
val creator = createMember(id = 2003L, nickname = "history-failure-creator")
|
||||||
|
val audioContent = createAudioContent(creator)
|
||||||
|
stubSuccessfulDetailDependencies(viewer, creator, audioContent)
|
||||||
|
Mockito.doThrow(IllegalStateException("history failed"))
|
||||||
|
.`when`(creatorContentViewHistoryService)
|
||||||
|
.recordView(
|
||||||
|
memberId = Mockito.eq(viewer.id!!),
|
||||||
|
contentId = Mockito.eq(audioContent.id!!),
|
||||||
|
viewedAt = anyLocalDateTime()
|
||||||
|
)
|
||||||
|
|
||||||
|
val response = service.getDetail(
|
||||||
|
id = audioContent.id!!,
|
||||||
|
member = viewer,
|
||||||
|
isAdultContentVisible = false,
|
||||||
|
timezone = "Asia/Seoul"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(audioContent.id!!, response.contentId)
|
||||||
|
assertTrue(output.out.contains("event=creator_content_view_history_record_failure"))
|
||||||
|
assertTrue(output.out.contains("memberId=${viewer.id}"))
|
||||||
|
assertTrue(output.out.contains("contentId=${audioContent.id}"))
|
||||||
|
}
|
||||||
|
|
||||||
private fun createMember(id: Long, nickname: String): Member {
|
private fun createMember(id: Long, nickname: String): Member {
|
||||||
val member = Member(
|
val member = Member(
|
||||||
email = "$nickname@test.com",
|
email = "$nickname@test.com",
|
||||||
@@ -277,4 +310,64 @@ class AudioContentServiceTest {
|
|||||||
|
|
||||||
return audioContent
|
return audioContent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
Mockito.`when`(
|
||||||
|
orderRepository.isExistOrderedAndOrderType(
|
||||||
|
memberId = viewer.id!!,
|
||||||
|
contentId = audioContent.id!!
|
||||||
|
)
|
||||||
|
).thenReturn(Pair(true, OrderType.KEEP))
|
||||||
|
Mockito.`when`(explorerQueryRepository.getCreatorFollowing(creator.id!!, viewer.id!!)).thenReturn(null)
|
||||||
|
Mockito.`when`(
|
||||||
|
limitedEditionOrderRepository.getOrderSequence(
|
||||||
|
contentId = audioContent.id!!,
|
||||||
|
memberId = viewer.id!!
|
||||||
|
)
|
||||||
|
).thenReturn(null)
|
||||||
|
Mockito.`when`(
|
||||||
|
audioContentCloudFront.generateSignedURL(
|
||||||
|
resourcePath = audioContent.content!!,
|
||||||
|
expirationTime = 7_200_000L
|
||||||
|
)
|
||||||
|
).thenReturn("https://signed.test/audio")
|
||||||
|
Mockito.`when`(
|
||||||
|
repository.getCreatorOtherContentList(
|
||||||
|
cloudfrontHost = "https://cdn.test",
|
||||||
|
contentId = audioContent.id!!,
|
||||||
|
creatorId = creator.id!!,
|
||||||
|
isAdult = false
|
||||||
|
)
|
||||||
|
).thenReturn(emptyList())
|
||||||
|
Mockito.`when`(
|
||||||
|
repository.getSameThemeOtherContentList(
|
||||||
|
cloudfrontHost = "https://cdn.test",
|
||||||
|
contentId = audioContent.id!!,
|
||||||
|
themeId = audioContent.theme!!.id!!,
|
||||||
|
isAdult = false
|
||||||
|
)
|
||||||
|
).thenReturn(emptyList())
|
||||||
|
Mockito.`when`(audioContentLikeRepository.totalCountAudioContentLike(audioContent.id!!)).thenReturn(0)
|
||||||
|
Mockito.`when`(audioContentLikeRepository.findByMemberIdAndContentId(viewer.id!!, audioContent.id!!)).thenReturn(null)
|
||||||
|
Mockito.`when`(
|
||||||
|
pinContentRepository.findByContentIdAndMemberId(
|
||||||
|
contentId = audioContent.id!!,
|
||||||
|
memberId = viewer.id!!,
|
||||||
|
active = true
|
||||||
|
)
|
||||||
|
).thenReturn(null)
|
||||||
|
Mockito.`when`(pinContentRepository.getPinContentList(memberId = viewer.id!!, active = true)).thenReturn(emptyList())
|
||||||
|
Mockito.`when`(
|
||||||
|
contentThemeTranslationRepository.findByContentThemeIdAndLocale(
|
||||||
|
contentThemeId = audioContent.theme!!.id!!,
|
||||||
|
locale = "ko"
|
||||||
|
)
|
||||||
|
).thenReturn(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun anyLocalDateTime(): LocalDateTime {
|
||||||
|
return Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.MIN
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user