package com.tcm.training.admin.live.service; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.tcm.training.admin.live.entity.LiveSession; import com.tcm.training.admin.live.mapper.LiveSessionMapper; import com.tcm.training.admin.live.vo.LiveSessionStatusVO; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.time.LocalDateTime; import java.util.Arrays; import java.util.Collections; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * 直播场次自动开播定时任务测试。 */ @ExtendWith(MockitoExtension.class) class LiveSessionStatusSyncServiceTest { @BeforeAll static void initLambdaCache() { MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), ""); TableInfoHelper.initTableInfo(assistant, LiveSession.class); } @Mock private LiveSessionMapper liveSessionMapper; @Mock private LiveSessionAppService liveSessionAppService; private LiveSessionStatusSyncService liveSessionStatusSyncService; /** * 每个用例前重建被测定时任务服务。 */ @BeforeEach void setUp() { liveSessionStatusSyncService = new LiveSessionStatusSyncService(liveSessionMapper, liveSessionAppService); } /** * 已到开播时间的未开始场次应触发自动开播。 */ @Test void syncDueSessionsShouldAutoStartPendingSessions() { LiveSession sessionA = buildSession(10001L, 9000L); LiveSession sessionB = buildSession(10002L, 9000L); when(liveSessionMapper.selectList(any())).thenReturn(Arrays.asList(sessionA, sessionB)); when(liveSessionAppService.autoStart(org.mockito.ArgumentMatchers.eq(10001L), any(LocalDateTime.class))) .thenReturn(new LiveSessionStatusVO(10001L, 1, LocalDateTime.of(2026, 4, 9, 10, 0), null)); when(liveSessionAppService.autoStart(org.mockito.ArgumentMatchers.eq(10002L), any(LocalDateTime.class))) .thenReturn(new LiveSessionStatusVO(10002L, 1, LocalDateTime.of(2026, 4, 9, 10, 0), null)); liveSessionStatusSyncService.syncDueSessions(); verify(liveSessionAppService).autoStart(org.mockito.ArgumentMatchers.eq(10001L), any(LocalDateTime.class)); verify(liveSessionAppService).autoStart(org.mockito.ArgumentMatchers.eq(10002L), any(LocalDateTime.class)); } /** * 没有命中场次时不应触发任何状态迁移。 */ @Test void syncDueSessionsShouldSkipWhenNoPendingSession() { when(liveSessionMapper.selectList(any())).thenReturn(Collections.emptyList()); liveSessionStatusSyncService.syncDueSessions(); verify(liveSessionAppService, never()).autoStart(any(Long.class), any(LocalDateTime.class)); } /** * 即使没有待开播场次,也应定时收敛历史残留的直播中课程状态。 */ @Test void syncDueSessionsShouldReconcileHistoricalLivingCourses() { LiveSession staleLivingSession = new LiveSession(); staleLivingSession.setId(10009L); staleLivingSession.setLiveCourseId(9001L); staleLivingSession.setLiveStatus(1); staleLivingSession.setStartTime(LocalDateTime.of(2026, 4, 8, 10, 0)); when(liveSessionMapper.selectList(any())).thenReturn( Collections.emptyList(), Collections.singletonList(staleLivingSession) ); when(liveSessionAppService.reconcileCourseLivingSessions(org.mockito.ArgumentMatchers.eq(9001L), any(LocalDateTime.class))) .thenReturn(1); liveSessionStatusSyncService.syncDueSessions(); verify(liveSessionAppService).reconcileCourseLivingSessions(org.mockito.ArgumentMatchers.eq(9001L), any(LocalDateTime.class)); } /** * 构造待自动开播的场次样例。 */ private LiveSession buildSession(Long sessionId, Long courseId) { LiveSession session = new LiveSession(); session.setId(sessionId); session.setLiveCourseId(courseId); session.setLiveStatus(0); session.setStartTime(LocalDateTime.of(2026, 4, 9, 10, 0)); session.setDeleted(0); return session; } }