union-ark-web 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROJECT_OVERVIEW.md +405 -0
- package/README.md +177 -0
- package/ark-control/pom.xml +142 -0
- package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SecurityResult.java +14 -0
- package/ark-control/src/local-mock/java/com/epcc/commons/securityproxy/api/SymmetricalSecurityService.java +11 -0
- package/ark-control/src/local-mock/java/com/epcc/dubbo/result/Result.java +29 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptField.java +16 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldLong.java +17 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/annotation/EnDecryptFieldWithTag.java +16 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/BaseDataErrorCode.java +26 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/CheckException.java +33 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/exception/ErrorCode.java +9 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/redis/RedisCacheService.java +131 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/Constant.java +24 -0
- package/ark-control/src/local-mock/java/com/nucc/channel/ark/common/util/ResultUtil.java +9 -0
- package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalMockSensitiveProxy.java +40 -0
- package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalRedisCacheService.java +45 -0
- package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveHostConfiguration.java +27 -0
- package/ark-control/src/local-mock/java/com/union/control/local/sensitive/LocalSensitiveProxyConfiguration.java +16 -0
- package/ark-control/src/main/java/com/union/control/ArkControlApplication.java +17 -0
- package/ark-control/src/main/java/com/union/control/dubbo/ProviderAccessLogFilter.java +45 -0
- package/ark-control/src/main/java/com/union/control/mapper/AgentExecutionMapper.java +35 -0
- package/ark-control/src/main/java/com/union/control/mapper/ConversationMapper.java +44 -0
- package/ark-control/src/main/java/com/union/control/mapper/MemoryStoreMapper.java +41 -0
- package/ark-control/src/main/java/com/union/control/mapper/ScheduledTaskMapper.java +96 -0
- package/ark-control/src/main/java/com/union/control/mapper/SensitiveAddressBookDemo.java +31 -0
- package/ark-control/src/main/java/com/union/control/mapper/SensitiveDataDemoMapper.java +24 -0
- package/ark-control/src/main/java/com/union/control/mapper/interceptor/AESInterceptor.java +265 -0
- package/ark-control/src/main/java/com/union/control/mapper/interceptor/AddressBookHandler.java +105 -0
- package/ark-control/src/main/java/com/union/control/schedule/ScheduledExecutionToken.java +55 -0
- package/ark-control/src/main/java/com/union/control/schedule/ScheduledTaskScheduler.java +206 -0
- package/ark-control/src/main/java/com/union/control/service/impl/AgentExecutionServiceImpl.java +212 -0
- package/ark-control/src/main/java/com/union/control/service/impl/AgentProxyServiceImpl.java +143 -0
- package/ark-control/src/main/java/com/union/control/service/impl/ConversationServiceImpl.java +245 -0
- package/ark-control/src/main/java/com/union/control/service/impl/MemoryStoreServiceImpl.java +252 -0
- package/ark-control/src/main/java/com/union/control/service/impl/RunningAnalysisMockServiceImpl.java +301 -0
- package/ark-control/src/main/java/com/union/control/service/impl/ScheduledTaskServiceImpl.java +576 -0
- package/ark-control/src/main/java/com/union/control/service/impl/SensitiveDataDemoServiceImpl.java +144 -0
- package/ark-control/src/main/java/com/union/control/service/sensitive/RedisRevealTokenStore.java +90 -0
- package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealProcessor.java +319 -0
- package/ark-control/src/main/java/com/union/control/service/sensitive/SensitiveRevealServiceImpl.java +72 -0
- package/ark-control/src/main/java/com/union/control/utils/AgentSupport.java +103 -0
- package/ark-control/src/main/java/com/union/control/utils/security/SymmetricalSecurityUtils.java +160 -0
- package/ark-control/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter +1 -0
- package/ark-control/src/main/resources/application.properties +4 -0
- package/ark-control/src/main/resources/application.yml +32 -0
- package/ark-control/src/main/resources/dubbo-provider.xml +20 -0
- package/ark-control/src/main/resources/mapper/AgentExecutionMapper.xml +75 -0
- package/ark-control/src/main/resources/mapper/ConversationMapper.xml +110 -0
- package/ark-control/src/main/resources/mapper/MemoryStoreMapper.xml +74 -0
- package/ark-control/src/main/resources/mapper/ScheduledTaskMapper.xml +286 -0
- package/ark-control/src/main/resources/mapper/SensitiveDataDemoMapper.xml +55 -0
- package/ark-control/src/main/resources/schema.sql +146 -0
- package/ark-control/src/test/java/com/union/control/AgentExecutionServiceTest.java +170 -0
- package/ark-control/src/test/java/com/union/control/ArkControlStructureContractTest.java +107 -0
- package/ark-control/src/test/java/com/union/control/ConversationServiceTest.java +89 -0
- package/ark-control/src/test/java/com/union/control/MemoryStoreServiceTest.java +26 -0
- package/ark-control/src/test/java/com/union/control/PydanticAiControlContractTest.java +52 -0
- package/ark-control/src/test/java/com/union/control/TestJson.java +45 -0
- package/ark-control/src/test/java/com/union/control/dubbo/ProviderAccessLogFilterTest.java +53 -0
- package/ark-control/src/test/java/com/union/control/local/sensitive/LocalSensitiveProxyConfigurationTest.java +23 -0
- package/ark-control/src/test/java/com/union/control/mapper/interceptor/AESInterceptorCompatibilityTest.java +505 -0
- package/ark-control/src/test/java/com/union/control/schedule/ScheduledExecutionTokenTest.java +27 -0
- package/ark-control/src/test/java/com/union/control/schedule/ScheduledTaskSchedulerTest.java +51 -0
- package/ark-control/src/test/java/com/union/control/service/AgentProxyServiceTest.java +111 -0
- package/ark-control/src/test/java/com/union/control/service/ScheduledTaskServiceTest.java +483 -0
- package/ark-control/src/test/java/com/union/control/service/impl/SensitiveDataDemoServiceImplTest.java +104 -0
- package/ark-control/src/test/java/com/union/control/service/sensitive/RedisRevealTokenStoreTest.java +65 -0
- package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealBoundaryTest.java +99 -0
- package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorCodecTest.java +111 -0
- package/ark-control/src/test/java/com/union/control/service/sensitive/SensitiveRevealProcessorTest.java +111 -0
- package/ark-control/src/test/java/com/union/control/utils/security/SymmetricalSecurityUtilsCompatibilityTest.java +87 -0
- package/ark-control-facade/pom.xml +16 -0
- package/ark-control-facade/src/main/java/com/union/control/service/AgentExecutionService.java +8 -0
- package/ark-control-facade/src/main/java/com/union/control/service/AgentProxyService.java +7 -0
- package/ark-control-facade/src/main/java/com/union/control/service/AgentResponse.java +22 -0
- package/ark-control-facade/src/main/java/com/union/control/service/ConversationService.java +12 -0
- package/ark-control-facade/src/main/java/com/union/control/service/MemoryStoreService.java +12 -0
- package/ark-control-facade/src/main/java/com/union/control/service/RunningAnalysisMockService.java +10 -0
- package/ark-control-facade/src/main/java/com/union/control/service/ScheduledTaskService.java +40 -0
- package/ark-control-facade/src/main/java/com/union/control/service/SensitiveDataDemoService.java +13 -0
- package/ark-control-facade/src/main/java/com/union/control/service/sensitive/SensitiveRevealService.java +18 -0
- package/ark-web/README.md +80 -0
- package/ark-web/pom.xml +105 -0
- package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/ArkAuthServiceMock.java +105 -0
- package/ark-web/src/local-mock/java/com/epcc/arkweb/mock/LocalKaptchaConfiguration.java +26 -0
- package/ark-web/src/main/java/com/epcc/arkweb/Application.java +13 -0
- package/ark-web/src/main/java/com/epcc/arkweb/config/InterceptorConfig.java +20 -0
- package/ark-web/src/main/java/com/epcc/arkweb/config/Realm.java +64 -0
- package/ark-web/src/main/java/com/epcc/arkweb/config/ShiroConfig.java +129 -0
- package/ark-web/src/main/java/com/epcc/arkweb/filter/LoginFormFilter.java +43 -0
- package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthContextHolder.java +39 -0
- package/ark-web/src/main/java/com/epcc/arkweb/helper/AuthenticatedRequest.java +91 -0
- package/ark-web/src/main/java/com/epcc/arkweb/model/ShiroUser.java +21 -0
- package/ark-web/src/main/java/com/epcc/arkweb/utils/ResultMsg.java +19 -0
- package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskCommandVO.java +30 -0
- package/ark-web/src/main/java/com/epcc/arkweb/vo/llm/ScheduledTaskQueryVO.java +20 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/CommonController.java +25 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptor.java +229 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentController.java +165 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/llm/AgentPermission.java +13 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/llm/LlmController.java +209 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/llm/ScheduledTaskController.java +160 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveCaptchaService.java +146 -0
- package/ark-web/src/main/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealController.java +163 -0
- package/ark-web/src/main/resources/application.properties +1 -0
- package/ark-web/src/main/resources/application.yml +23 -0
- package/ark-web/src/main/resources/dubbo-consumer.xml +19 -0
- package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/CasShiroConfig.java +229 -0
- package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/InterceptorConfig.java +35 -0
- package/ark-web/src/production-overlay/java/com/epcc/arkweb/config/ShiroConfig.java +161 -0
- package/ark-web/src/test/java/com/epcc/arkweb/ArkWebStructureContractTest.java +290 -0
- package/ark-web/src/test/java/com/epcc/arkweb/ShiroTestSupport.java +32 -0
- package/ark-web/src/test/java/com/epcc/arkweb/config/LocalShiroIntegrationTest.java +121 -0
- package/ark-web/src/test/java/com/epcc/arkweb/helper/AuthenticatedRequestTest.java +131 -0
- package/ark-web/src/test/java/com/epcc/arkweb/local/LocalArkAuthServiceMockTest.java +17 -0
- package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentAuthorizationInterceptorTest.java +134 -0
- package/ark-web/src/test/java/com/epcc/arkweb/web/llm/AgentControllerAuthorizationTest.java +97 -0
- package/ark-web/src/test/java/com/epcc/arkweb/web/llm/LlmControllerTest.java +113 -0
- package/ark-web/src/test/java/com/epcc/arkweb/web/sensitive/reveal/SensitiveRevealControllerTest.java +273 -0
- package/package.json +18 -0
- package/pom.xml +16 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
package com.union.control.service;
|
|
2
|
+
|
|
3
|
+
import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
4
|
+
import ch.qos.logback.core.read.ListAppender;
|
|
5
|
+
import org.junit.Test;
|
|
6
|
+
import org.slf4j.LoggerFactory;
|
|
7
|
+
import org.springframework.http.HttpStatus;
|
|
8
|
+
import org.springframework.http.HttpMethod;
|
|
9
|
+
import org.springframework.http.MediaType;
|
|
10
|
+
import com.union.control.service.impl.AgentProxyServiceImpl;
|
|
11
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
12
|
+
import org.springframework.test.web.client.MockRestServiceServer;
|
|
13
|
+
import org.springframework.web.client.RestTemplate;
|
|
14
|
+
|
|
15
|
+
import java.util.stream.Collectors;
|
|
16
|
+
|
|
17
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
18
|
+
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
|
19
|
+
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
|
20
|
+
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
|
21
|
+
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
|
22
|
+
|
|
23
|
+
public class AgentProxyServiceTest {
|
|
24
|
+
@Test
|
|
25
|
+
public void logsModelCallMetadataWithoutCredentialsOrPayload() {
|
|
26
|
+
RestTemplate http = new RestTemplate();
|
|
27
|
+
MockRestServiceServer server = MockRestServiceServer.createServer(http);
|
|
28
|
+
server.expect(requestTo("http://py-app/agent/v1/runs/sync"))
|
|
29
|
+
.andExpect(method(HttpMethod.POST))
|
|
30
|
+
.andRespond(withSuccess("{ \"content\" : \"model-secret\" }", MediaType.APPLICATION_JSON));
|
|
31
|
+
ListAppender<ILoggingEvent> logs = logs();
|
|
32
|
+
String payload = "{\"prompt\":\"plaintext-secret\"}";
|
|
33
|
+
|
|
34
|
+
AgentResponse response = new AgentProxyServiceImpl("http://py-app", http, new ObjectMapper())
|
|
35
|
+
.sync("CASSESSIONID=cookie-secret", payload);
|
|
36
|
+
|
|
37
|
+
String messages = logs.list.stream()
|
|
38
|
+
.map(ILoggingEvent::getFormattedMessage)
|
|
39
|
+
.collect(Collectors.joining("\n"));
|
|
40
|
+
assertThat(response.getBody()).isEqualTo("{\"content\":\"model-secret\"}");
|
|
41
|
+
assertThat(messages).contains("Agent call started mode=sync payload_chars=" + payload.length())
|
|
42
|
+
.contains("Agent call completed mode=sync status=200 duration_ms=")
|
|
43
|
+
.doesNotContain("cookie-secret")
|
|
44
|
+
.doesNotContain("plaintext-secret")
|
|
45
|
+
.doesNotContain("model-secret");
|
|
46
|
+
server.verify();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Test
|
|
50
|
+
public void cancellationPassesThroughPyAppResponse() {
|
|
51
|
+
RestTemplate http = new RestTemplate();
|
|
52
|
+
MockRestServiceServer server = MockRestServiceServer.createServer(http);
|
|
53
|
+
server.expect(requestTo("http://py-app/agent/v1/runs/cancel"))
|
|
54
|
+
.andExpect(method(HttpMethod.POST))
|
|
55
|
+
.andRespond(withStatus(HttpStatus.CONFLICT)
|
|
56
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
57
|
+
.body("{\"detail\":\"already finished\"}"));
|
|
58
|
+
|
|
59
|
+
AgentResponse response = new AgentProxyServiceImpl("http://py-app", http, new ObjectMapper())
|
|
60
|
+
.cancel("CASSESSIONID=session", "thread-1", "run-1");
|
|
61
|
+
|
|
62
|
+
assertThat(response.getStatus()).isEqualTo(HttpStatus.CONFLICT.value());
|
|
63
|
+
assertThat(response.getBody()).isEqualTo("{\"detail\":\"already finished\"}");
|
|
64
|
+
server.verify();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@Test(timeout = 5000)
|
|
68
|
+
public void allProxyModesStopWaitingForASilentUpstream() throws Exception {
|
|
69
|
+
com.sun.net.httpserver.HttpServer server = com.sun.net.httpserver.HttpServer.create(
|
|
70
|
+
new java.net.InetSocketAddress("127.0.0.1", 0), 0);
|
|
71
|
+
server.createContext("/", exchange -> {
|
|
72
|
+
try { Thread.sleep(150); }
|
|
73
|
+
catch (InterruptedException error) { Thread.currentThread().interrupt(); }
|
|
74
|
+
finally { exchange.close(); }
|
|
75
|
+
});
|
|
76
|
+
server.start();
|
|
77
|
+
try {
|
|
78
|
+
AgentProxyServiceImpl service = new AgentProxyServiceImpl(
|
|
79
|
+
"http://127.0.0.1:" + server.getAddress().getPort(), new ObjectMapper(), 0.05);
|
|
80
|
+
org.assertj.core.api.Assertions.assertThatThrownBy(() -> service.sync("session", "{}"))
|
|
81
|
+
.isInstanceOf(org.springframework.web.client.ResourceAccessException.class)
|
|
82
|
+
.hasCauseInstanceOf(java.net.SocketTimeoutException.class);
|
|
83
|
+
org.assertj.core.api.Assertions.assertThatThrownBy(() -> service.scheduled("Scheduled token"))
|
|
84
|
+
.isInstanceOf(org.springframework.web.client.ResourceAccessException.class)
|
|
85
|
+
.hasCauseInstanceOf(java.net.SocketTimeoutException.class);
|
|
86
|
+
org.assertj.core.api.Assertions.assertThatThrownBy(() -> service.cancel("session", "thread", "run"))
|
|
87
|
+
.isInstanceOf(org.springframework.web.client.ResourceAccessException.class)
|
|
88
|
+
.hasCauseInstanceOf(java.net.SocketTimeoutException.class);
|
|
89
|
+
} finally {
|
|
90
|
+
server.stop(0);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@Test
|
|
95
|
+
public void rejectsUnboundedOrOverflowingTimeouts() {
|
|
96
|
+
for (double seconds : new double[]{0, -1, Double.NaN, Double.POSITIVE_INFINITY, Integer.MAX_VALUE}) {
|
|
97
|
+
org.assertj.core.api.Assertions.assertThatThrownBy(() ->
|
|
98
|
+
new AgentProxyServiceImpl("http://py-app", new ObjectMapper(), seconds))
|
|
99
|
+
.isInstanceOf(IllegalArgumentException.class);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private static ListAppender<ILoggingEvent> logs() {
|
|
104
|
+
ch.qos.logback.classic.Logger logger =
|
|
105
|
+
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(AgentProxyServiceImpl.class);
|
|
106
|
+
ListAppender<ILoggingEvent> appender = new ListAppender<>();
|
|
107
|
+
appender.start();
|
|
108
|
+
logger.addAppender(appender);
|
|
109
|
+
return appender;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
package com.union.control.service.impl;
|
|
2
|
+
|
|
3
|
+
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
4
|
+
import com.union.control.TestJson;
|
|
5
|
+
import com.union.control.mapper.ScheduledTaskMapper;
|
|
6
|
+
import com.union.control.service.ScheduledTaskService;
|
|
7
|
+
import com.union.control.schedule.ScheduledExecutionToken;
|
|
8
|
+
import org.junit.Before;
|
|
9
|
+
import org.junit.Test;
|
|
10
|
+
import org.mockito.ArgumentCaptor;
|
|
11
|
+
|
|
12
|
+
import java.nio.charset.StandardCharsets;
|
|
13
|
+
import java.nio.file.Files;
|
|
14
|
+
import java.nio.file.Paths;
|
|
15
|
+
import java.time.Instant;
|
|
16
|
+
import java.time.LocalDateTime;
|
|
17
|
+
import java.time.ZoneId;
|
|
18
|
+
import java.util.Arrays;
|
|
19
|
+
import java.util.Collections;
|
|
20
|
+
import java.util.LinkedHashMap;
|
|
21
|
+
import java.util.List;
|
|
22
|
+
import java.util.Map;
|
|
23
|
+
|
|
24
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
25
|
+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
26
|
+
import static org.mockito.Matchers.any;
|
|
27
|
+
import static org.mockito.Matchers.anyString;
|
|
28
|
+
import static org.mockito.Matchers.contains;
|
|
29
|
+
import static org.mockito.Matchers.eq;
|
|
30
|
+
import static org.mockito.Mockito.doAnswer;
|
|
31
|
+
import static org.mockito.Mockito.mock;
|
|
32
|
+
import static org.mockito.Mockito.never;
|
|
33
|
+
import static org.mockito.Mockito.times;
|
|
34
|
+
import static org.mockito.Mockito.verify;
|
|
35
|
+
import static org.mockito.Mockito.when;
|
|
36
|
+
|
|
37
|
+
public class ScheduledTaskServiceTest {
|
|
38
|
+
private ScheduledTaskMapper mapper;
|
|
39
|
+
private JsonScheduledTaskService service;
|
|
40
|
+
private ConversationServiceImpl conversationService;
|
|
41
|
+
|
|
42
|
+
@Before
|
|
43
|
+
public void setUp() {
|
|
44
|
+
mapper = mock(ScheduledTaskMapper.class);
|
|
45
|
+
conversationService = mock(ConversationServiceImpl.class);
|
|
46
|
+
service = new JsonScheduledTaskService(
|
|
47
|
+
mapper, new ObjectMapper(), conversationService, 960, 930);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Test
|
|
51
|
+
public void timezoneMustBeAZoneInfoCompatibleTzdbIdentifier() {
|
|
52
|
+
assertThat(ScheduledTaskServiceImpl.zone("UTC")).isEqualTo(ZoneId.of("UTC"));
|
|
53
|
+
assertThat(ScheduledTaskServiceImpl.zone("Asia/Shanghai"))
|
|
54
|
+
.isEqualTo(ZoneId.of("Asia/Shanghai"));
|
|
55
|
+
for (String value : Arrays.asList("+08:00", "GMT+08:00", "UTC+08:00")) {
|
|
56
|
+
assertThatThrownBy(() -> ScheduledTaskServiceImpl.zone(value))
|
|
57
|
+
.isInstanceOf(IllegalArgumentException.class)
|
|
58
|
+
.hasMessageContaining("timezone");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Test
|
|
63
|
+
public void resolvesRawTokenByHashingInsideControl() {
|
|
64
|
+
ScheduledExecutionToken token = ScheduledExecutionToken.issue();
|
|
65
|
+
Map<String, Object> row = new LinkedHashMap<>();
|
|
66
|
+
row.put("runId", 7L);
|
|
67
|
+
when(mapper.resolveScheduledToken(token.hash())).thenReturn(row);
|
|
68
|
+
|
|
69
|
+
assertThat(service.resolveScheduledToken(
|
|
70
|
+
token.authorizationHeader().substring("Scheduled ".length())))
|
|
71
|
+
.isSameAs(row);
|
|
72
|
+
verify(mapper).resolveScheduledToken(token.hash());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Test
|
|
76
|
+
public void calculatesCronAndIntervalAfterTheReferenceInstant() {
|
|
77
|
+
Instant now = Instant.parse("2026-08-10T01:00:01Z");
|
|
78
|
+
|
|
79
|
+
assertThat(service.nextCron("0 0 9 * * MON", ZoneId.of("Asia/Shanghai"), now))
|
|
80
|
+
.isEqualTo(Instant.parse("2026-08-17T01:00:00Z"));
|
|
81
|
+
assertThat(service.nextInterval(
|
|
82
|
+
Instant.parse("2026-08-10T00:00:00Z"), 3600, now))
|
|
83
|
+
.isEqualTo(Instant.parse("2026-08-10T02:00:00Z"));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@Test
|
|
87
|
+
public void rejectsTooFrequentOrInvalidSchedules() {
|
|
88
|
+
assertThatThrownBy(() -> service.nextInterval(Instant.now(), 59, Instant.now()))
|
|
89
|
+
.isInstanceOf(IllegalArgumentException.class);
|
|
90
|
+
assertThatThrownBy(() -> service.validateCron("bad cron", ZoneId.of("UTC")))
|
|
91
|
+
.isInstanceOf(IllegalArgumentException.class);
|
|
92
|
+
assertThatThrownBy(() -> service.validateCron("* * * * * *", ZoneId.of("UTC")))
|
|
93
|
+
.isInstanceOf(IllegalArgumentException.class)
|
|
94
|
+
.hasMessageContaining("60");
|
|
95
|
+
|
|
96
|
+
service.validateCron("0 * * * * *", ZoneId.of("UTC"));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@Test
|
|
100
|
+
public void createRejectsMoreThanOneHundredRunnableTasksPerUser() {
|
|
101
|
+
when(mapper.countRunnableTasks(TestJson.USER_ID)).thenReturn(100);
|
|
102
|
+
Map<String, Object> payload = new LinkedHashMap<>();
|
|
103
|
+
payload.put("title", "超限任务");
|
|
104
|
+
payload.put("prompt", "执行分析");
|
|
105
|
+
payload.put("scheduleType", "ONCE");
|
|
106
|
+
payload.put("runAt", "2030-01-01T00:00:00Z");
|
|
107
|
+
payload.put("timezone", "UTC");
|
|
108
|
+
|
|
109
|
+
assertThatThrownBy(() -> service.create(payload))
|
|
110
|
+
.isInstanceOf(ScheduledTaskService.ConflictException.class)
|
|
111
|
+
.hasMessageContaining("100");
|
|
112
|
+
verify(mapper).lockUserTasks(TestJson.USER_ID);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@Test
|
|
116
|
+
public void createSnapshotsTheAuthenticatedOrganizationAndRole() {
|
|
117
|
+
Map<String, Object> payload = oncePayload();
|
|
118
|
+
doAnswer(invocation -> {
|
|
119
|
+
@SuppressWarnings("unchecked") Map<String, Object> task =
|
|
120
|
+
(Map<String, Object>) invocation.getArguments()[0];
|
|
121
|
+
task.put("id", 7L);
|
|
122
|
+
return 1;
|
|
123
|
+
}).when(mapper).insertTask(org.mockito.Matchers.<Map<String, Object>>any());
|
|
124
|
+
when(mapper.findTaskDetail(7L, TestJson.USER_ID))
|
|
125
|
+
.thenReturn(Collections.<String, Object>singletonMap("id", 7L));
|
|
126
|
+
|
|
127
|
+
service.create(payload);
|
|
128
|
+
|
|
129
|
+
ArgumentCaptor<Map> inserted = ArgumentCaptor.forClass(Map.class);
|
|
130
|
+
verify(mapper).insertTask(inserted.capture());
|
|
131
|
+
assertThat(inserted.getValue())
|
|
132
|
+
.containsEntry("userId", TestJson.USER_ID)
|
|
133
|
+
.containsEntry("orgCode", TestJson.ORG_CODE)
|
|
134
|
+
.containsEntry("roleId", TestJson.ROLE_ID);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@Test
|
|
138
|
+
public void updateValidatesAndPersistsOnlyTheOwnedTaskDefinition() {
|
|
139
|
+
Map<String, Object> owned = new LinkedHashMap<>();
|
|
140
|
+
owned.put("status", "ACTIVE");
|
|
141
|
+
when(mapper.findTaskOwner(7L, TestJson.USER_ID, true)).thenReturn(owned);
|
|
142
|
+
Map<String, Object> payload = new LinkedHashMap<>();
|
|
143
|
+
payload.put("taskId", 7L);
|
|
144
|
+
payload.put("title", "新标题");
|
|
145
|
+
payload.put("prompt", "新的可信任务提示");
|
|
146
|
+
payload.put("scheduleType", "ONCE");
|
|
147
|
+
payload.put("runAt", "2099-08-12T15:00:00+08:00");
|
|
148
|
+
payload.put("timezone", "Asia/Shanghai");
|
|
149
|
+
when(mapper.updateTask(org.mockito.Matchers.<Map<String, Object>>any())).thenReturn(1);
|
|
150
|
+
when(mapper.findTaskDetail(7L, TestJson.USER_ID)).thenReturn(Collections.<String, Object>singletonMap("id", 7L));
|
|
151
|
+
|
|
152
|
+
service.update(payload);
|
|
153
|
+
|
|
154
|
+
ArgumentCaptor<Map> updated = ArgumentCaptor.forClass(Map.class);
|
|
155
|
+
verify(mapper).updateTask(updated.capture());
|
|
156
|
+
assertThat(updated.getValue())
|
|
157
|
+
.containsEntry("taskId", 7L)
|
|
158
|
+
.containsEntry("userId", TestJson.USER_ID)
|
|
159
|
+
.containsEntry("orgCode", TestJson.ORG_CODE)
|
|
160
|
+
.containsEntry("roleId", TestJson.ROLE_ID)
|
|
161
|
+
.containsEntry("title", "新标题")
|
|
162
|
+
.containsEntry("prompt", "新的可信任务提示")
|
|
163
|
+
.containsEntry("scheduleType", "ONCE")
|
|
164
|
+
.containsEntry("timezone", "Asia/Shanghai");
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@Test
|
|
168
|
+
public void updateRejectsTasksNotOwnedByTheCallerBeforeWriting() {
|
|
169
|
+
Map<String, Object> payload = new LinkedHashMap<>();
|
|
170
|
+
payload.put("taskId", 7L);
|
|
171
|
+
when(mapper.findTaskOwner(7L, TestJson.USER_ID, true)).thenReturn(null);
|
|
172
|
+
|
|
173
|
+
assertThatThrownBy(() -> service.update(payload))
|
|
174
|
+
.isInstanceOf(ScheduledTaskService.NotFoundException.class);
|
|
175
|
+
|
|
176
|
+
verify(mapper, never()).updateTask(org.mockito.Matchers.<Map<String, Object>>any());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@Test
|
|
180
|
+
public void runDetailScopesTheQueryToTheAuthenticatedOwner() {
|
|
181
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, false)).thenReturn(null);
|
|
182
|
+
assertThatThrownBy(() -> service.runDetail(7))
|
|
183
|
+
.isInstanceOf(ScheduledTaskService.NotFoundException.class);
|
|
184
|
+
verify(mapper).findOwnedRun(7L, TestJson.USER_ID, false);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
@Test
|
|
188
|
+
public void runDetailSelectsAndReturnsTheStoredResultContent() {
|
|
189
|
+
Map<String, Object> run = run("SUCCEEDED");
|
|
190
|
+
run.put("resultPayload", "{\"content\":\"detail-only\"}");
|
|
191
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, false)).thenReturn(run);
|
|
192
|
+
|
|
193
|
+
@SuppressWarnings("unchecked") Map<String, Object> data = (Map<String, Object>)
|
|
194
|
+
service.runDetail(7).get("data");
|
|
195
|
+
|
|
196
|
+
assertThat(data).containsEntry("resultContent", "detail-only")
|
|
197
|
+
.doesNotContainKey("resultPayload");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
@Test
|
|
201
|
+
public void unreadAcceptsMysqlBooleanReadFlag() {
|
|
202
|
+
Map<String, Object> run = run("SUCCEEDED");
|
|
203
|
+
run.put("readFlag", Boolean.FALSE);
|
|
204
|
+
run.put("resultPayload", "{\"content\":\"must-not-be-listed\"}");
|
|
205
|
+
when(mapper.countUnread(TestJson.USER_ID)).thenReturn(1L);
|
|
206
|
+
when(mapper.findUnread(TestJson.USER_ID)).thenReturn(Collections.singletonList(run));
|
|
207
|
+
|
|
208
|
+
@SuppressWarnings("unchecked") Map<String, Object> data = (Map<String, Object>)
|
|
209
|
+
service.unread().get("data");
|
|
210
|
+
@SuppressWarnings("unchecked") List<Map<String, Object>> items =
|
|
211
|
+
(List<Map<String, Object>>) data.get("items");
|
|
212
|
+
|
|
213
|
+
assertThat(items).hasSize(1);
|
|
214
|
+
assertThat(items.get(0).get("readFlag")).isEqualTo(false);
|
|
215
|
+
assertThat(items.get(0)).doesNotContainKeys("resultPayload", "resultContent");
|
|
216
|
+
verify(mapper).findUnread(TestJson.USER_ID);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@Test
|
|
220
|
+
public void runListDoesNotSelectOrExposeResultPayload() {
|
|
221
|
+
Map<String, Object> task = new LinkedHashMap<>();
|
|
222
|
+
task.put("id", 3L);
|
|
223
|
+
when(mapper.findTaskOwner(3L, TestJson.USER_ID, false)).thenReturn(task);
|
|
224
|
+
when(mapper.countRuns(3L, TestJson.USER_ID)).thenReturn(1L);
|
|
225
|
+
Map<String, Object> run = run("SUCCEEDED");
|
|
226
|
+
run.put("resultPayload", "{\"content\":\"must-not-be-listed\"}");
|
|
227
|
+
when(mapper.findRuns(3L, TestJson.USER_ID, 20, 0))
|
|
228
|
+
.thenReturn(Collections.singletonList(run));
|
|
229
|
+
|
|
230
|
+
@SuppressWarnings("unchecked") Map<String, Object> data = (Map<String, Object>)
|
|
231
|
+
service.runs(3, 1, 20).get("data");
|
|
232
|
+
@SuppressWarnings("unchecked") List<Map<String, Object>> items =
|
|
233
|
+
(List<Map<String, Object>>) data.get("items");
|
|
234
|
+
|
|
235
|
+
assertThat(items).hasSize(1);
|
|
236
|
+
assertThat(items.get(0)).doesNotContainKeys("resultPayload", "resultContent");
|
|
237
|
+
verify(mapper).findRuns(3L, TestJson.USER_ID, 20, 0);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@Test
|
|
241
|
+
public void openingAnAlreadyMaterializedRunIsIdempotent() {
|
|
242
|
+
Map<String, Object> run = run("SUCCEEDED");
|
|
243
|
+
run.put("resultConversationId", "scheduled-7");
|
|
244
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, true)).thenReturn(run);
|
|
245
|
+
|
|
246
|
+
@SuppressWarnings("unchecked") Map<String, Object> data = (Map<String, Object>)
|
|
247
|
+
service.open(7).get("data");
|
|
248
|
+
|
|
249
|
+
assertThat(data.get("conversationId")).isEqualTo("scheduled-7");
|
|
250
|
+
verify(mapper).markRunRead(7L);
|
|
251
|
+
verify(conversationService, never()).materializeCompletedConversation(
|
|
252
|
+
anyString(), anyString(), anyString(), anyString(), anyString());
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@Test
|
|
256
|
+
public void onlyTerminalRunsCanBeOpened() {
|
|
257
|
+
for (String status : Arrays.asList("PENDING", "RUNNING")) {
|
|
258
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, true)).thenReturn(run(status));
|
|
259
|
+
|
|
260
|
+
assertThatThrownBy(() -> service.open(7))
|
|
261
|
+
.isInstanceOf(ScheduledTaskService.ConflictException.class)
|
|
262
|
+
.hasMessageContaining("尚未结束");
|
|
263
|
+
}
|
|
264
|
+
verify(conversationService, never()).materializeCompletedConversation(
|
|
265
|
+
anyString(), anyString(), anyString(), anyString(), anyString());
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
@Test
|
|
269
|
+
public void openingScopesTheLockedRunToTheAuthenticatedOwner() {
|
|
270
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, true)).thenReturn(null);
|
|
271
|
+
|
|
272
|
+
assertThatThrownBy(() -> service.open(7))
|
|
273
|
+
.isInstanceOf(ScheduledTaskService.NotFoundException.class);
|
|
274
|
+
|
|
275
|
+
verify(mapper).findOwnedRun(7L, TestJson.USER_ID, true);
|
|
276
|
+
verify(conversationService, never()).materializeCompletedConversation(
|
|
277
|
+
anyString(), anyString(), anyString(), anyString(), anyString());
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
@Test
|
|
281
|
+
public void openingCreatesTheExistingAguiConversationModelOnce() throws Exception {
|
|
282
|
+
Map<String, Object> run = run("SUCCEEDED");
|
|
283
|
+
run.put("title", "日报");
|
|
284
|
+
run.put("prompt", "可信任务提示");
|
|
285
|
+
run.put("resultPayload", new ObjectMapper().writeValueAsString(result()));
|
|
286
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, true)).thenReturn(run);
|
|
287
|
+
when(conversationService.materializeCompletedConversation(anyString(), anyString(),
|
|
288
|
+
anyString(), anyString(), anyString())).thenReturn("scheduled-7-shared");
|
|
289
|
+
|
|
290
|
+
@SuppressWarnings("unchecked") Map<String, Object> data = (Map<String, Object>)
|
|
291
|
+
service.open(7).get("data");
|
|
292
|
+
|
|
293
|
+
assertThat(data.get("conversationId")).isEqualTo("scheduled-7-shared");
|
|
294
|
+
verify(conversationService).materializeCompletedConversation(
|
|
295
|
+
TestJson.USER_ID, "日报", "可信任务提示", "日报内容", "ScheduledTaskAgent");
|
|
296
|
+
verify(mapper).attachConversation(7L, "scheduled-7-shared");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
@Test
|
|
300
|
+
public void openingAFailedRunCreatesAFollowUpConversationWithTheSafeFailure() {
|
|
301
|
+
Map<String, Object> run = run("FAILED");
|
|
302
|
+
run.put("title", "失败任务");
|
|
303
|
+
run.put("prompt", "执行可信任务");
|
|
304
|
+
run.put("errorMessage", "定时任务执行失败");
|
|
305
|
+
when(mapper.findOwnedRun(7L, TestJson.USER_ID, true)).thenReturn(run);
|
|
306
|
+
when(conversationService.materializeCompletedConversation(anyString(), anyString(),
|
|
307
|
+
anyString(), anyString(), anyString())).thenReturn("scheduled-7-failed");
|
|
308
|
+
|
|
309
|
+
service.open(7);
|
|
310
|
+
|
|
311
|
+
verify(conversationService).materializeCompletedConversation(
|
|
312
|
+
TestJson.USER_ID, "失败任务", "执行可信任务", "定时任务执行失败", "ScheduledTaskAgent");
|
|
313
|
+
verify(mapper).attachConversation(7L, "scheduled-7-failed");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
@Test
|
|
317
|
+
public void claimUsesSkipLockedAndSchemaEnforcesOccurrenceDeduplication() throws Exception {
|
|
318
|
+
String source = new String(Files.readAllBytes(Paths.get(
|
|
319
|
+
"src/main/resources/mapper/ScheduledTaskMapper.xml")),
|
|
320
|
+
StandardCharsets.UTF_8);
|
|
321
|
+
String schema = new String(Files.readAllBytes(Paths.get(
|
|
322
|
+
"src/main/resources/schema.sql")), StandardCharsets.UTF_8);
|
|
323
|
+
|
|
324
|
+
assertThat(source).contains("FOR UPDATE SKIP LOCKED");
|
|
325
|
+
assertThat(source).contains("r.status IN ('SUCCEEDED','FAILED') AND r.read_flag=0");
|
|
326
|
+
assertThat(schema).contains(
|
|
327
|
+
"UNIQUE KEY `uk_scheduled_run_occurrence` (`task_id`, `scheduled_at`)",
|
|
328
|
+
"`role_id` VARCHAR(64) COLLATE utf8mb4_bin NOT NULL");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@Test
|
|
332
|
+
public void claimingAOnceTaskExhaustsItBeforeTheRunIsDispatched() {
|
|
333
|
+
Map<String, Object> task = new LinkedHashMap<>();
|
|
334
|
+
task.put("id", 3L);
|
|
335
|
+
task.put("scheduleType", "ONCE");
|
|
336
|
+
task.put("nextRunAt", java.sql.Timestamp.from(Instant.parse("2026-08-11T00:00:00Z")));
|
|
337
|
+
when(mapper.findDueTask()).thenReturn(task);
|
|
338
|
+
doAnswer(invocation -> {
|
|
339
|
+
@SuppressWarnings("unchecked") Map<String, Object> run =
|
|
340
|
+
(Map<String, Object>) invocation.getArguments()[0];
|
|
341
|
+
run.put("id", 7L);
|
|
342
|
+
return 1;
|
|
343
|
+
}).when(mapper).insertRun(org.mockito.Matchers.<Map<String, Object>>any());
|
|
344
|
+
|
|
345
|
+
assertThat(service.claimDueRun()).isEqualTo(7L);
|
|
346
|
+
|
|
347
|
+
verify(mapper).completeOnceTask(3L);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@Test
|
|
351
|
+
public void convertsMysqlLocalDateTimeAsUtc() {
|
|
352
|
+
assertThat(ScheduledTaskServiceImpl.instant(
|
|
353
|
+
LocalDateTime.of(2026, 8, 10, 16, 45, 49, 780000000)))
|
|
354
|
+
.isEqualTo(Instant.parse("2026-08-10T16:45:49.780Z"));
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@Test
|
|
358
|
+
public void writesDatabaseDateTimesAsUtcLiteralsWithoutJvmTimezoneConversion() {
|
|
359
|
+
assertThat(ScheduledTaskServiceImpl.databaseDateTime(
|
|
360
|
+
Instant.parse("2026-08-11T04:52:30Z")))
|
|
361
|
+
.isEqualTo("2026-08-11 04:52:30.000");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@Test
|
|
365
|
+
public void scheduledMapperNeverOwnsNormalConversationPersistence() throws Exception {
|
|
366
|
+
String scheduledMapper = new String(Files.readAllBytes(Paths.get(
|
|
367
|
+
"src/main/resources/mapper/ScheduledTaskMapper.xml")),
|
|
368
|
+
StandardCharsets.UTF_8);
|
|
369
|
+
assertThat(scheduledMapper)
|
|
370
|
+
.doesNotContain("INSERT INTO ai_conversation")
|
|
371
|
+
.doesNotContain("INSERT INTO ai_agent_execution")
|
|
372
|
+
.doesNotContain("INSERT INTO ai_conversation_message")
|
|
373
|
+
.contains("SET result_conversation_id=#{conversationId},read_flag=1");
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
@Test
|
|
377
|
+
public void storesOnlyTheResultFieldsNeededToOpenAConversation() throws Exception {
|
|
378
|
+
Map<String, Object> run = run("RUNNING");
|
|
379
|
+
when(mapper.findRunForUpdate(7L)).thenReturn(run);
|
|
380
|
+
Map<String, Object> result = result();
|
|
381
|
+
result.put("providerSecret", "must-not-be-stored");
|
|
382
|
+
ArgumentCaptor<String> stored = ArgumentCaptor.forClass(String.class);
|
|
383
|
+
|
|
384
|
+
service.completeFromProxy(7, result);
|
|
385
|
+
|
|
386
|
+
verify(mapper).completeRun(eq(7L), stored.capture());
|
|
387
|
+
String storedJson = stored.getValue();
|
|
388
|
+
@SuppressWarnings("unchecked") Map<String, Object> decoded =
|
|
389
|
+
new ObjectMapper().readValue(storedJson, Map.class);
|
|
390
|
+
assertThat(decoded).containsEntry("content", "日报内容")
|
|
391
|
+
.containsEntry("agentName", "ScheduledTaskAgent")
|
|
392
|
+
.doesNotContainKeys("messages", "providerSecret");
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private static Map<String, Object> run(String status) {
|
|
396
|
+
Map<String, Object> run = new LinkedHashMap<>();
|
|
397
|
+
run.put("id", 7L);
|
|
398
|
+
run.put("taskId", 3L);
|
|
399
|
+
run.put("status", status);
|
|
400
|
+
run.put("readFlag", 0);
|
|
401
|
+
run.put("resultConversationId", null);
|
|
402
|
+
return run;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private static Map<String, Object> oncePayload() {
|
|
406
|
+
Map<String, Object> payload = new LinkedHashMap<>();
|
|
407
|
+
payload.put("title", "日报任务");
|
|
408
|
+
payload.put("prompt", "生成日报");
|
|
409
|
+
payload.put("scheduleType", "ONCE");
|
|
410
|
+
payload.put("runAt", "2099-01-01T00:00:00Z");
|
|
411
|
+
payload.put("timezone", "UTC");
|
|
412
|
+
return payload;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private static Map<String, Object> result() {
|
|
416
|
+
Map<String, Object> first = new LinkedHashMap<>();
|
|
417
|
+
first.put("id", "user-1");
|
|
418
|
+
first.put("role", "user");
|
|
419
|
+
first.put("content", "生成日报");
|
|
420
|
+
Map<String, Object> second = new LinkedHashMap<>();
|
|
421
|
+
second.put("id", "assistant-1");
|
|
422
|
+
second.put("role", "assistant");
|
|
423
|
+
second.put("content", "日报内容");
|
|
424
|
+
Map<String, Object> result = new LinkedHashMap<>();
|
|
425
|
+
result.put("content", "日报内容");
|
|
426
|
+
result.put("agentName", "ScheduledTaskAgent");
|
|
427
|
+
result.put("messages", Arrays.asList(first, second));
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
private static final class JsonScheduledTaskService extends ScheduledTaskServiceImpl {
|
|
431
|
+
JsonScheduledTaskService(ScheduledTaskMapper mapper, ObjectMapper json,
|
|
432
|
+
ConversationServiceImpl conversations, int ignoredTtl, int ignoredMax) {
|
|
433
|
+
super(mapper, json, conversations);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
Map<String, Object> create(Map<String, Object> value) {
|
|
437
|
+
return super.create(TestJson.request(value));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
Map<String, Object> update(Map<String, Object> value) {
|
|
441
|
+
return super.update(TestJson.request(value));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
Map<String, Object> list(String keyword, String status, int page, int pageSize) {
|
|
445
|
+
return super.list(TestJson.request("keyword", keyword, "status", status,
|
|
446
|
+
"page", page, "pageSize", pageSize));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
Map<String, Object> detail(long taskId) {
|
|
450
|
+
return super.detail(TestJson.request("taskId", taskId));
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
Map<String, Object> runs(long taskId, int page, int pageSize) {
|
|
454
|
+
return super.runs(TestJson.request("taskId", taskId, "page", page,
|
|
455
|
+
"pageSize", pageSize));
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
Map<String, Object> runDetail(long runId) {
|
|
459
|
+
return super.runDetail(TestJson.request("runId", runId));
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
Map<String, Object> unread() {
|
|
463
|
+
return super.unread(TestJson.request());
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
Map<String, Object> start(long taskId) {
|
|
467
|
+
return super.start(TestJson.request("taskId", taskId));
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
Map<String, Object> pause(long taskId) {
|
|
471
|
+
return super.pause(TestJson.request("taskId", taskId));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
Map<String, Object> discard(long taskId) {
|
|
475
|
+
return super.discard(TestJson.request("taskId", taskId));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
Map<String, Object> open(long runId) {
|
|
479
|
+
return super.open(TestJson.request("runId", runId));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
}
|