feat(notice): 예약 관리와 공개 시점 기반 조회를 구현한다

This commit is contained in:
2026-10-30 22:50:58 +09:00
parent 4f4c842ccf
commit 394949ab6e
16 changed files with 1544 additions and 69 deletions
@@ -0,0 +1,104 @@
package kr.co.vividnext.sodalive.content.main.tab.home
import com.fasterxml.jackson.databind.ObjectMapper
import kr.co.vividnext.sodalive.content.ContentType
import kr.co.vividnext.sodalive.notice.NoticeItem
import kr.co.vividnext.sodalive.notice.ServiceNotice
import kr.co.vividnext.sodalive.notice.ServiceServiceNoticeRepository
import kr.co.vividnext.sodalive.support.EmbeddedRedisInitializer
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
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.boot.test.context.TestConfiguration
import org.springframework.boot.test.web.client.TestRestTemplate
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Import
import org.springframework.http.HttpStatus
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
import org.springframework.web.context.request.RequestContextHolder
import org.springframework.web.context.request.ServletRequestAttributes
import java.sql.Timestamp
import java.time.LocalDateTime
@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = [
"spring.datasource.url=jdbc:h2:mem:notice-home-integration;" +
"MODE=MySQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=VALUE;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
]
)
@Import(AudioContentMainTabHomeServiceIntegrationTest.TimeConfiguration::class)
@ContextConfiguration(initializers = [EmbeddedRedisInitializer::class])
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
class AudioContentMainTabHomeServiceIntegrationTest @Autowired constructor(
private val service: AudioContentMainTabHomeService,
private val repository: ServiceServiceNoticeRepository,
private val jdbcTemplate: JdbcTemplate,
private val restTemplate: TestRestTemplate,
private val objectMapper: ObjectMapper
) {
@BeforeEach
fun setUp() {
repository.deleteAllInBatch()
jdbcTemplate.execute("ALTER TABLE service_notice ALTER COLUMN publish_at TIMESTAMP(0)")
jdbcTemplate.execute(
"CREATE ALIAS IF NOT EXISTS DATE_FORMAT FOR 'kr.co.vividnext.sodalive.support.H2MysqlDateFunctions.dateFormat'"
)
jdbcTemplate.execute(
"CREATE ALIAS IF NOT EXISTS CONVERT_TZ FOR 'kr.co.vividnext.sodalive.support.H2MysqlDateFunctions.convertTz'"
)
}
@AfterEach
fun cleanUp() {
repository.deleteAllInBatch()
}
@Test
@DisplayName("실제 홈 조립과 HTTP latestNotice는 미공개 예약을 제외한 최신 공개 공지다")
fun shouldDelegateHomeLatestNoticeToRealFilteredLookup() {
val id = requireNotNull(repository.saveAndFlush(ServiceNotice("공개 공지", "홈 전체 본문")).id)
jdbcTemplate.update(
"UPDATE service_notice SET created_at = ? WHERE id = ?",
Timestamp.valueOf("2026-10-29 15:00:00"),
id
)
repository.saveAndFlush(
ServiceNotice("미공개", "노출 금지", publishAt = LocalDateTime.of(2026, 11, 1, 0, 0, 0), isScheduled = true)
)
repository.saveAndFlush(ServiceNotice("비활성", "노출 금지", isActive = false))
RequestContextHolder.setRequestAttributes(ServletRequestAttributes(MockHttpServletRequest()))
try {
val result = service.fetchData(false, ContentType.ALL, null)
assertEquals(NoticeItem(id, "공개 공지", "홈 전체 본문", "2026-10-30"), result.latestNotice)
} finally {
RequestContextHolder.resetRequestAttributes()
}
val response = restTemplate.getForEntity("/v2/audio-content/main/home", String::class.java)
println("HTTP GET /v2/audio-content/main/home -> ${response.statusCodeValue} ${response.body}")
assertEquals(HttpStatus.OK, response.statusCode)
val body = objectMapper.readTree(response.body)
assertEquals(true, body["success"].asBoolean())
assertEquals(
objectMapper.readTree(
"""{"id":$id,"title":"공개 공지","content":"홈 전체 본문","date":"2026-10-30"}"""
),
body["data"]["latestNotice"]
)
}
@TestConfiguration
class TimeConfiguration {
@Bean
fun noticeNowProvider(): () -> LocalDateTime = { LocalDateTime.of(2026, 10, 30, 0, 0, 0) }
}
}