feat(runner): implement builtin command session actions with start/inspect/read/cancel/overview

This commit is contained in:
2026-03-18 23:00:56 +08:00
parent 7d9ec976e3
commit 12368ded53
4 changed files with 478 additions and 17 deletions

View File

@@ -90,4 +90,31 @@ class CommandExecutionServiceTest {
Assertions.assertEquals(List.of("out"), result.getResultList());
Assertions.assertEquals("out", result.getTotal());
}
@Test
void testCreateSessionTaskCollectsStdoutAndStderr() throws Exception {
CommandExecutionService.CommandSession session = service.createSessionTask(
"sh", "-lc", "printf 'hello\\nworld\\n'; printf 'oops\\n' >&2"
);
session.getProcess().waitFor();
waitForBufferContains(session.getStdoutBuffer(), "world");
waitForBufferContains(session.getStderrBuffer(), "oops");
Assertions.assertEquals("hello\nworld", session.getStdoutBuffer().toString());
Assertions.assertEquals("oops", session.getStderrBuffer().toString());
}
private void waitForBufferContains(StringBuilder buffer, String expected) throws InterruptedException {
long deadline = System.currentTimeMillis() + 2000;
while (System.currentTimeMillis() < deadline) {
synchronized (buffer) {
if (buffer.toString().contains(expected)) {
return;
}
}
Thread.sleep(20);
}
Assertions.fail("buffer did not contain expected text: " + expected);
}
}

View File

@@ -0,0 +1,84 @@
package work.slhaf.partner.module.modules.action.builtin;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Map;
class BuiltinCommandActionManagerTest {
@Test
void testStartInspectReadAndOverview() throws Exception {
BuiltinCommandActionManager manager = new BuiltinCommandActionManager();
String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of(
"desc", "demo-session",
"arg", "sh",
"arg1", "-lc",
"arg2", "printf 'hello\\nworld\\n'; printf 'oops\\n' >&2"
));
String executionId = JSONObject.parseObject(startResult).getString("executionId");
Assertions.assertNotNull(executionId);
JSONObject inspect = waitForInspectExit(manager, executionId);
Assertions.assertEquals("demo-session", inspect.getString("desc"));
Assertions.assertEquals(0, inspect.getInteger("exitCode"));
Assertions.assertTrue(inspect.getInteger("stdoutSize") > 0);
Assertions.assertTrue(inspect.getInteger("stderrSize") > 0);
Assertions.assertTrue(inspect.getString("stdoutSummary").contains("hello"));
Assertions.assertTrue(inspect.getString("stderrSummary").contains("oops"));
JSONObject read = JSONObject.parseObject(manager.buildCommandReadDefinition().invoker().apply(Map.of(
"id", executionId,
"limit", 5
)));
Assertions.assertEquals("stdout", read.getString("stream"));
Assertions.assertEquals(0, read.getIntValue("offset"));
Assertions.assertEquals(5, read.getIntValue("nextOffset"));
Assertions.assertTrue(read.getBooleanValue("contentTruncated"));
Assertions.assertEquals("hello", read.getString("content"));
JSONObject overview = JSONObject.parseObject(manager.buildCommandOverviewDefinition().invoker().apply(Map.of()));
JSONArray result = overview.getJSONArray("result");
Assertions.assertTrue(result.stream().map(item -> (JSONObject) item)
.anyMatch(item -> executionId.equals(item.getString("executionId"))));
}
@Test
void testCancelStopsBackgroundCommand() throws Exception {
BuiltinCommandActionManager manager = new BuiltinCommandActionManager();
String startResult = manager.buildCommandStartDefinition().invoker().apply(Map.of(
"desc", "sleep-session",
"arg", "sh",
"arg1", "-lc",
"arg2", "sleep 5"
));
String executionId = JSONObject.parseObject(startResult).getString("executionId");
JSONObject cancel = JSONObject.parseObject(manager.buildCommandCancelDefinition().invoker().apply(Map.of(
"id", executionId
)));
Assertions.assertEquals(executionId, cancel.getString("executionId"));
Assertions.assertTrue(cancel.getBooleanValue("ok"));
JSONObject inspect = waitForInspectExit(manager, executionId);
Assertions.assertNotNull(inspect.get("endAt"));
}
private JSONObject waitForInspectExit(BuiltinCommandActionManager manager, String executionId) throws Exception {
long deadline = System.currentTimeMillis() + 3000;
while (System.currentTimeMillis() < deadline) {
JSONObject inspect = JSONObject.parseObject(manager.buildCommandInspectDefinition().invoker().apply(Map.of(
"id", executionId
)));
if (inspect.get("exitCode") != null) {
return inspect;
}
Thread.sleep(20);
}
throw new AssertionError("command session did not exit in time");
}
}