| | |
| | | package com.zy.ai.service.impl; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.zy.ai.domain.autotune.AutoTuneRoutePressureSnapshot; |
| | | import com.zy.ai.domain.autotune.AutoTuneRuleSnapshotItem; |
| | | import com.zy.ai.domain.autotune.AutoTuneSnapshot; |
| | | import com.zy.ai.domain.autotune.AutoTuneStationRuntimeItem; |
| | | import com.zy.ai.domain.autotune.AutoTuneTaskDetailItem; |
| | | import com.zy.ai.domain.autotune.AutoTuneTaskSnapshot; |
| | | import com.zy.ai.service.FlowTopologySnapshotService; |
| | | import com.zy.ai.service.RoutePressureSnapshotService; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.entity.BasStation; |
| | | import com.zy.asrs.entity.StationFlowCapacity; |
| | | import com.zy.asrs.entity.WrkMast; |
| | | import com.zy.asrs.service.BasDevpService; |
| | | import com.zy.asrs.service.BasStationService; |
| | | import com.zy.asrs.service.StationFlowCapacityService; |
| | | import com.zy.asrs.service.WrkMastService; |
| | | import com.zy.core.enums.WrkIoType; |
| | | import com.zy.core.enums.WrkStsType; |
| | | import com.zy.core.model.StationObjModel; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.system.service.ConfigService; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.mockito.ArgumentCaptor; |
| | |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertNull; |
| | | import static org.junit.jupiter.api.Assertions.assertSame; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.Mockito.mock; |
| | |
| | | |
| | | @BeforeEach |
| | | void setUp() { |
| | | ConfigService configService = mock(ConfigService.class); |
| | | service = new AutoTuneSnapshotServiceImpl(); |
| | | ReflectionTestUtils.setField(service, "configService", configService); |
| | | ReflectionTestUtils.setField(service, "autoTuneControlModeService", |
| | | new AutoTuneControlModeServiceImpl(configService)); |
| | | } |
| | | |
| | | @Test |
| | |
| | | assertEquals(0, result.get("102")); |
| | | assertEquals(-1, result.get("103")); |
| | | assertEquals(5, result.get("104")); |
| | | } |
| | | |
| | | @Test |
| | | void buildStationOutBufferCapacityMapPreservesConfiguredCapacity() { |
| | | Map<String, Integer> result = service.buildStationOutBufferCapacityMap(Arrays.asList( |
| | | station(101, 1, null), |
| | | station(102, 1, 0), |
| | | station(103, 1, 3) |
| | | )); |
| | | |
| | | assertNull(result.get("101")); |
| | | assertEquals(0, result.get("102")); |
| | | assertEquals(3, result.get("103")); |
| | | } |
| | | |
| | | @Test |
| | | void buildRuleSnapshotExposesStepRangeCooldownAndDynamicMaxSource() { |
| | | List<AutoTuneRuleSnapshotItem> result = service.buildRuleSnapshot(); |
| | | |
| | | AutoTuneRuleSnapshotItem stationOutTaskRule = findRule(result, "station", "outTaskLimit"); |
| | | assertEquals(0, stationOutTaskRule.getMinValue()); |
| | | assertNull(stationOutTaskRule.getMaxValue()); |
| | | assertEquals(3, stationOutTaskRule.getMaxStep()); |
| | | assertEquals(10, stationOutTaskRule.getCooldownMinutes()); |
| | | assertEquals(Boolean.TRUE, stationOutTaskRule.getDynamicMaxValue()); |
| | | assertEquals("currentParameterSnapshot.stationOutBufferCapacities[targetId]", |
| | | stationOutTaskRule.getDynamicMaxSource()); |
| | | assertEquals("单次调整幅度不能超过 maxStep;增大时不得超过对应站点 outBufferCapacity。", |
| | | stationOutTaskRule.getNote()); |
| | | |
| | | AutoTuneRuleSnapshotItem crnMaxOutRule = findRule(result, "crn", "maxOutTask"); |
| | | assertEquals(3, crnMaxOutRule.getMaxStep()); |
| | | assertNull(crnMaxOutRule.getDynamicMaxSource()); |
| | | assertEquals("单次调整幅度不能超过 maxStep。", crnMaxOutRule.getNote()); |
| | | |
| | | AutoTuneRuleSnapshotItem crnMaxInRule = findRule(result, "crn", "maxInTask"); |
| | | assertEquals(3, crnMaxInRule.getMaxStep()); |
| | | |
| | | assertRuleMaxStep(result, "sys_config", "crnOutBatchRunningLimit", 3); |
| | | assertRuleMaxStep(result, "dual_crn", "maxOutTask", 3); |
| | | assertRuleMaxStep(result, "dual_crn", "maxInTask", 3); |
| | | } |
| | | |
| | | @Test |
| | |
| | | } |
| | | |
| | | @Test |
| | | void loadStationOutTaskLimitsOnlyQueriesConfiguredOutDirectionStations() { |
| | | void buildTaskSnapshotExposesStationLimitBlockedTasksAndOutboundOrder() { |
| | | WrkMastService wrkMastService = mock(WrkMastService.class); |
| | | when(wrkMastService.list(any(Wrapper.class))).thenReturn(Arrays.asList( |
| | | outboundTask(190264, WrkStsType.STATION_RUN.sts, 101, 1, |
| | | "MANUAL_OUT_20260427181201", 9, ""), |
| | | outboundTask(190263, WrkStsType.NEW_OUTBOUND.sts, 101, 1, |
| | | "MANUAL_OUT_20260427181201", 8, |
| | | "目标出库站:101 已达出库任务上限,当前=1,上限=1") |
| | | )); |
| | | ReflectionTestUtils.setField(service, "wrkMastService", wrkMastService); |
| | | |
| | | AutoTuneTaskSnapshot snapshot = ReflectionTestUtils.invokeMethod(service, "buildTaskSnapshot"); |
| | | |
| | | assertEquals(2, snapshot.getActiveTaskCount()); |
| | | assertEquals(1, snapshot.getByStatus().get("101")); |
| | | assertEquals(1, snapshot.getByStatus().get("104")); |
| | | |
| | | List<AutoTuneTaskDetailItem> blockedTasks = snapshot.getStationLimitBlockedTasks(); |
| | | assertEquals(1, blockedTasks.size()); |
| | | assertEquals(190263, blockedTasks.get(0).getWrkNo()); |
| | | assertEquals("生成出库任务", blockedTasks.get(0).getWrkStsDesc()); |
| | | assertTrue(blockedTasks.get(0).getSystemMsg().contains("出库任务上限")); |
| | | |
| | | List<AutoTuneTaskDetailItem> outboundSamples = snapshot.getOutboundTaskSamples(); |
| | | assertEquals(2, outboundSamples.size()); |
| | | assertEquals(190263, outboundSamples.get(0).getWrkNo()); |
| | | assertEquals(8, outboundSamples.get(0).getBatchSeq()); |
| | | assertEquals(190264, outboundSamples.get(1).getWrkNo()); |
| | | assertEquals(9, outboundSamples.get(1).getBatchSeq()); |
| | | } |
| | | |
| | | @Test |
| | | void buildSnapshotIncludesRoutePressureSnapshot() { |
| | | WrkMastService wrkMastService = mock(WrkMastService.class); |
| | | FlowTopologySnapshotService flowTopologySnapshotService = mock(FlowTopologySnapshotService.class); |
| | | RoutePressureSnapshotService routePressureSnapshotService = mock(RoutePressureSnapshotService.class); |
| | | AutoTuneRoutePressureSnapshot routePressureSnapshot = new AutoTuneRoutePressureSnapshot(); |
| | | List<WrkMast> activeTasks = Collections.singletonList( |
| | | outboundTask(190263, WrkStsType.NEW_OUTBOUND.sts, 101, 1, |
| | | "BATCH", 8, "目标出库站:101 已达出库任务上限,当前=1,上限=1") |
| | | ); |
| | | when(wrkMastService.list(any(Wrapper.class))).thenReturn(activeTasks); |
| | | when(flowTopologySnapshotService.buildSnapshot(any())).thenReturn(Collections.emptyList()); |
| | | when(routePressureSnapshotService.buildSnapshot(any(), any(), any())).thenReturn(routePressureSnapshot); |
| | | ReflectionTestUtils.setField(service, "wrkMastService", wrkMastService); |
| | | ReflectionTestUtils.setField(service, "flowTopologySnapshotService", flowTopologySnapshotService); |
| | | ReflectionTestUtils.setField(service, "routePressureSnapshotService", routePressureSnapshotService); |
| | | |
| | | AutoTuneSnapshot snapshot = service.buildSnapshot(); |
| | | |
| | | assertSame(routePressureSnapshot, snapshot.getRoutePressureSnapshot()); |
| | | assertEquals(1, snapshot.getTaskSnapshot().getActiveTaskCount()); |
| | | |
| | | ArgumentCaptor<List<WrkMast>> activeTasksCaptor = ArgumentCaptor.forClass(List.class); |
| | | ArgumentCaptor<AutoTuneTaskSnapshot> taskSnapshotCaptor = ArgumentCaptor.forClass(AutoTuneTaskSnapshot.class); |
| | | ArgumentCaptor<List<AutoTuneStationRuntimeItem>> stationRuntimeCaptor = ArgumentCaptor.forClass(List.class); |
| | | verify(routePressureSnapshotService).buildSnapshot( |
| | | activeTasksCaptor.capture(), |
| | | taskSnapshotCaptor.capture(), |
| | | stationRuntimeCaptor.capture() |
| | | ); |
| | | assertSame(activeTasks, activeTasksCaptor.getValue()); |
| | | assertSame(snapshot.getTaskSnapshot(), taskSnapshotCaptor.getValue()); |
| | | assertSame(snapshot.getStationRuntimeSnapshot(), stationRuntimeCaptor.getValue()); |
| | | verify(wrkMastService).list(any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void loadOutStationListOnlyQueriesBasDevpOutStations() { |
| | | BasStationService basStationService = mock(BasStationService.class); |
| | | StationFlowCapacityService stationFlowCapacityService = mock(StationFlowCapacityService.class); |
| | | BasDevpService basDevpService = mock(BasDevpService.class); |
| | | ReflectionTestUtils.setField(service, "basStationService", basStationService); |
| | | ReflectionTestUtils.setField(service, "stationFlowCapacityService", stationFlowCapacityService); |
| | | when(stationFlowCapacityService.list(any(Wrapper.class))).thenReturn(Arrays.asList( |
| | | capacity(101, "OUT"), |
| | | capacity(102, "OUT") |
| | | ReflectionTestUtils.setField(service, "basDevpService", basDevpService); |
| | | when(basDevpService.list(any(Wrapper.class))).thenReturn(Arrays.asList( |
| | | basDevp(1, 101, 102), |
| | | basDevp(2, 102) |
| | | )); |
| | | when(basStationService.list(any(Wrapper.class))).thenReturn(Arrays.asList( |
| | | station(101, 2), |
| | | station(102, 3) |
| | | )); |
| | | |
| | | Map<String, Integer> result = ReflectionTestUtils.invokeMethod(service, "loadStationOutTaskLimits"); |
| | | java.util.List<BasStation> result = ReflectionTestUtils.invokeMethod(service, "loadOutStationList"); |
| | | |
| | | assertEquals(2, result.size()); |
| | | assertEquals(2, result.get("101")); |
| | | assertEquals(3, result.get("102")); |
| | | assertEquals(101, result.get(0).getStationId()); |
| | | assertEquals(102, result.get(1).getStationId()); |
| | | |
| | | ArgumentCaptor<Wrapper<StationFlowCapacity>> capacityWrapperCaptor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(stationFlowCapacityService).list(capacityWrapperCaptor.capture()); |
| | | assertTrue(capacityWrapperCaptor.getValue().getSqlSegment().contains("direction_code =")); |
| | | ArgumentCaptor<Wrapper<BasDevp>> basDevpWrapperCaptor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(basDevpService).list(basDevpWrapperCaptor.capture()); |
| | | assertTrue(basDevpWrapperCaptor.getValue().getSqlSegment().contains("status =")); |
| | | |
| | | ArgumentCaptor<Wrapper<BasStation>> stationWrapperCaptor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(basStationService).list(stationWrapperCaptor.capture()); |
| | |
| | | } |
| | | |
| | | @Test |
| | | void loadStationOutTaskLimitsDoesNotQueryStationsWhenNoOutCapacityExists() { |
| | | void loadOutStationListDoesNotQueryStationsWhenBasDevpOutStationsAreEmpty() { |
| | | BasStationService basStationService = mock(BasStationService.class); |
| | | StationFlowCapacityService stationFlowCapacityService = mock(StationFlowCapacityService.class); |
| | | BasDevpService basDevpService = mock(BasDevpService.class); |
| | | ReflectionTestUtils.setField(service, "basStationService", basStationService); |
| | | ReflectionTestUtils.setField(service, "stationFlowCapacityService", stationFlowCapacityService); |
| | | when(stationFlowCapacityService.list(any(Wrapper.class))).thenReturn(Collections.emptyList()); |
| | | ReflectionTestUtils.setField(service, "basDevpService", basDevpService); |
| | | when(basDevpService.list(any(Wrapper.class))).thenReturn(Collections.singletonList(basDevp(1))); |
| | | |
| | | Map<String, Integer> result = ReflectionTestUtils.invokeMethod(service, "loadStationOutTaskLimits"); |
| | | java.util.List<BasStation> result = ReflectionTestUtils.invokeMethod(service, "loadOutStationList"); |
| | | |
| | | assertTrue(result.isEmpty()); |
| | | verify(basStationService, never()).list(any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void toRuntimeItemExposesRunBlockForRoutePressure() { |
| | | StationProtocol protocol = new StationProtocol(); |
| | | protocol.setStationId(101); |
| | | protocol.setAutoing(true); |
| | | protocol.setLoading(false); |
| | | protocol.setTaskNo(0); |
| | | protocol.setRunBlock(true); |
| | | |
| | | AutoTuneStationRuntimeItem item = ReflectionTestUtils.invokeMethod(service, "toRuntimeItem", protocol); |
| | | |
| | | assertEquals(1, item.getRunBlock()); |
| | | } |
| | | |
| | | private BasStation station(Integer stationId, Integer outTaskLimit) { |
| | | return station(stationId, outTaskLimit, null); |
| | | } |
| | | |
| | | private BasStation station(Integer stationId, Integer outTaskLimit, Integer outBufferCapacity) { |
| | | BasStation station = new BasStation(); |
| | | station.setStationId(stationId); |
| | | station.setOutTaskLimit(outTaskLimit); |
| | | station.setOutBufferCapacity(outBufferCapacity); |
| | | return station; |
| | | } |
| | | |
| | | private StationFlowCapacity capacity(Integer stationId, String directionCode) { |
| | | StationFlowCapacity capacity = new StationFlowCapacity(); |
| | | capacity.setStationId(stationId); |
| | | capacity.setDirectionCode(directionCode); |
| | | return capacity; |
| | | private WrkMast outboundTask(Integer wrkNo, |
| | | long wrkSts, |
| | | Integer stationNo, |
| | | Integer crnNo, |
| | | String batch, |
| | | Integer batchSeq, |
| | | String systemMsg) { |
| | | WrkMast wrkMast = new WrkMast(); |
| | | wrkMast.setWrkNo(wrkNo); |
| | | wrkMast.setWrkSts(wrkSts); |
| | | wrkMast.setIoType(WrkIoType.OUT.id); |
| | | wrkMast.setStaNo(stationNo); |
| | | wrkMast.setCrnNo(crnNo); |
| | | wrkMast.setBatch(batch); |
| | | wrkMast.setBatchSeq(batchSeq); |
| | | wrkMast.setSystemMsg(systemMsg); |
| | | return wrkMast; |
| | | } |
| | | |
| | | private BasDevp basDevp(Integer devpNo, Integer... stationIds) { |
| | | BasDevp basDevp = new BasDevp(); |
| | | basDevp.setDevpNo(devpNo); |
| | | basDevp.setStatus(1); |
| | | if (stationIds == null || stationIds.length == 0) { |
| | | return basDevp; |
| | | } |
| | | basDevp.setOutStationList(JSON.toJSONString(Arrays.stream(stationIds) |
| | | .map(this::stationObjModel) |
| | | .toList())); |
| | | return basDevp; |
| | | } |
| | | |
| | | private StationObjModel stationObjModel(Integer stationId) { |
| | | StationObjModel stationObjModel = new StationObjModel(); |
| | | stationObjModel.setStationId(stationId); |
| | | return stationObjModel; |
| | | } |
| | | |
| | | private AutoTuneRuleSnapshotItem findRule(List<AutoTuneRuleSnapshotItem> rules, |
| | | String targetType, |
| | | String targetKey) { |
| | | for (AutoTuneRuleSnapshotItem rule : rules) { |
| | | if (targetType.equals(rule.getTargetType()) && targetKey.equals(rule.getTargetKey())) { |
| | | return rule; |
| | | } |
| | | } |
| | | throw new AssertionError("rule not found: " + targetType + "/" + targetKey); |
| | | } |
| | | |
| | | private void assertRuleMaxStep(List<AutoTuneRuleSnapshotItem> rules, |
| | | String targetType, |
| | | String targetKey, |
| | | int expectedMaxStep) { |
| | | AutoTuneRuleSnapshotItem rule = findRule(rules, targetType, targetKey); |
| | | assertEquals(expectedMaxStep, rule.getMaxStep()); |
| | | } |
| | | } |