feat(home): 홈 추천 조회 로그와 회원 컨텍스트를 전달한다
This commit is contained in:
@@ -5,17 +5,26 @@ import kr.co.vividnext.sodalive.member.Member
|
||||
import kr.co.vividnext.sodalive.member.MemberAdapter
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreference
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
import kr.co.vividnext.sodalive.member.following.CreatorFollowing
|
||||
import kr.co.vividnext.sodalive.member.following.CreatorFollowingRepository
|
||||
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
|
||||
import kr.co.vividnext.sodalive.v2.api.home.application.HomeRecommendationFacade
|
||||
import kr.co.vividnext.sodalive.v2.recommend.application.HomeRecommendationQueryService
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
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.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.system.CapturedOutput
|
||||
import org.springframework.boot.test.system.OutputCaptureExtension
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
@@ -32,6 +41,7 @@ import javax.persistence.EntityManager
|
||||
@AutoConfigureMockMvc
|
||||
@Transactional
|
||||
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
|
||||
@ExtendWith(OutputCaptureExtension::class)
|
||||
class HomeRecommendationControllerTest @Autowired constructor(
|
||||
private val mockMvc: MockMvc,
|
||||
private val memberRepository: MemberRepository,
|
||||
@@ -197,7 +207,7 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
|
||||
@Test
|
||||
@DisplayName("메인 홈 통합 조회는 비회원도 호출 가능하고 섹션별 빈 배열을 포함해 성공 응답한다")
|
||||
fun shouldReturnHomeRecommendationsForAnonymous() {
|
||||
fun shouldReturnHomeRecommendationsForAnonymous(output: CapturedOutput) {
|
||||
mockMvc.perform(get("/api/v2/home/recommendations"))
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.success").value(true))
|
||||
@@ -210,6 +220,9 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.genreCreators").isArray)
|
||||
.andExpect(jsonPath("$.data.cheerCreators").isArray)
|
||||
.andExpect(jsonPath("$.data.popularCommunities").isArray)
|
||||
|
||||
assertTrue(output.out.contains("event=home_recommendations_query_success"))
|
||||
assertTrue(output.out.contains("emptySections="))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -227,9 +240,27 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.lives").isArray)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("메인 홈 통합 조회 실패는 응답 시간과 함께 로그로 관측된다")
|
||||
fun shouldLogHomeRecommendationFailure(output: CapturedOutput) {
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
Mockito.`when`(failingQueryService.findLiveRecommendations(limit = 20, memberId = null, includeAdultLives = false))
|
||||
.thenThrow(IllegalStateException("home query failed"))
|
||||
|
||||
val exception = assertThrows(IllegalStateException::class.java) {
|
||||
facade.getHomeRecommendations(member = null)
|
||||
}
|
||||
|
||||
assertEquals("home query failed", exception.message)
|
||||
assertTrue(output.out.contains("event=home_recommendations_query_failure"))
|
||||
assertTrue(output.out.contains("memberId=null"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("라이브 전체보기는 page/size를 포함한 페이징 응답 형식으로 반환한다")
|
||||
fun shouldReturnPagedLives() {
|
||||
fun shouldReturnPagedLives(output: CapturedOutput) {
|
||||
val member = saveMember("paged-live-viewer", MemberRole.USER)
|
||||
entityManager.flush()
|
||||
entityManager.clear()
|
||||
@@ -241,6 +272,74 @@ class HomeRecommendationControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.page").value(0))
|
||||
.andExpect(jsonPath("$.data.size").value(20))
|
||||
.andExpect(jsonPath("$.data.hasNext").value(false))
|
||||
|
||||
assertTrue(output.out.contains("event=home_recommendations_page_query_success"))
|
||||
assertTrue(output.out.contains("section=LIVE"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("세부 전체보기 조회 실패는 섹션과 응답 시간과 함께 로그로 관측된다")
|
||||
fun shouldLogHomeRecommendationPageFailure(output: CapturedOutput) {
|
||||
val member = saveMember("page-failure-viewer", MemberRole.USER)
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
Mockito.`when`(preferenceService.initializeDefaultPreference(member)).thenReturn(MemberContentPreference())
|
||||
Mockito.`when`(
|
||||
failingQueryService.findLiveRecommendations(
|
||||
offset = 0,
|
||||
limit = 21,
|
||||
memberId = member.id,
|
||||
includeAdultLives = false
|
||||
)
|
||||
)
|
||||
.thenThrow(IllegalStateException("page query failed"))
|
||||
|
||||
val exception = assertThrows(IllegalStateException::class.java) {
|
||||
facade.getLives(member, page = 0, size = 20)
|
||||
}
|
||||
|
||||
assertEquals("page query failed", exception.message)
|
||||
assertTrue(output.out.contains("event=home_recommendations_page_query_failure"))
|
||||
assertTrue(output.out.contains("section=LIVE"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("나머지 세부 전체보기 조회 실패도 섹션과 응답 시간과 함께 로그로 관측된다")
|
||||
fun shouldLogOtherHomeRecommendationPageFailures(output: CapturedOutput) {
|
||||
val member = saveMember("other-page-failure-viewer", MemberRole.USER)
|
||||
val failingQueryService = Mockito.mock(HomeRecommendationQueryService::class.java)
|
||||
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
val facade = HomeRecommendationFacade(failingQueryService, preferenceService, "https://cdn.test")
|
||||
Mockito.`when`(preferenceService.initializeDefaultPreference(member)).thenReturn(MemberContentPreference())
|
||||
Mockito.`when`(
|
||||
failingQueryService.findRecentDebutCreators(
|
||||
now = Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.MIN,
|
||||
offset = Mockito.eq(0),
|
||||
limit = Mockito.eq(21),
|
||||
memberId = Mockito.eq(member.id),
|
||||
includeAdultContents = Mockito.eq(false)
|
||||
)
|
||||
).thenThrow(IllegalStateException("debut page failed"))
|
||||
Mockito.`when`(
|
||||
failingQueryService.findFirstAudioContents(
|
||||
now = Mockito.any(LocalDateTime::class.java) ?: LocalDateTime.MIN,
|
||||
offset = Mockito.eq(0),
|
||||
limit = Mockito.eq(21),
|
||||
memberId = Mockito.eq(member.id),
|
||||
includeAdultContents = Mockito.eq(false)
|
||||
)
|
||||
).thenThrow(IllegalStateException("first audio page failed"))
|
||||
Mockito.`when`(failingQueryService.findAiCharacterRecommendations(offset = 0, limit = 21))
|
||||
.thenThrow(IllegalStateException("ai page failed"))
|
||||
|
||||
assertThrows(IllegalStateException::class.java) { facade.getRecentDebutCreators(member, page = 0, size = 20) }
|
||||
assertThrows(IllegalStateException::class.java) { facade.getFirstAudioContents(member, page = 0, size = 20) }
|
||||
assertThrows(IllegalStateException::class.java) { facade.getAiCharacters(member, page = 0, size = 20) }
|
||||
|
||||
assertTrue(output.out.contains("section=DEBUT_CREATOR"))
|
||||
assertTrue(output.out.contains("section=FIRST_AUDIO_CONTENT"))
|
||||
assertTrue(output.out.contains("section=AI_CHARACTER"))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user