mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
refactor(action): support built-in actions
This commit is contained in:
@@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import work.slhaf.partner.core.action.entity.MetaAction;
|
||||
import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
||||
import work.slhaf.partner.module.modules.action.builtin.BuiltinActionRegistry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
@@ -843,6 +844,53 @@ public class LocalRunnerClientTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoRunWithBuiltin(@TempDir Path tempDir) {
|
||||
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
|
||||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
LocalRunnerClient client = new LocalRunnerClient(existedMetaActions, executor, tempDir.toString());
|
||||
BuiltinActionRegistry registry = new BuiltinActionRegistry() {
|
||||
@Override
|
||||
protected List<BuiltinActionDefinition> buildDefinitions() {
|
||||
return List.of(
|
||||
definition("echo", buildMetaActionInfo("echo"), params -> params.get("value"))
|
||||
);
|
||||
}
|
||||
};
|
||||
client.setBuiltinActionRegistry(registry);
|
||||
registry.getDefinitions().put(
|
||||
"builtin::echo",
|
||||
BuiltinActionRegistry.definition("echo", buildMetaActionInfo("echo"), params -> params.get("value"))
|
||||
);
|
||||
|
||||
try {
|
||||
MetaAction metaAction = buildMetaAction(MetaAction.Type.BUILTIN, "builtin", "echo", Map.of("value", "ok"));
|
||||
RunnerClient.RunnerResponse response = client.doRun(metaAction);
|
||||
Assertions.assertNotNull(response);
|
||||
Assertions.assertTrue(response.isOk());
|
||||
Assertions.assertEquals("ok", response.getData());
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoRunWithBuiltinMissingRegistry(@TempDir Path tempDir) {
|
||||
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
|
||||
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
|
||||
LocalRunnerClient client = new LocalRunnerClient(existedMetaActions, executor, tempDir.toString());
|
||||
|
||||
try {
|
||||
MetaAction metaAction = buildMetaAction(MetaAction.Type.BUILTIN, "builtin", "echo", Map.of());
|
||||
RunnerClient.RunnerResponse response = client.doRun(metaAction);
|
||||
Assertions.assertNotNull(response);
|
||||
Assertions.assertFalse(response.isOk());
|
||||
Assertions.assertEquals("BuiltinActionRegistry 未初始化", response.getData());
|
||||
} finally {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoRunWithMcpLoadedFromCommonConfig(@TempDir Path tempDir) throws IOException, InterruptedException {
|
||||
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package work.slhaf.partner.module.modules.action.builtin;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import work.slhaf.partner.core.action.ActionCapability;
|
||||
import work.slhaf.partner.core.action.ActionCore;
|
||||
import work.slhaf.partner.core.action.entity.MetaActionInfo;
|
||||
import work.slhaf.partner.core.action.exception.MetaActionNotFoundException;
|
||||
import work.slhaf.partner.core.action.runner.RunnerClient;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class BuiltinActionRegistryTest {
|
||||
|
||||
private static void injectActionCapability(BuiltinActionRegistry registry, ActionCapability actionCapability) throws Exception {
|
||||
Field field = BuiltinActionRegistry.class.getDeclaredField("actionCapability");
|
||||
field.setAccessible(true);
|
||||
field.set(registry, actionCapability);
|
||||
}
|
||||
|
||||
private static Map<String, BuiltinActionRegistry.BuiltinActionDefinition> indexDefinitions(
|
||||
List<BuiltinActionRegistry.BuiltinActionDefinition> definitions
|
||||
) {
|
||||
Map<String, BuiltinActionRegistry.BuiltinActionDefinition> map = new HashMap<>();
|
||||
for (BuiltinActionRegistry.BuiltinActionDefinition definition : definitions) {
|
||||
map.put(definition.actionKey(), definition);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static MetaActionInfo buildMetaActionInfo(String description) {
|
||||
MetaActionInfo info = new MetaActionInfo();
|
||||
info.setDescription(description);
|
||||
info.setParams(new HashMap<>());
|
||||
return info;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInitRegistersMetaActionsAndMountsRunner() throws Exception {
|
||||
ActionCapability actionCapability = mock(ActionCapability.class);
|
||||
RunnerClient runnerClient = mock(RunnerClient.class);
|
||||
when(actionCapability.runnerClient()).thenReturn(runnerClient);
|
||||
|
||||
BuiltinActionRegistry registry = new TestRegistry(List.of(
|
||||
BuiltinActionRegistry.definition("echo", buildMetaActionInfo("echo"), params -> params.get("value"))
|
||||
));
|
||||
injectActionCapability(registry, actionCapability);
|
||||
|
||||
registry.init();
|
||||
|
||||
verify(actionCapability).registerMetaActions(argThat(metaActions ->
|
||||
metaActions.containsKey("builtin::echo")
|
||||
&& "echo".equals(metaActions.get("builtin::echo").getDescription())
|
||||
));
|
||||
verify(runnerClient).setBuiltinActionRegistry(registry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallReturnsStringifiedResults() {
|
||||
BuiltinActionRegistry registry = new TestRegistry(List.of(
|
||||
BuiltinActionRegistry.definition("echo", buildMetaActionInfo("echo"), params -> params.get("value")),
|
||||
BuiltinActionRegistry.definition("json", buildMetaActionInfo("json"), params -> Map.of("ok", true)),
|
||||
BuiltinActionRegistry.definition("nil", buildMetaActionInfo("nil"), params -> null)
|
||||
));
|
||||
|
||||
registry.getDefinitions().putAll(indexDefinitions(registry.buildDefinitions()));
|
||||
|
||||
Assertions.assertEquals("hello", registry.call("builtin::echo", Map.of("value", "hello")));
|
||||
Assertions.assertEquals("{\"ok\":true}", registry.call("builtin::json", Map.of()));
|
||||
Assertions.assertEquals("null", registry.call("builtin::nil", Map.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallThrowsWhenMissingDefinition() {
|
||||
BuiltinActionRegistry registry = new TestRegistry(List.of());
|
||||
Assertions.assertThrows(MetaActionNotFoundException.class, () -> registry.call("builtin::missing", Map.of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCallPropagatesInvokerFailure() {
|
||||
BuiltinActionRegistry registry = new TestRegistry(List.of(
|
||||
BuiltinActionRegistry.definition("boom", buildMetaActionInfo("boom"), params -> {
|
||||
throw new IllegalStateException("boom");
|
||||
})
|
||||
));
|
||||
registry.getDefinitions().putAll(indexDefinitions(registry.buildDefinitions()));
|
||||
|
||||
IllegalStateException exception = Assertions.assertThrows(IllegalStateException.class,
|
||||
() -> registry.call("builtin::boom", Map.of()));
|
||||
Assertions.assertEquals("boom", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testActionCoreLoadsBuiltinMetaAction() throws Exception {
|
||||
ActionCore actionCore = new ActionCore();
|
||||
try {
|
||||
actionCore.registerMetaActions(Map.of("builtin::echo", buildMetaActionInfo("echo")));
|
||||
|
||||
Assertions.assertTrue(actionCore.listAvailableMetaActions().containsKey("builtin::echo"));
|
||||
Assertions.assertEquals("echo", actionCore.loadMetaActionInfo("builtin::echo").getDescription());
|
||||
Assertions.assertEquals("builtin::echo", actionCore.loadMetaAction("builtin::echo").getKey());
|
||||
Assertions.assertEquals(ActionCore.BUILTIN_LOCATION, actionCore.loadMetaAction("builtin::echo").getLocation());
|
||||
} finally {
|
||||
actionCore.getExecutor(ActionCore.ExecutorType.PLATFORM).shutdownNow();
|
||||
actionCore.getExecutor(ActionCore.ExecutorType.VIRTUAL).shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestRegistry extends BuiltinActionRegistry {
|
||||
private final List<BuiltinActionDefinition> definitions;
|
||||
|
||||
private TestRegistry(List<BuiltinActionDefinition> definitions) {
|
||||
this.definitions = definitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BuiltinActionDefinition> buildDefinitions() {
|
||||
return definitions;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user