fix(LocalRunnerClient): harden doRun branches and add tests

This commit is contained in:
2026-01-16 23:28:46 +08:00
parent 8ead306b7b
commit 420d51af15
2 changed files with 108 additions and 6 deletions

View File

@@ -222,6 +222,10 @@ public class LocalRunnerClient extends RunnerClient {
return response; return response;
} }
String[] commands = SystemExecHelper.buildCommands(ext, metaAction.getParams(), file.getAbsolutePath()); String[] commands = SystemExecHelper.buildCommands(ext, metaAction.getParams(), file.getAbsolutePath());
if (commands == null || commands.length == 0) {
response.setOk(false);
response.setData("不支持的文件类型: " + file.getName());
}
SystemExecHelper.Result execResult = SystemExecHelper.exec(commands); SystemExecHelper.Result execResult = SystemExecHelper.exec(commands);
response.setOk(execResult.isOk()); response.setOk(execResult.isOk());
response.setData(execResult.getTotal()); response.setData(execResult.getTotal());
@@ -236,7 +240,12 @@ public class LocalRunnerClient extends RunnerClient {
.arguments(metaAction.getParams()) .arguments(metaAction.getParams())
.build(); .build();
McpSchema.CallToolResult callToolResult = mcpClient.callTool(callToolRequest); McpSchema.CallToolResult callToolResult = mcpClient.callTool(callToolRequest);
response.setOk(callToolResult.isError()); val callToolResultError = callToolResult.isError();
if (callToolResultError == null) {
response.setOk(false);
} else {
response.setOk(!callToolResultError);
}
response.setData(callToolResult.structuredContent().toString()); response.setData(callToolResult.structuredContent().toString());
return response; return response;
} }
@@ -1234,7 +1243,7 @@ public class LocalRunnerClient extends RunnerClient {
val httpKeys = Set.of("uri", "endpoint", "headers"); val httpKeys = Set.of("uri", "endpoint", "headers");
val httpKey = Set.of("url"); val httpKey = Set.of("url");
val keys = mcp.keySet(); val keys = mcp.keySet();
val timeout = mcp.getInt("timeout", 10); val timeout = mcp.getInt("timeout", 30);
if (keys.equals(stdioKeys)) { if (keys.equals(stdioKeys)) {
val command = mcp.getStr("command"); val command = mcp.getStr("command");

View File

@@ -5,16 +5,15 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; 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.core.action.entity.MetaActionInfo;
import work.slhaf.partner.core.action.entity.MetaActionType;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@@ -177,6 +176,15 @@ public class LocalRunnerClientTest {
+ " \"env\": {}\n" + " \"env\": {}\n"
+ " }"; + " }";
} }
static MetaAction buildMetaAction(MetaActionType type, String location, String name, Map<String, Object> params) {
MetaAction metaAction = new MetaAction();
metaAction.setType(type);
metaAction.setLocation(location);
metaAction.setName(name);
metaAction.setParams(params);
return metaAction;
}
} }
@Nested @Nested
@@ -762,4 +770,89 @@ public class LocalRunnerClientTest {
} }
} }
@Nested
class DoRunTest {
@Test
void testDoRunWithOriginUnknownExt(@TempDir Path tempDir) throws IOException {
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
LocalRunnerClient client = new LocalRunnerClient(existedMetaActions, executor, tempDir.toString());
try {
Path script = tempDir.resolve("run");
Files.writeString(script, "echo ok\n");
MetaAction metaAction = buildMetaAction(MetaActionType.ORIGIN, script.toString(), "run", Map.of());
RunnerClient.RunnerResponse response = client.doRun(metaAction);
Assertions.assertNotNull(response);
Assertions.assertFalse(response.isOk());
Assertions.assertEquals("未知文件类型", response.getData());
} finally {
executor.shutdownNow();
}
}
@Test
void testDoRunWithOriginScriptSuccess(@TempDir Path tempDir) throws IOException {
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
LocalRunnerClient client = new LocalRunnerClient(existedMetaActions, executor, tempDir.toString());
try {
Path script = tempDir.resolve("run.sh");
Files.writeString(script, "echo ok\n");
MetaAction metaAction = buildMetaAction(MetaActionType.ORIGIN, script.toString(), "run", Map.of());
RunnerClient.RunnerResponse response = client.doRun(metaAction);
Assertions.assertNotNull(response);
Assertions.assertTrue(response.isOk());
Assertions.assertTrue(response.getData().contains("ok"));
} finally {
executor.shutdownNow();
}
}
@Test
void testDoRunWithMcpMissingClient(@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(MetaActionType.MCP, "missing-client", "missing-tool", Map.of());
RunnerClient.RunnerResponse response = client.doRun(metaAction);
Assertions.assertNotNull(response);
Assertions.assertFalse(response.isOk());
} finally {
executor.shutdownNow();
}
}
@Test
void testDoRunWithMcpLoadedFromCommonConfig(@TempDir Path tempDir) throws IOException, InterruptedException {
ConcurrentHashMap<String, MetaActionInfo> existedMetaActions = new ConcurrentHashMap<>();
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
Path mcpDir = tempDir.resolve("action").resolve("mcp");
Files.createDirectories(mcpDir);
Path configFile = mcpDir.resolve("servers.json");
String config = buildCommonMcpConfig(
buildStdioServerEntry("playwright", "@playwright/mcp@latest")
);
writeCommonMcpConfig(configFile, config);
LocalRunnerClient client = new LocalRunnerClient(existedMetaActions, executor, tempDir.toString());
try {
waitForCondition(() -> hasActionKey(existedMetaActions, key -> key.startsWith("playwright::")), 20000);
Assertions.assertTrue(hasActionKey(existedMetaActions, key -> key.startsWith("playwright::")));
MetaAction metaAction = buildMetaAction(MetaActionType.MCP, "playwright", "browser_navigate", Map.of("url", "https://deepwiki.com/microsoft/vscode"));
client.run(metaAction);
Assertions.assertNotEquals(MetaAction.ResultStatus.WAITING, metaAction.getResult().getStatus());
} finally {
executor.shutdownNow();
}
}
}
} }