test #426
@@ -0,0 +1,32 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.scheduler
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.v2.audio.recommendation.application.AudioRecommendationSnapshotRefreshService
|
||||||
|
import org.redisson.api.RedissonClient
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class AudioRecommendationSnapshotScheduler(
|
||||||
|
private val refreshService: AudioRecommendationSnapshotRefreshService,
|
||||||
|
private val redissonClient: RedissonClient
|
||||||
|
) {
|
||||||
|
@Scheduled(cron = "0 0 0 * * *", zone = "Asia/Seoul")
|
||||||
|
fun refreshDailySnapshots() {
|
||||||
|
val lock = redissonClient.getLock(LOCK_KEY)
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (lock.tryLock(0, -1, TimeUnit.SECONDS)) {
|
||||||
|
refreshService.refreshDailySnapshots()
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (lock.isHeldByCurrentThread) {
|
||||||
|
lock.unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LOCK_KEY = "lock:audio-recommendation-snapshot-refresh"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.audio.recommendation.adapter.out.scheduler
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.v2.audio.recommendation.application.AudioRecommendationSnapshotRefreshService
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.DisplayName
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.redisson.api.RLock
|
||||||
|
import org.redisson.api.RedissonClient
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class AudioRecommendationSnapshotSchedulerTest {
|
||||||
|
private val refreshService = Mockito.mock(AudioRecommendationSnapshotRefreshService::class.java)
|
||||||
|
private val redissonClient = Mockito.mock(RedissonClient::class.java)
|
||||||
|
private val lock = Mockito.mock(RLock::class.java)
|
||||||
|
private val scheduler = AudioRecommendationSnapshotScheduler(refreshService, redissonClient)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("스케줄러는 매일 00:00 KST cron을 사용한다")
|
||||||
|
fun shouldUseMidnightKstCron() {
|
||||||
|
val annotation = AudioRecommendationSnapshotScheduler::class.java
|
||||||
|
.getDeclaredMethod("refreshDailySnapshots")
|
||||||
|
.getAnnotation(Scheduled::class.java)
|
||||||
|
|
||||||
|
assertEquals("0 0 0 * * *", annotation.cron)
|
||||||
|
assertEquals("Asia/Seoul", annotation.zone)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("락 획득 성공 시에만 refresh를 호출하고 보유 중이면 unlock한다")
|
||||||
|
fun shouldRefreshOnlyWhenLockAcquired() {
|
||||||
|
Mockito.doReturn(lock).`when`(redissonClient).getLock(AudioRecommendationSnapshotScheduler.LOCK_KEY)
|
||||||
|
Mockito.doReturn(true).`when`(lock).tryLock(0, -1, TimeUnit.SECONDS)
|
||||||
|
Mockito.doReturn(true).`when`(lock).isHeldByCurrentThread
|
||||||
|
|
||||||
|
scheduler.refreshDailySnapshots()
|
||||||
|
|
||||||
|
Mockito.verify(refreshService).refreshDailySnapshots()
|
||||||
|
Mockito.verify(lock).unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("락 획득 실패 시 refresh와 unlock을 호출하지 않는다")
|
||||||
|
fun shouldSkipWhenLockNotAcquired() {
|
||||||
|
Mockito.doReturn(lock).`when`(redissonClient).getLock(AudioRecommendationSnapshotScheduler.LOCK_KEY)
|
||||||
|
Mockito.doReturn(false).`when`(lock).tryLock(0, -1, TimeUnit.SECONDS)
|
||||||
|
Mockito.doReturn(false).`when`(lock).isHeldByCurrentThread
|
||||||
|
|
||||||
|
scheduler.refreshDailySnapshots()
|
||||||
|
|
||||||
|
Mockito.verify(refreshService, Mockito.never()).refreshDailySnapshots()
|
||||||
|
Mockito.verify(lock, Mockito.never()).unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user