From 63b01db83d9aad8a15276b4236a9a22e4aeef065 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期二, 05 五月 2026 12:30:59 +0800
Subject: [PATCH] # Agent数据分析V3.0.1.7

---
 src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java |  122 ++++++++++++++++++++++++++++++++++------
 1 files changed, 103 insertions(+), 19 deletions(-)

diff --git a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
index 278b1ae..4650cc9 100644
--- a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
+++ b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
@@ -7,6 +7,7 @@
 import com.zy.ai.entity.AiAutoTuneChange;
 import com.zy.ai.entity.AiAutoTuneJob;
 import com.zy.ai.service.impl.AutoTuneApplyServiceImpl;
+import com.zy.ai.service.impl.AutoTuneControlModeServiceImpl;
 import com.zy.asrs.entity.BasCrnp;
 import com.zy.asrs.entity.BasDualCrnp;
 import com.zy.asrs.entity.BasStation;
@@ -89,6 +90,8 @@
         ReflectionTestUtils.setField(service, "aiAutoTuneJobService", aiAutoTuneJobService);
         ReflectionTestUtils.setField(service, "aiAutoTuneChangeService", aiAutoTuneChangeService);
         ReflectionTestUtils.setField(service, "configService", configService);
+        ReflectionTestUtils.setField(service, "autoTuneControlModeService",
+                new AutoTuneControlModeServiceImpl(configService));
         ReflectionTestUtils.setField(service, "basStationService", basStationService);
         ReflectionTestUtils.setField(service, "basCrnpService", basCrnpService);
         ReflectionTestUtils.setField(service, "basDualCrnpService", basDualCrnpService);
@@ -111,6 +114,7 @@
         when(aiAutoTuneChangeService.list(any(Wrapper.class))).thenReturn(Collections.emptyList());
         when(wrkMastService.count(any(Wrapper.class))).thenReturn(0L);
         when(configService.getConfigValue(eq("aiAutoTuneIntervalMinutes"), any())).thenReturn("10");
+        when(configService.getConfigValue("aiAutoTuneAnalysisOnly", "Y")).thenReturn("N");
         when(configService.saveConfigValue(any(), any())).thenReturn(true);
         when(basStationService.update(any(Wrapper.class))).thenReturn(true);
         when(basCrnpService.update(any(Wrapper.class))).thenReturn(true);
@@ -163,35 +167,41 @@
     }
 
     @Test
-    void rejectCrnOutBatchRunningLimitRangeAndStepCases() {
+    void crnOutBatchRunningLimitAllowsStepThreeAndRejectsRangeAndStepCases() {
         when(configService.getOne(any(Wrapper.class))).thenReturn(config("crnOutBatchRunningLimit", "10"));
 
         service.apply(request(true,
                 command("sys_config", null, "crnOutBatchRunningLimit", "13"),
+                command("sys_config", null, "crnOutBatchRunningLimit", "14"),
                 command("sys_config", null, "crnOutBatchRunningLimit", "21")
         ));
 
         List<AiAutoTuneChange> changes = savedChanges();
-        assertEquals("rejected", changes.get(0).getResultStatus());
-        assertTrue(changes.get(0).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 2"));
+        assertEquals("dry_run", changes.get(0).getResultStatus());
+        assertEquals("13", changes.get(0).getRequestedValue());
         assertEquals("rejected", changes.get(1).getResultStatus());
-        assertTrue(changes.get(1).getRejectReason().contains("1~20"));
+        assertTrue(changes.get(1).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 3"));
+        assertEquals("rejected", changes.get(2).getResultStatus());
+        assertTrue(changes.get(2).getRejectReason().contains("1~20"));
     }
 
     @Test
-    void rejectMaxInTaskRangeAndStepCases() {
+    void maxInTaskAllowsStepThreeAndRejectsRangeAndStepCases() {
         when(basCrnpService.getById(1)).thenReturn(crn(1, 1, 5));
 
         service.apply(request(true,
-                command("crn", "1", "maxInTask", "7"),
+                command("crn", "1", "maxInTask", "8"),
+                command("crn", "1", "maxInTask", "9"),
                 command("crn", "1", "maxInTask", "11")
         ));
 
         List<AiAutoTuneChange> changes = savedChanges();
-        assertEquals("rejected", changes.get(0).getResultStatus());
-        assertTrue(changes.get(0).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 1"));
+        assertEquals("dry_run", changes.get(0).getResultStatus());
+        assertEquals("8", changes.get(0).getRequestedValue());
         assertEquals("rejected", changes.get(1).getResultStatus());
-        assertTrue(changes.get(1).getRejectReason().contains("0~10"));
+        assertTrue(changes.get(1).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 3"));
+        assertEquals("rejected", changes.get(2).getResultStatus());
+        assertTrue(changes.get(2).getRejectReason().contains("0~10"));
     }
 
     @Test
@@ -227,14 +237,20 @@
     }
 
     @Test
-    void rejectStationOutTaskLimitAboveDirectionalBufferCapacity() {
-        when(basStationService.getById(101)).thenReturn(station(101, 1, 2));
+    void stationOutTaskLimitAllowsAboveBufferCapacityButRejectsOverStep() {
+        when(basStationService.getById(101)).thenReturn(station(101, 5, 3));
 
-        service.apply(request(true, command("station", "101", "outTaskLimit", "3")));
+        service.apply(request(true,
+                command("station", "101", "outTaskLimit", "6"),
+                command("station", "101", "outTaskLimit", "9")
+        ));
 
         List<AiAutoTuneChange> changes = savedChanges();
-        assertEquals("rejected", changes.get(0).getResultStatus());
-        assertTrue(changes.get(0).getRejectReason().contains("0~2"));
+        assertEquals("dry_run", changes.get(0).getResultStatus());
+        assertEquals("5", changes.get(0).getOldValue());
+        assertEquals("6", changes.get(0).getRequestedValue());
+        assertEquals("rejected", changes.get(1).getResultStatus());
+        assertTrue(changes.get(1).getRejectReason().contains("姝ラ暱涓嶈兘瓒呰繃 3"));
     }
 
     @Test
@@ -273,14 +289,15 @@
     }
 
     @Test
-    void rejectStationOutTaskLimitWithoutOutBufferCapacity() {
+    void allowStationOutTaskLimitWithoutOutBufferCapacity() {
         when(basStationService.getById(101)).thenReturn(station(101, 0));
 
-        service.apply(request(true, command("station", "101", "outTaskLimit", "1")));
+        AutoTuneApplyResult result = service.apply(request(true, command("station", "101", "outTaskLimit", "1")));
 
         List<AiAutoTuneChange> changes = savedChanges();
-        assertEquals("rejected", changes.get(0).getResultStatus());
-        assertTrue(changes.get(0).getRejectReason().contains("缂哄皯 outBufferCapacity"));
+        assertTrue(result.getSuccess());
+        assertEquals("dry_run", changes.get(0).getResultStatus());
+        assertEquals("1", changes.get(0).getRequestedValue());
     }
 
     @Test
@@ -305,7 +322,7 @@
 
         AutoTuneApplyResult result = service.apply(request(false,
                 command("sys_config", null, "conveyorStationTaskLimit", "15"),
-                command("station", "101", "outTaskLimit", "3")
+                command("station", "101", "outTaskLimit", "5")
         ));
 
         List<AiAutoTuneChange> changes = savedChanges();
@@ -314,6 +331,38 @@
         assertTrue(changes.stream().allMatch(change -> "rejected".equals(change.getResultStatus())));
         verify(configService, never()).saveConfigValue(any(), any());
         verify(basStationService, never()).update(any(Wrapper.class));
+    }
+
+    @Test
+    void analysisOnlyRealApplyWritesRejectedAuditAndDoesNotAcquireApplyLock() {
+        when(configService.getConfigValue("aiAutoTuneAnalysisOnly", "Y")).thenReturn("Y");
+
+        AutoTuneApplyResult result = service.apply(request(false,
+                command("sys_config", null, "conveyorStationTaskLimit", "15")));
+
+        List<AiAutoTuneChange> changes = savedChanges();
+        AiAutoTuneJob job = updatedJob();
+        assertFalse(result.getSuccess());
+        assertTrue(result.getAnalysisOnly());
+        assertTrue(result.getNoApply());
+        assertEquals("rejected", job.getStatus());
+        assertEquals("rejected", changes.get(0).getResultStatus());
+        assertTrue(changes.get(0).getRejectReason().contains("浠呭垎鏋愭ā寮忕姝㈠疄闄呭簲鐢�/鍥炴粴"));
+        verify(redisUtil, never()).trySetStringIfAbsent(anyString(), anyString(), anyLong());
+        verify(configService, never()).saveConfigValue(any(), any());
+    }
+
+    @Test
+    void realApplyResultUsesEntryControlModeSnapshotWhenConfigFlips() {
+        when(configService.getConfigValue("aiAutoTuneAnalysisOnly", "Y")).thenReturn("N", "Y");
+        when(configService.getOne(any(Wrapper.class))).thenReturn(config("conveyorStationTaskLimit", "10"));
+
+        AutoTuneApplyResult result = service.apply(request(false,
+                command("sys_config", null, "conveyorStationTaskLimit", "15")));
+
+        assertTrue(result.getSuccess());
+        assertFalse(result.getAnalysisOnly());
+        verify(configService, times(1)).getConfigValue("aiAutoTuneAnalysisOnly", "Y");
     }
 
     @Test
@@ -332,6 +381,41 @@
     }
 
     @Test
+    void analysisOnlyRollbackWritesRejectedAuditAndDoesNotAcquireApplyLock() {
+        when(configService.getConfigValue("aiAutoTuneAnalysisOnly", "Y")).thenReturn("Y");
+
+        AutoTuneApplyResult result = service.rollbackLastSuccessfulJob("manual rollback");
+
+        List<AiAutoTuneChange> changes = savedChanges();
+        AiAutoTuneJob job = updatedJob();
+        assertFalse(result.getSuccess());
+        assertTrue(result.getAnalysisOnly());
+        assertTrue(result.getNoApply());
+        assertEquals("rejected", job.getStatus());
+        assertEquals("rejected", changes.get(0).getResultStatus());
+        assertEquals("rollback", changes.get(0).getTargetKey());
+        verify(redisUtil, never()).trySetStringIfAbsent(anyString(), anyString(), anyLong());
+    }
+
+    @Test
+    void rollbackResultUsesEntryControlModeSnapshotWhenConfigFlips() {
+        when(configService.getConfigValue("aiAutoTuneAnalysisOnly", "Y")).thenReturn("N", "Y");
+        AiAutoTuneJob latestRealJob = job(10L, "manual", "success");
+        AiAutoTuneChange configChange = successChange(10L, "sys_config", "", "conveyorStationTaskLimit", "10", "15");
+        when(aiAutoTuneChangeService.list(any(Wrapper.class)))
+                .thenReturn(List.of(configChange))
+                .thenReturn(List.of(configChange));
+        when(aiAutoTuneJobService.getById(10L)).thenReturn(latestRealJob);
+        when(configService.getOne(any(Wrapper.class))).thenReturn(config("conveyorStationTaskLimit", "15"));
+
+        AutoTuneApplyResult result = service.rollbackLastSuccessfulJob("manual rollback");
+
+        assertTrue(result.getSuccess());
+        assertFalse(result.getAnalysisOnly());
+        verify(configService, times(1)).getConfigValue("aiAutoTuneAnalysisOnly", "Y");
+    }
+
+    @Test
     void applyJobRecordsActiveTasksWhenCountIsPositive() {
         when(configService.getOne(any(Wrapper.class))).thenReturn(config("conveyorStationTaskLimit", "10"));
         when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L);

--
Gitblit v1.9.1