mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
* Run server tests on Linux+Windows matrix Replace the hand-curated Windows server test allow-list with a full-suite matrix run.\nBoth Ubuntu and Windows now run the same server test command with shared setup and secrets. * Add isPlatform helper and gate Windows-hostile server tests - Add a shared server test isPlatform helper. - Migrate existing Windows-gated spawn, worktree, executable, and worktree-core tests to the helper. - Gate Windows-hostile symlink, macOS path-normalization, and POSIX shell setup tests with skipIf. * Replace POSIX shell calls in test fixtures with Node primitives - Replaced test fixture mkdir/echo shell setup with fs mkdirSync/writeFileSync calls in touched server tests. - Replaced git shell strings with execFileSync/spawnSync argv calls across checkout, worktree, MCP, script, and workspace git fixtures. - Gated the directory suggestion symlink escape tests on Windows because those fixtures require POSIX symlink behavior. * Fix Windows server-test failures and split POSIX-only suites into sibling files - Fix Windows path/cwd assertions in terminal, session/workspace, git-service, checkout-git, MCP, logger, spawn, and registry bootstrap tests.\n- Keep terminal tests runnable on Windows by canonicalizing temp cwd fixtures and ensuring a Windows shell fallback.\n- Gate POSIX-only shell, signal, Unix socket, and git-worktree reuse fixtures that need dedicated Windows coverage later. * Move POSIX-only test blocks into sibling .posix.test.ts files - terminal.test.ts: moved PTY/bash interaction blocks into terminal.posix.test.ts. - worktree.test.ts: moved git-worktree and teardown shell blocks into worktree.posix.test.ts. - worktree-bootstrap.test.ts: moved setup shell and terminal-backed service blocks into worktree-bootstrap.posix.test.ts. - worktree-core.test.ts: moved the POSIX-only worktree-core suite into worktree-core.posix.test.ts and removed the empty original. - provider-availability.test.ts and file-explorer/service.test.ts: moved POSIX PATH/symlink blocks into sibling suites. * Fix Windows 8.3 short-name, EBUSY cleanup, and node-pty shell-path failures in server tests - Normalize temp home directories in directory suggestion assertions to avoid Windows short-name mismatches. - Use Windows-valid terminal shells/cwds in terminal fixtures and wait for terminal-manager PTYs before cleanup. - Replace hardcoded POSIX paths in workspace-git/MCP/loop fixtures with platform-resolved paths or command files. - Gate the two explicitly Linux-only workspace-git watcher tests. * Replace hardcoded POSIX paths with portable Node path constructions in server tests - checkout-git.test.ts and worktree-session.test.ts: compare Windows temp paths with realpathSync.native to avoid 8.3 short-name mismatches. - directory-suggestions.test.ts: canonicalize result and expected paths with realpathSync.native. - session.workspaces.test.ts: replace literal /tmp and /Users fixtures with path.resolve/path.join constructions. - workspace-git-service.primitive.test.ts, loop-service.test.ts, and mcp-server.test.ts: use canonical repo/temp paths and shell-safe relative verify commands. * Fix loop-service verify-check shell and workspace-git-service path-separator on Windows - Run the loop-service verify script through the current Node executable with a relative script path. - Normalize the workspace-git-service expected repo cwd to forward slashes for the listWorktrees assertion. * Fix loop-service worker PTY spawn on Windows - Canonicalize the loop-service temporary root and workspace with realpathSync.native before worker agents use the path as cwd. * Gate loop-service real-worker-PTY test on Windows - Skip the real worker PTY loop test on Windows after ConPTY path resolution still fails with node-pty error 267.\n- Keep the test running on POSIX so the loop behavior remains covered. * Stub getMetricsSnapshot in test mocks to suppress async-leak uncaught exceptions on Windows - Add a no-op AgentManager metrics snapshot to the WebSocket notification test server stub. * Fix terminal-manager Windows-path test to avoid PTY spawn into nonexistent dir - Use an existing temporary cwd for the createTerminal absolute-path validation assertion so node-pty does not spawn into a missing Windows directory.
138 lines
4.3 KiB
TypeScript
138 lines
4.3 KiB
TypeScript
import { mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
import { spawn } from "node:child_process";
|
|
import { describe, expect, test } from "vitest";
|
|
import { isPlatform } from "../src/test-utils/platform.js";
|
|
|
|
const repoRoot = path.resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
const supervisorPath = fileURLToPath(new URL("./supervisor.ts", import.meta.url));
|
|
|
|
async function runSupervisorFixture(options: {
|
|
workerSource: string;
|
|
restartOnCrash?: boolean;
|
|
}): Promise<{
|
|
code: number | null;
|
|
signal: NodeJS.Signals | null;
|
|
log: string;
|
|
stdout: string;
|
|
stderr: string;
|
|
}> {
|
|
const tempDir = await mkdtemp(path.join(tmpdir(), "paseo-supervisor-log-"));
|
|
const logPath = path.join(tempDir, "daemon.log");
|
|
const workerPath = path.join(tempDir, "worker.mjs");
|
|
const runnerPath = path.join(tempDir, "runner.mjs");
|
|
|
|
await writeFile(workerPath, options.workerSource);
|
|
await writeFile(
|
|
runnerPath,
|
|
`
|
|
import { runSupervisor } from ${JSON.stringify(pathToFileURL(supervisorPath).href)};
|
|
|
|
runSupervisor({
|
|
name: "TestSupervisor",
|
|
startupMessage: "starting fixture",
|
|
resolveWorkerEntry: () => ${JSON.stringify(workerPath)},
|
|
workerArgs: [],
|
|
workerEnv: process.env,
|
|
workerExecArgv: [],
|
|
restartOnCrash: ${JSON.stringify(options.restartOnCrash ?? false)},
|
|
logFile: {
|
|
path: ${JSON.stringify(logPath)},
|
|
rotate: { maxSize: "1m", maxFiles: 2 },
|
|
},
|
|
});
|
|
`,
|
|
);
|
|
|
|
const child = spawn(process.execPath, ["--import", "tsx", runnerPath], {
|
|
cwd: repoRoot,
|
|
env: { ...process.env },
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
});
|
|
|
|
let stdout = "";
|
|
let stderr = "";
|
|
child.stdout.setEncoding("utf8");
|
|
child.stderr.setEncoding("utf8");
|
|
child.stdout.on("data", (chunk) => {
|
|
stdout += chunk;
|
|
});
|
|
child.stderr.on("data", (chunk) => {
|
|
stderr += chunk;
|
|
});
|
|
|
|
const { code, signal } = await new Promise<{
|
|
code: number | null;
|
|
signal: NodeJS.Signals | null;
|
|
}>((resolve, reject) => {
|
|
const timeout = setTimeout(() => {
|
|
child.kill("SIGKILL");
|
|
reject(new Error("supervisor fixture timed out"));
|
|
}, 10000);
|
|
|
|
child.on("error", (error) => {
|
|
clearTimeout(timeout);
|
|
reject(error);
|
|
});
|
|
child.on("close", (exitCode, exitSignal) => {
|
|
clearTimeout(timeout);
|
|
resolve({ code: exitCode, signal: exitSignal });
|
|
});
|
|
});
|
|
|
|
const log = await readFile(logPath, "utf8");
|
|
return { code, signal, log, stdout, stderr };
|
|
}
|
|
|
|
describe("supervisor durable logging", () => {
|
|
test("writes supervised worker stdout and stderr to daemon.log", async () => {
|
|
const result = await runSupervisorFixture({
|
|
workerSource: `
|
|
process.stdout.write('{"level":30,"msg":"worker-json-stdout"}\\n');
|
|
process.stderr.write('{"level":50,"msg":"worker-json-stderr"}\\n');
|
|
process.exit(0);
|
|
`,
|
|
});
|
|
|
|
expect(result.code).toBe(0);
|
|
expect(result.signal).toBeNull();
|
|
expect(result.log).toContain('"worker-json-stdout"');
|
|
expect(result.log).toContain('"worker-json-stderr"');
|
|
expect(result.stdout).toContain('"worker-json-stdout"');
|
|
expect(result.stderr).toContain('"worker-json-stderr"');
|
|
});
|
|
|
|
test("preserves raw non-JSON stdout and stderr lines", async () => {
|
|
const result = await runSupervisorFixture({
|
|
workerSource: `
|
|
process.stdout.write('raw stdout line\\n');
|
|
process.stderr.write('raw stderr line\\n');
|
|
process.exit(0);
|
|
`,
|
|
});
|
|
|
|
expect(result.log).toContain("raw stdout line\n");
|
|
expect(result.log).toContain("raw stderr line\n");
|
|
});
|
|
|
|
// POSIX-only: Windows reports the worker self-kill as an exit code, not SIGKILL.
|
|
test.skipIf(isPlatform("win32"))(
|
|
"logs worker signal exits even when the worker cannot log",
|
|
async () => {
|
|
const result = await runSupervisorFixture({
|
|
workerSource: `
|
|
process.kill(process.pid, "SIGKILL");
|
|
`,
|
|
});
|
|
|
|
expect(result.code).toBe(1);
|
|
expect(result.signal).toBeNull();
|
|
expect(result.log).toContain('"msg":"Worker exited"');
|
|
expect(result.log).toContain('"signal":"SIGKILL"');
|
|
expect(result.log).toContain("Supervisor exiting");
|
|
},
|
|
);
|
|
});
|