| | |
| | | import static org.mockito.ArgumentMatchers.anyInt; |
| | | import static org.mockito.ArgumentMatchers.anyLong; |
| | | import static org.mockito.ArgumentMatchers.anyString; |
| | | import static org.mockito.ArgumentMatchers.eq; |
| | | import static org.mockito.Mockito.doThrow; |
| | | import static org.mockito.Mockito.never; |
| | | import static org.mockito.Mockito.times; |
| | | import static org.mockito.Mockito.verify; |
| | |
| | | when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10"); |
| | | when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L); |
| | | when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null); |
| | | when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList(), Collections.emptyList()); |
| | | when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList()); |
| | | when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true); |
| | | when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult); |
| | | |
| | |
| | | verify(autoTuneAgentService).runAutoTune(AutoTuneTriggerType.AUTO.getCode()); |
| | | verify(operateLogService).save(any()); |
| | | verify(redisUtil).set(anyString(), any(), anyLong()); |
| | | verify(redisUtil).compareAndDelete(anyString(), anyString()); |
| | | } |
| | | |
| | | @Test |
| | | void coordinatorKeepsAgentResultWhenOperateLogFails() { |
| | | AutoTuneAgentService.AutoTuneAgentResult agentResult = successfulAgentResult(); |
| | | when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y"); |
| | | when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10"); |
| | | when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L); |
| | | when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null); |
| | | when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList()); |
| | | when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true); |
| | | when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult); |
| | | doThrow(new RuntimeException("log failed")).when(operateLogService).save(any()); |
| | | |
| | | AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible(); |
| | | |
| | | assertFalse(result.getSkipped()); |
| | | assertTrue(result.getTriggered()); |
| | | assertSame(agentResult, result.getAgentResult()); |
| | | verify(redisUtil).compareAndDelete(anyString(), anyString()); |
| | | } |
| | | |
| | | @Test |
| | | void coordinatorSetsGuardWhenAgentReturnsFailure() { |
| | | AutoTuneAgentService.AutoTuneAgentResult agentResult = failedAgentResult(); |
| | | when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y"); |
| | | when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10"); |
| | | when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L); |
| | | when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null); |
| | | when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList()); |
| | | when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true); |
| | | when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenReturn(agentResult); |
| | | |
| | | AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible(); |
| | | |
| | | assertFalse(result.getSkipped()); |
| | | assertSame(agentResult, result.getAgentResult()); |
| | | verify(redisUtil).set(eq(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key), any(), eq(600L)); |
| | | } |
| | | |
| | | @Test |
| | | void coordinatorSetsGuardWhenAgentThrows() { |
| | | when(configService.getConfigValue("aiAutoTuneEnabled", "N")).thenReturn("Y"); |
| | | when(configService.getConfigValue("aiAutoTuneIntervalMinutes", "10")).thenReturn("10"); |
| | | when(wrkMastService.count(any(Wrapper.class))).thenReturn(1L); |
| | | when(redisUtil.get(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key)).thenReturn(null); |
| | | when(aiAutoTuneJobService.list(any(Wrapper.class))).thenReturn(Collections.emptyList()); |
| | | when(redisUtil.trySetStringIfAbsent(anyString(), anyString(), anyLong())).thenReturn(true); |
| | | when(autoTuneAgentService.runAutoTune(AutoTuneTriggerType.AUTO.getCode())).thenThrow(new RuntimeException("agent failed")); |
| | | |
| | | AutoTuneCoordinatorService.AutoTuneCoordinatorResult result = coordinatorService().runAutoTuneIfEligible(); |
| | | |
| | | assertFalse(result.getSkipped()); |
| | | assertFalse(result.getAgentResult().getSuccess()); |
| | | verify(redisUtil).set(eq(RedisKeyType.AI_AUTO_TUNE_LAST_TRIGGER_GUARD.key), any(), eq(600L)); |
| | | verify(redisUtil).compareAndDelete(anyString(), anyString()); |
| | | } |
| | | |
| | |
| | | assertTrue(visibleToolNames.contains("wcs_local_dispatch_apply_auto_tune_changes")); |
| | | assertTrue(visibleToolNames.contains("wcs_local_dispatch_revert_last_auto_tune_job")); |
| | | assertFalse(visibleToolNames.contains("wcs_local_device_get_crn_status")); |
| | | } |
| | | |
| | | @Test |
| | | void agentForcesAutoTriggerTypeOnApplyTools() { |
| | | AutoTuneAgentServiceImpl service = agentService(); |
| | | when(mcpToolManager.buildOpenAiTools()).thenReturn(allowedOpenAiTools()); |
| | | when(mcpToolManager.callTool(any(), any(JSONObject.class))).thenReturn(Collections.singletonMap("ok", true)); |
| | | when(llmChatService.chatCompletion(any(), anyDouble(), anyInt(), any())) |
| | | .thenReturn( |
| | | response("snapshot", toolCall("call_1", "wcs_local_dispatch_get_auto_tune_snapshot", |
| | | "{}"), 10, 5), |
| | | response("dry run", toolCall("call_2", "wcs_local_dispatch_apply_auto_tune_changes", |
| | | "{\"dryRun\":true,\"changes\":[]}"), 10, 5), |
| | | response("done", null, 10, 5) |
| | | ); |
| | | |
| | | AutoTuneAgentService.AutoTuneAgentResult result = service.runAutoTune("auto"); |
| | | |
| | | assertTrue(result.getSuccess()); |
| | | ArgumentCaptor<JSONObject> argumentCaptor = ArgumentCaptor.forClass(JSONObject.class); |
| | | verify(mcpToolManager).callTool(eq("wcs_local_dispatch_apply_auto_tune_changes"), argumentCaptor.capture()); |
| | | assertEquals("auto", argumentCaptor.getValue().getString("triggerType")); |
| | | } |
| | | |
| | | @Test |
| | |
| | | return result; |
| | | } |
| | | |
| | | private AutoTuneAgentService.AutoTuneAgentResult failedAgentResult() { |
| | | AutoTuneAgentService.AutoTuneAgentResult result = successfulAgentResult(); |
| | | result.setSuccess(false); |
| | | result.setSummary("failed"); |
| | | return result; |
| | | } |
| | | |
| | | private AutoTuneChangeCommand change(String targetType, String targetId, String targetKey, String newValue) { |
| | | AutoTuneChangeCommand command = new AutoTuneChangeCommand(); |
| | | command.setTargetType(targetType); |