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.utils.generateFileName
|
||||
import kr.co.vividnext.sodalive.v2.recommend.application.CreatorContentViewHistoryService
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Value
|
||||
import org.springframework.cache.annotation.Cacheable
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
@@ -91,6 +92,8 @@ class AudioContentService(
|
||||
@Value("\${cloud.aws.cloud-front.host}")
|
||||
private val coverImageHost: String
|
||||
) {
|
||||
private val log = LoggerFactory.getLogger(javaClass)
|
||||
|
||||
@Transactional
|
||||
fun audioContentLike(request: PutAudioContentLikeRequest, member: Member): PutAudioContentLikeResponse {
|
||||
var audioContentLike = audioContentLikeRepository.findByMemberIdAndContentId(
|
||||
@@ -820,6 +823,14 @@ class AudioContentService(
|
||||
memberId = member.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(
|
||||
|
||||
@@ -29,10 +29,15 @@ import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.ExtendWith
|
||||
import org.mockito.Mockito
|
||||
import org.springframework.boot.test.system.CapturedOutput
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||
import org.springframework.context.ApplicationEventPublisher
|
||||
import java.time.LocalDateTime
|
||||
import java.util.Optional
|
||||
|
||||
@ExtendWith(OutputCaptureExtension::class)
|
||||
class AudioContentServiceTest {
|
||||
private lateinit var repository: AudioContentRepository
|
||||
private lateinit var explorerQueryRepository: ExplorerQueryRepository
|
||||
@@ -240,6 +245,34 @@ class AudioContentServiceTest {
|
||||
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 {
|
||||
val member = Member(
|
||||
email = "$nickname@test.com",
|
||||
@@ -277,4 +310,64 @@ class AudioContentServiceTest {
|
||||
|
||||
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