diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt index 39cdf2a0..bb6d442c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt @@ -82,6 +82,7 @@ class AdminLiveService( ) } + @Transactional(readOnly = true) fun getRecommendCreator(pageable: Pageable): GetAdminRecommendCreatorResponse { val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveControllerIntegrationTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveControllerIntegrationTest.kt new file mode 100644 index 00000000..1542129c --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveControllerIntegrationTest.kt @@ -0,0 +1,86 @@ +package kr.co.vividnext.sodalive.admin.live + +import kr.co.vividnext.sodalive.i18n.Lang +import kr.co.vividnext.sodalive.live.recommend.RecommendLiveCreatorBanner +import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.member.MemberRole +import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.transaction.support.TransactionTemplate +import java.time.LocalDateTime +import javax.persistence.EntityManager + +@SpringBootTest( + properties = [ + "cloud.aws.cloud-front.host=https://cdn.test", + "spring.datasource.url=jdbc:h2:mem:admin-live-controller-integration;" + + "MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" + ] +) +@AutoConfigureMockMvc +@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class]) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +class AdminLiveControllerIntegrationTest @Autowired constructor( + private val mockMvc: MockMvc, + private val entityManager: EntityManager, + private val transactionTemplate: TransactionTemplate +) { + @Test + @DisplayName("관리자 라이브 추천 크리에이터 목록 API는 OSIV off 환경에서 lazy 초기화 예외 없이 응답한다") + fun shouldReturnAdminRecommendCreatorListWhenOpenInViewIsDisabled() { + createBannerFixture() + + mockMvc.perform( + get("/admin/live/recommend-creator") + .param("page", "0") + .param("size", "20") + .with(user("admin").roles("ADMIN")) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.success").value(true)) + .andExpect(jsonPath("$.data.totalCount").value(1)) + .andExpect(jsonPath("$.data.recommendCreatorList[0].creatorNickname").value("admin-live-api-creator")) + .andExpect(jsonPath("$.data.recommendCreatorList[0].image").value("https://cdn.test/recommend/api.png")) + .andExpect(jsonPath("$.data.recommendCreatorList[0].startDate").value("2026-06-29 10:00")) + .andExpect(jsonPath("$.data.recommendCreatorList[0].endDate").value("2026-06-30 10:00")) + .andExpect(jsonPath("$.data.recommendCreatorList[0].isAdult").value(false)) + } + + private fun createBannerFixture() { + transactionTemplate.execute { + val creator = Member( + email = "admin-live-api-creator@test.com", + password = "password", + nickname = "admin-live-api-creator", + profileImage = "profile/default-profile.png", + role = MemberRole.CREATOR + ) + entityManager.persist(creator) + + val banner = RecommendLiveCreatorBanner( + startDate = LocalDateTime.of(2026, 6, 29, 1, 0), + endDate = LocalDateTime.of(2026, 6, 30, 1, 0), + isAdult = false, + lang = Lang.KO, + orders = 1, + image = "recommend/api.png" + ) + banner.creator = creator + entityManager.persist(banner) + + entityManager.flush() + entityManager.clear() + } + } +} diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveServiceIntegrationTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveServiceIntegrationTest.kt new file mode 100644 index 00000000..b2be2834 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveServiceIntegrationTest.kt @@ -0,0 +1,83 @@ +package kr.co.vividnext.sodalive.admin.live + +import kr.co.vividnext.sodalive.i18n.Lang +import kr.co.vividnext.sodalive.live.recommend.RecommendLiveCreatorBanner +import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.member.MemberRole +import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.domain.PageRequest +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.ContextConfiguration +import org.springframework.transaction.support.TransactionTemplate +import java.time.LocalDateTime +import javax.persistence.EntityManager + +@SpringBootTest( + properties = [ + "cloud.aws.cloud-front.host=https://cdn.test", + "spring.datasource.url=jdbc:h2:mem:admin-live-service-integration;" + + "MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE" + ] +) +@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class]) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +class AdminLiveServiceIntegrationTest @Autowired constructor( + private val service: AdminLiveService, + private val entityManager: EntityManager, + private val transactionTemplate: TransactionTemplate +) { + @Test + @DisplayName("관리자 라이브 추천 크리에이터 목록은 OSIV off 환경에서 lazy 초기화 예외 없이 응답한다") + fun shouldReturnRecommendCreatorListWhenOpenInViewIsDisabled() { + val fixture = createBannerFixture() + + val response = service.getRecommendCreator(PageRequest.of(0, 20)) + + val item = response.recommendCreatorList.single() + assertEquals(1, response.totalCount) + assertEquals(fixture.creatorId, item.creatorId) + assertEquals("admin-live-recommend-creator", item.creatorNickname) + assertEquals("https://cdn.test/recommend/live.png", item.image) + assertEquals("2026-06-29 10:00", item.startDate) + assertEquals("2026-06-30 10:00", item.endDate) + assertEquals(false, item.isAdult) + } + + private fun createBannerFixture(): Fixture { + return transactionTemplate.execute { + val creator = Member( + email = "admin-live-recommend-creator@test.com", + password = "password", + nickname = "admin-live-recommend-creator", + profileImage = "profile/default-profile.png", + role = MemberRole.CREATOR + ) + entityManager.persist(creator) + + val banner = RecommendLiveCreatorBanner( + startDate = LocalDateTime.of(2026, 6, 29, 1, 0), + endDate = LocalDateTime.of(2026, 6, 30, 1, 0), + isAdult = false, + lang = Lang.KO, + orders = 1, + image = "recommend/live.png" + ) + banner.creator = creator + entityManager.persist(banner) + + entityManager.flush() + val fixture = Fixture(creatorId = creator.id!!) + entityManager.clear() + fixture + }!! + } + + private data class Fixture( + val creatorId: Long + ) +}