惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
B
Blog
Stack Overflow Blog
Stack Overflow Blog
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
Recent Announcements
Recent Announcements
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
腾讯CDC
D
DataBreaches.Net
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
罗磊的独立博客
L
LangChain Blog
V
Visual Studio Blog
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
test: slim pty fallback coverage · openclaw/openclaw@a8edf29
steipete · 2026-04-24 · via Recent Commits to openclaw:main

@@ -0,0 +1,103 @@

1+

import { afterEach, beforeAll, beforeEach, expect, test, vi } from "vitest";

2+

import type { ManagedRun, SpawnInput } from "../process/supervisor/index.js";

3+4+

let listRunningSessions: typeof import("./bash-process-registry.js").listRunningSessions;

5+

let resetProcessRegistryForTests: typeof import("./bash-process-registry.js").resetProcessRegistryForTests;

6+

let runExecProcess: typeof import("./bash-tools.exec-runtime.js").runExecProcess;

7+8+

const { supervisorSpawnMock } = vi.hoisted(() => ({

9+

supervisorSpawnMock: vi.fn(),

10+

}));

11+12+

vi.mock("../process/supervisor/index.js", () => ({

13+

getProcessSupervisor: () => ({

14+

spawn: supervisorSpawnMock,

15+

cancel: vi.fn(),

16+

cancelScope: vi.fn(),

17+

reconcileOrphans: vi.fn(),

18+

getRecord: vi.fn(),

19+

}),

20+

}));

21+22+

function createSuccessfulRun(input: SpawnInput): ManagedRun {

23+

input.onStdout?.("ok");

24+

return {

25+

runId: input.runId ?? "test-run",

26+

pid: 1234,

27+

startedAtMs: Date.now(),

28+

stdin: {

29+

write: vi.fn(),

30+

end: vi.fn(),

31+

destroy: vi.fn(),

32+

},

33+

cancel: vi.fn(),

34+

wait: vi.fn(async () => ({

35+

reason: "exit" as const,

36+

exitCode: 0,

37+

exitSignal: null,

38+

durationMs: 1,

39+

stdout: "",

40+

stderr: "",

41+

timedOut: false,

42+

noOutputTimedOut: false,

43+

})),

44+

};

45+

}

46+47+

beforeAll(async () => {

48+

({ listRunningSessions, resetProcessRegistryForTests } =

49+

await import("./bash-process-registry.js"));

50+

({ runExecProcess } = await import("./bash-tools.exec-runtime.js"));

51+

});

52+53+

beforeEach(() => {

54+

supervisorSpawnMock.mockReset();

55+

});

56+57+

afterEach(() => {

58+

resetProcessRegistryForTests();

59+

vi.clearAllMocks();

60+

});

61+62+

function runPtyFallback(warnings: string[] = []) {

63+

return runExecProcess({

64+

command: "printf ok",

65+

workdir: process.cwd(),

66+

env: {},

67+

usePty: true,

68+

warnings,

69+

maxOutput: 20_000,

70+

pendingMaxOutput: 20_000,

71+

notifyOnExit: false,

72+

timeoutSec: 5,

73+

});

74+

}

75+76+

test("exec falls back when PTY spawn fails", async () => {

77+

supervisorSpawnMock

78+

.mockRejectedValueOnce(new Error("pty spawn failed"))

79+

.mockImplementationOnce(async (input: SpawnInput) => createSuccessfulRun(input));

80+81+

const warnings: string[] = [];

82+

const handle = await runPtyFallback(warnings);

83+

const outcome = await handle.promise;

84+85+

expect(outcome.status).toBe("completed");

86+

expect(outcome.aggregated).toContain("ok");

87+

expect(warnings.join("\n")).toContain("PTY spawn failed");

88+

expect(supervisorSpawnMock).toHaveBeenNthCalledWith(1, expect.objectContaining({ mode: "pty" }));

89+

expect(supervisorSpawnMock).toHaveBeenNthCalledWith(

90+

2,

91+

expect.objectContaining({ mode: "child" }),

92+

);

93+

});

94+95+

test("exec cleans session state when PTY fallback spawn also fails", async () => {

96+

supervisorSpawnMock

97+

.mockRejectedValueOnce(new Error("pty spawn failed"))

98+

.mockRejectedValueOnce(new Error("child fallback failed"));

99+100+

await expect(runPtyFallback()).rejects.toThrow("child fallback failed");

101+102+

expect(listRunningSessions()).toHaveLength(0);

103+

});