From 26e9c84458f7cce7c17a968bd843a5ead5029b80 Mon Sep 17 00:00:00 2001
From: Junjie <fallin.jie@qq.com>
Date: 星期一, 27 四月 2026 13:39:12 +0800
Subject: [PATCH] test: cover auto tune failure job recovery

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

diff --git a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
index a138e1e..29a4323 100644
--- a/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
+++ b/src/test/java/com/zy/ai/service/AutoTuneApplyServiceImplTest.java
@@ -39,6 +39,7 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -406,6 +407,37 @@
     }
 
     @Test
+    void jobUpdateFailureRecordsFailureJobWhenRecoveryUpdateSucceeds() {
+        AtomicInteger updateAttempts = new AtomicInteger();
+        when(configService.getOne(any(Wrapper.class))).thenReturn(config("conveyorStationTaskLimit", "10"));
+        when(aiAutoTuneJobService.updateById(any(AiAutoTuneJob.class))).thenAnswer(invocation -> {
+            transactionManager.recordJobUpdateCall();
+            return updateAttempts.incrementAndGet() > 1;
+        });
+
+        AutoTuneApplyResult result = service.apply(request(false, command("sys_config", null, "conveyorStationTaskLimit", "15")));
+
+        List<AiAutoTuneChange> changes = savedChanges();
+        AiAutoTuneJob updatedJob = updatedJob();
+        assertFalse(result.getSuccess());
+        assertEquals("failed", updatedJob.getStatus());
+        assertEquals(1, changes.size());
+        assertEquals("failed", changes.get(0).getResultStatus());
+        assertTrue(changes.get(0).getRejectReason().contains("鏇存柊璋冨弬浠诲姟鐘舵�佸け璐�"));
+        assertEquals(1, transactionManager.getRollbackCount());
+        assertTrue(transactionManager.getCommitCount() >= 1);
+        assertTrue(transactionManager.getJobSaveInsideTransactionCount() > 0);
+        assertTrue(transactionManager.getJobUpdateInsideTransactionCount() > 0);
+        assertEquals(0, transactionManager.getJobSaveOutsideTransactionCount());
+        assertEquals(0, transactionManager.getJobUpdateOutsideTransactionCount());
+        verify(configService).saveConfigValue("conveyorStationTaskLimit", "15");
+        verify(configService, never()).refreshSystemConfigCache();
+        verify(aiAutoTuneChangeService, times(2)).saveBatch(any(Collection.class));
+        verify(aiAutoTuneJobService, times(2)).updateById(any(AiAutoTuneJob.class));
+        verify(redisUtil).compareAndDelete(eq(RedisKeyType.AI_AUTO_TUNE_APPLY_LOCK.key), anyString());
+    }
+
+    @Test
     void realApplyLockNotAcquiredRejectsWithoutTargetWrite() {
         when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(false);
 
@@ -546,6 +578,43 @@
     }
 
     @Test
+    void rollbackJobUpdateFailureRecordsFailureJobWhenRecoveryUpdateSucceeds() {
+        AtomicInteger updateAttempts = new AtomicInteger();
+        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"));
+        when(aiAutoTuneJobService.updateById(any(AiAutoTuneJob.class))).thenAnswer(invocation -> {
+            transactionManager.recordJobUpdateCall();
+            return updateAttempts.incrementAndGet() > 1;
+        });
+
+        AutoTuneApplyResult result = service.rollbackLastSuccessfulJob("manual rollback");
+
+        List<AiAutoTuneChange> changes = savedChanges();
+        AiAutoTuneJob updatedJob = updatedJob();
+        assertFalse(result.getSuccess());
+        assertEquals("failed", updatedJob.getStatus());
+        assertEquals(1, changes.size());
+        assertEquals("failed", changes.get(0).getResultStatus());
+        assertTrue(changes.get(0).getRejectReason().contains("鏇存柊璋冨弬浠诲姟鐘舵�佸け璐�"));
+        assertEquals(1, transactionManager.getRollbackCount());
+        assertTrue(transactionManager.getCommitCount() >= 1);
+        assertTrue(transactionManager.getJobSaveInsideTransactionCount() > 0);
+        assertTrue(transactionManager.getJobUpdateInsideTransactionCount() > 0);
+        assertEquals(0, transactionManager.getJobSaveOutsideTransactionCount());
+        assertEquals(0, transactionManager.getJobUpdateOutsideTransactionCount());
+        verify(configService).saveConfigValue("conveyorStationTaskLimit", "10");
+        verify(configService, never()).refreshSystemConfigCache();
+        verify(aiAutoTuneChangeService, times(2)).saveBatch(any(Collection.class));
+        verify(aiAutoTuneJobService, times(2)).updateById(any(AiAutoTuneJob.class));
+        verify(redisUtil).compareAndDelete(eq(RedisKeyType.AI_AUTO_TUNE_APPLY_LOCK.key), anyString());
+    }
+
+    @Test
     void rollbackLockNotAcquiredReturnsFailedAuditWithoutTargetWrite() {
         when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(false);
 

--
Gitblit v1.9.1