test #426
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user