package com.zy.core.utils; import com.zy.asrs.entity.BasDevp; import com.zy.asrs.entity.WrkMast; import com.zy.core.enums.WrkIoType; import com.zy.core.move.StationMoveCoordinator; import com.zy.core.move.StationMoveSession; import com.zy.core.model.command.StationCommand; import com.zy.core.model.protocol.StationProtocol; import com.zy.core.model.protocol.StationTaskBufferItem; import com.zy.core.thread.StationThread; import com.zy.common.utils.RedisUtil; import org.junit.jupiter.api.Test; import org.springframework.test.util.ReflectionTestUtils; import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class StationOperateProcessUtilsReroutePipelineTest { @Test void choosesRunBlockCommandBuilderForRunBlockRerouteScene() { StationOperateProcessUtils.RerouteSceneType scene = StationOperateProcessUtils.RerouteSceneType.RUN_BLOCK_REROUTE; assertSame(StationOperateProcessUtils.RerouteSceneType.RUN_BLOCK_REROUTE, scene); } @Test void resolveExecutionTarget_skipsWhenTargetEqualsCurrentStation() { StationOperateProcessUtils.RerouteDecision decision = StationOperateProcessUtils.RerouteDecision.skip("same-station"); assertTrue(decision.skip()); assertEquals("same-station", decision.skipReason()); } @Test void buildCommandPlan_usesRunBlockCommandBuilderForRunBlockScene() { StationOperateProcessUtils utils = new StationOperateProcessUtils(); StationThread stationThread = mock(StationThread.class); StationCommand command = new StationCommand(); command.setTaskNo(100); command.setStationId(10); command.setTargetStaNo(20); when(stationThread.getRunBlockRerouteCommand(100, 10, 20, 0, 0.25d)).thenReturn(command); StationOperateProcessUtils.RerouteContext context = StationOperateProcessUtils.RerouteContext.create( StationOperateProcessUtils.RerouteSceneType.RUN_BLOCK_REROUTE, buildBasDevp(1), stationThread, buildStationProtocol(10, 100, 10), buildWrkMast(100, 99), Collections.emptyList(), 0.25d, "checkStationRunBlock_reroute" ).withRunBlockCommand() .withCancelSessionBeforeDispatch() .withResetSegmentCommandsBeforeDispatch(); StationOperateProcessUtils.RerouteCommandPlan plan = utils.buildRerouteCommandPlan( context, StationOperateProcessUtils.RerouteDecision.proceed(20) ); verify(stationThread).getRunBlockRerouteCommand(100, 10, 20, 0, 0.25d); assertSame(command, plan.command()); } @Test void executePlan_skipsWhenCurrentTaskStillExistsInBuffer() { StationOperateProcessUtils utils = new StationOperateProcessUtils(); StationCommand command = new StationCommand(); command.setTaskNo(100); command.setStationId(10); command.setTargetStaNo(20); StationTaskBufferItem bufferItem = new StationTaskBufferItem(); bufferItem.setTaskNo(100); StationOperateProcessUtils.RerouteContext context = StationOperateProcessUtils.RerouteContext.create( StationOperateProcessUtils.RerouteSceneType.OUT_ORDER, buildBasDevp(1), mock(StationThread.class), buildStationProtocol(10, 100, 10, Collections.singletonList(bufferItem)), buildWrkMast(100, 20), List.of(10, 20), 0.0d, "checkStationOutOrder" ); StationOperateProcessUtils.RerouteExecutionResult result = utils.executeReroutePlan( context, StationOperateProcessUtils.RerouteCommandPlan.dispatch( command, StationOperateProcessUtils.RerouteDecision.proceed(20), "checkStationOutOrder" ) ); assertTrue(result.skipped()); assertEquals("buffer-has-current-task", result.skipReason()); } @Test void outOrderAndWatchCircle_shareDecisionFlow() { StationOperateProcessUtils utils = new StationOperateProcessUtils(); WrkMast wrkMast = buildWrkMast(100, 20); StationOperateProcessUtils.RerouteContext outOrderContext = StationOperateProcessUtils.RerouteContext.create( StationOperateProcessUtils.RerouteSceneType.OUT_ORDER, buildBasDevp(1), mock(StationThread.class), buildStationProtocol(10, 100, 10), wrkMast, Collections.emptyList(), 0.0d, "checkStationOutOrder" ); StationOperateProcessUtils.RerouteContext watchCircleContext = StationOperateProcessUtils.RerouteContext.create( StationOperateProcessUtils.RerouteSceneType.WATCH_CIRCLE, buildBasDevp(1), mock(StationThread.class), buildStationProtocol(10, 100, 10), wrkMast, Collections.emptyList(), 0.0d, "watchCircleStation" ); StationOperateProcessUtils.RerouteDecision outOrderDecision = utils.resolveSharedRerouteDecision(outOrderContext); StationOperateProcessUtils.RerouteDecision watchCircleDecision = utils.resolveSharedRerouteDecision(watchCircleContext); assertEquals(20, outOrderDecision.targetStationId()); assertEquals(20, watchCircleDecision.targetStationId()); } @Test void runBlockReroute_keepsDirectReassignAndNormalRerouteSeparate() { StationOperateProcessUtils utils = new StationOperateProcessUtils(); WrkMast inboundWrkMast = buildWrkMast(100, 20); inboundWrkMast.setIoType(WrkIoType.IN.id); assertTrue(utils.shouldUseRunBlockDirectReassign(inboundWrkMast, 10, List.of(10))); assertTrue(!utils.shouldUseRunBlockDirectReassign(inboundWrkMast, 11, List.of(10))); } @Test void idleRecover_skipsWhenLastDispatchIsTooRecent() { StationOperateProcessUtils utils = new StationOperateProcessUtils(); StationMoveCoordinator coordinator = mock(StationMoveCoordinator.class); RedisUtil redisUtil = mock(RedisUtil.class); ReflectionTestUtils.setField(utils, "stationMoveCoordinator", coordinator); ReflectionTestUtils.setField(utils, "redisUtil", redisUtil); StationMoveSession session = new StationMoveSession(); session.setStatus(StationMoveSession.STATUS_RUNNING); session.setCurrentStationId(10); session.setDispatchStationId(10); session.setLastIssuedAt(System.currentTimeMillis()); when(coordinator.loadSession(100)).thenReturn(session); StationCommand command = new StationCommand(); command.setTaskNo(100); command.setStationId(10); command.setTargetStaNo(20); StationOperateProcessUtils.RerouteContext context = StationOperateProcessUtils.RerouteContext.create( StationOperateProcessUtils.RerouteSceneType.IDLE_RECOVER, buildBasDevp(1), mock(StationThread.class), buildStationProtocol(10, 100, 10), buildWrkMast(100, 20), Collections.emptyList(), 0.0d, "checkStationIdleRecover" ).withRecentDispatchGuard(); StationOperateProcessUtils.RerouteExecutionResult result = utils.executeReroutePlan( context, StationOperateProcessUtils.RerouteCommandPlan.dispatch( command, StationOperateProcessUtils.RerouteDecision.proceed(20), "checkStationIdleRecover" ) ); assertTrue(result.skipped()); assertEquals("recent-dispatch", result.skipReason()); verify(coordinator, never()).cancelSession(100); } private static BasDevp buildBasDevp(int devpNo) { BasDevp basDevp = new BasDevp(); basDevp.setDevpNo(devpNo); return basDevp; } private static WrkMast buildWrkMast(int wrkNo, int targetStationId) { WrkMast wrkMast = new WrkMast(); wrkMast.setWrkNo(wrkNo); wrkMast.setStaNo(targetStationId); return wrkMast; } private static StationProtocol buildStationProtocol(int stationId, int taskNo, int targetStationId) { return buildStationProtocol(stationId, taskNo, targetStationId, Collections.emptyList()); } private static StationProtocol buildStationProtocol(int stationId, int taskNo, int targetStationId, List taskBufferItems) { StationProtocol stationProtocol = new StationProtocol(); stationProtocol.setStationId(stationId); stationProtocol.setTaskNo(taskNo); stationProtocol.setTargetStaNo(targetStationId); stationProtocol.setTaskBufferItems(taskBufferItems); return stationProtocol; } }