test #426

Merged
klaus merged 415 commits from test into main 2026-06-27 00:35:30 +00:00
2 changed files with 176 additions and 0 deletions
Showing only changes of commit f5d755b2a6 - Show all commits

View File

@@ -0,0 +1,39 @@
package kr.co.vividnext.sodalive.v2.home.following.application
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
import kr.co.vividnext.sodalive.v2.home.following.domain.HomeFollowing
import kr.co.vividnext.sodalive.v2.home.following.port.out.HomeFollowingQueryPort
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.Clock
import java.time.LocalDateTime
@Service
@Transactional(readOnly = true)
class HomeFollowingQueryService(
private val queryPort: HomeFollowingQueryPort,
private val memberContentPreferenceService: MemberContentPreferenceService,
private val nowProvider: () -> LocalDateTime = { LocalDateTime.now(Clock.systemUTC()) }
) {
fun findHomeFollowing(member: Member): HomeFollowing {
val memberId = requireNotNull(member.id)
val canViewAdultContent = memberContentPreferenceService.canViewAdultContent(member)
val now = nowProvider()
return HomeFollowing(
followingCreators = queryPort.findFollowingCreators(memberId, FOLLOWING_CREATORS_LIMIT),
onAirLives = queryPort.findOnAirLives(memberId, canViewAdultContent, ON_AIR_LIVES_LIMIT),
recentChats = emptyList(),
monthlySchedules = queryPort.findMonthlySchedules(memberId, canViewAdultContent, now, MONTHLY_SCHEDULES_LIMIT),
recentNews = queryPort.findRecentNews(memberId, canViewAdultContent, now, RECENT_NEWS_LIMIT)
)
}
companion object {
private const val FOLLOWING_CREATORS_LIMIT = 20
private const val ON_AIR_LIVES_LIMIT = 10
private const val MONTHLY_SCHEDULES_LIMIT = 3
private const val RECENT_NEWS_LIMIT = 30
}
}

View File

@@ -0,0 +1,137 @@
package kr.co.vividnext.sodalive.v2.home.following.application
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
import kr.co.vividnext.sodalive.v2.home.following.domain.HomeFollowingCreator
import kr.co.vividnext.sodalive.v2.home.following.domain.HomeFollowingLive
import kr.co.vividnext.sodalive.v2.home.following.domain.HomeFollowingNews
import kr.co.vividnext.sodalive.v2.home.following.domain.HomeFollowingSchedule
import kr.co.vividnext.sodalive.v2.home.following.port.out.HomeFollowingQueryPort
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.TimeZone
class HomeFollowingQueryServiceTest {
private val queryPort = RecordingHomeFollowingQueryPort()
private val memberContentPreferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
private val now = LocalDateTime.of(2026, 6, 25, 12, 0)
private val service = HomeFollowingQueryService(
queryPort,
memberContentPreferenceService
) { now }
@Test
@DisplayName("팔로잉 탭 조회는 각 섹션의 기본 limit와 고정 now를 port에 전달한다")
fun shouldCallQueryPortWithDefaultLimitsAndNow() {
val member = member(10L)
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(true)
val home = service.findHomeFollowing(member)
assertEquals(listOf(HomeFollowingCreator(1L, "creator", "profile")), home.followingCreators)
assertEquals(emptyList<Any>(), home.recentChats)
assertEquals(20, queryPort.followingCreatorsLimit)
assertEquals(10, queryPort.onAirLivesLimit)
assertEquals(3, queryPort.monthlySchedulesLimit)
assertEquals(30, queryPort.recentNewsLimit)
assertEquals(now, queryPort.monthlySchedulesNow)
assertEquals(now, queryPort.recentNewsNow)
}
@Test
@DisplayName("성인 콘텐츠 노출 가능 여부는 On Air, 스케줄, 최근 소식 조회에 전달된다")
fun shouldPassAdultContentVisibilityToQueryPort() {
val member = member(11L)
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(false)
service.findHomeFollowing(member)
assertEquals(false, queryPort.onAirCanViewAdultContent)
assertEquals(false, queryPort.monthlySchedulesCanViewAdultContent)
assertEquals(false, queryPort.recentNewsCanViewAdultContent)
assertEquals(11L, queryPort.memberId)
}
@Test
@DisplayName("기본 now는 JVM 기본 timezone과 무관하게 UTC 기준으로 port에 전달된다")
fun shouldUseUtcNowRegardlessOfJvmDefaultTimezone() {
val originalTimeZone = TimeZone.getDefault()
try {
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul"))
val defaultQueryPort = RecordingHomeFollowingQueryPort()
val defaultService = HomeFollowingQueryService(defaultQueryPort, memberContentPreferenceService)
val member = member(12L)
Mockito.`when`(memberContentPreferenceService.canViewAdultContent(member)).thenReturn(true)
val beforeUtc = LocalDateTime.now(ZoneOffset.UTC).minusSeconds(1)
defaultService.findHomeFollowing(member)
val afterUtc = LocalDateTime.now(ZoneOffset.UTC).plusSeconds(1)
val capturedNow = defaultQueryPort.recentNewsNow!!
assertFalse(capturedNow.isBefore(beforeUtc))
assertFalse(capturedNow.isAfter(afterUtc))
assertTrue(LocalDateTime.now().isAfter(capturedNow.plusHours(8)))
} finally {
TimeZone.setDefault(originalTimeZone)
}
}
private fun member(id: Long): Member {
return Member(email = "member-$id@test.com", password = "password", nickname = "member-$id").apply { this.id = id }
}
private class RecordingHomeFollowingQueryPort : HomeFollowingQueryPort {
var memberId: Long? = null
var followingCreatorsLimit: Int? = null
var onAirLivesLimit: Int? = null
var onAirCanViewAdultContent: Boolean? = null
var monthlySchedulesLimit: Int? = null
var monthlySchedulesNow: LocalDateTime? = null
var monthlySchedulesCanViewAdultContent: Boolean? = null
var recentNewsLimit: Int? = null
var recentNewsNow: LocalDateTime? = null
var recentNewsCanViewAdultContent: Boolean? = null
override fun findFollowingCreators(memberId: Long, limit: Int): List<HomeFollowingCreator> {
this.memberId = memberId
followingCreatorsLimit = limit
return listOf(HomeFollowingCreator(1L, "creator", "profile"))
}
override fun findOnAirLives(memberId: Long, canViewAdultContent: Boolean, limit: Int): List<HomeFollowingLive> {
onAirCanViewAdultContent = canViewAdultContent
onAirLivesLimit = limit
return emptyList()
}
override fun findMonthlySchedules(
memberId: Long,
canViewAdultContent: Boolean,
now: LocalDateTime,
limit: Int
): List<HomeFollowingSchedule> {
monthlySchedulesCanViewAdultContent = canViewAdultContent
monthlySchedulesNow = now
monthlySchedulesLimit = limit
return emptyList()
}
override fun findRecentNews(
memberId: Long,
canViewAdultContent: Boolean,
nowUtc: LocalDateTime,
limit: Int
): List<HomeFollowingNews> {
recentNewsCanViewAdultContent = canViewAdultContent
recentNewsNow = nowUtc
recentNewsLimit = limit
return emptyList()
}
}
}