mirror of https://github.com/openclaw/openclaw.git
refactor: share windows daemon test fixtures
This commit is contained in:
parent
4e05357c45
commit
7d69579634
|
|
@ -1,30 +1,15 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
defaultRuntime,
|
||||
resetLifecycleRuntimeLogs,
|
||||
resetLifecycleServiceMocks,
|
||||
service,
|
||||
stubEmptyGatewayEnv,
|
||||
} from "./test-helpers/lifecycle-core-harness.js";
|
||||
|
||||
const readConfigFileSnapshotMock = vi.fn();
|
||||
const loadConfig = vi.fn(() => ({}));
|
||||
|
||||
const runtimeLogs: string[] = [];
|
||||
const defaultRuntime = {
|
||||
log: (message: string) => runtimeLogs.push(message),
|
||||
error: vi.fn(),
|
||||
exit: (code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
},
|
||||
};
|
||||
|
||||
const service = {
|
||||
label: "TestService",
|
||||
loadedText: "loaded",
|
||||
notLoadedText: "not loaded",
|
||||
install: vi.fn(),
|
||||
uninstall: vi.fn(),
|
||||
stop: vi.fn(),
|
||||
isLoaded: vi.fn(),
|
||||
readCommand: vi.fn(),
|
||||
readRuntime: vi.fn(),
|
||||
restart: vi.fn(),
|
||||
};
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
loadConfig: () => loadConfig(),
|
||||
readConfigFileSnapshot: () => readConfigFileSnapshotMock(),
|
||||
|
|
@ -50,7 +35,7 @@ describe("runServiceRestart config pre-flight (#35862)", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
runtimeLogs.length = 0;
|
||||
resetLifecycleRuntimeLogs();
|
||||
readConfigFileSnapshotMock.mockReset();
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
exists: true,
|
||||
|
|
@ -60,15 +45,8 @@ describe("runServiceRestart config pre-flight (#35862)", () => {
|
|||
});
|
||||
loadConfig.mockReset();
|
||||
loadConfig.mockReturnValue({});
|
||||
service.isLoaded.mockClear();
|
||||
service.readCommand.mockClear();
|
||||
service.restart.mockClear();
|
||||
service.isLoaded.mockResolvedValue(true);
|
||||
service.readCommand.mockResolvedValue({ environment: {} });
|
||||
service.restart.mockResolvedValue({ outcome: "completed" });
|
||||
vi.unstubAllEnvs();
|
||||
vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "");
|
||||
vi.stubEnv("CLAWDBOT_GATEWAY_TOKEN", "");
|
||||
resetLifecycleServiceMocks();
|
||||
stubEmptyGatewayEnv();
|
||||
});
|
||||
|
||||
it("aborts restart when config is invalid", async () => {
|
||||
|
|
@ -152,7 +130,7 @@ describe("runServiceStart config pre-flight (#35862)", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
runtimeLogs.length = 0;
|
||||
resetLifecycleRuntimeLogs();
|
||||
readConfigFileSnapshotMock.mockReset();
|
||||
readConfigFileSnapshotMock.mockResolvedValue({
|
||||
exists: true,
|
||||
|
|
@ -160,10 +138,7 @@ describe("runServiceStart config pre-flight (#35862)", () => {
|
|||
config: {},
|
||||
issues: [],
|
||||
});
|
||||
service.isLoaded.mockClear();
|
||||
service.restart.mockClear();
|
||||
service.isLoaded.mockResolvedValue(true);
|
||||
service.restart.mockResolvedValue({ outcome: "completed" });
|
||||
resetLifecycleServiceMocks();
|
||||
});
|
||||
|
||||
it("aborts start when config is invalid", async () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
defaultRuntime,
|
||||
resetLifecycleRuntimeLogs,
|
||||
resetLifecycleServiceMocks,
|
||||
runtimeLogs,
|
||||
service,
|
||||
stubEmptyGatewayEnv,
|
||||
} from "./test-helpers/lifecycle-core-harness.js";
|
||||
|
||||
const loadConfig = vi.fn(() => ({
|
||||
gateway: {
|
||||
|
|
@ -8,28 +16,6 @@ const loadConfig = vi.fn(() => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const runtimeLogs: string[] = [];
|
||||
const defaultRuntime = {
|
||||
log: (message: string) => runtimeLogs.push(message),
|
||||
error: vi.fn(),
|
||||
exit: (code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
},
|
||||
};
|
||||
|
||||
const service = {
|
||||
label: "TestService",
|
||||
loadedText: "loaded",
|
||||
notLoadedText: "not loaded",
|
||||
install: vi.fn(),
|
||||
uninstall: vi.fn(),
|
||||
stop: vi.fn(),
|
||||
isLoaded: vi.fn(),
|
||||
readCommand: vi.fn(),
|
||||
readRuntime: vi.fn(),
|
||||
restart: vi.fn(),
|
||||
};
|
||||
|
||||
vi.mock("../../config/config.js", () => ({
|
||||
loadConfig: () => loadConfig(),
|
||||
readBestEffortConfig: async () => loadConfig(),
|
||||
|
|
@ -49,7 +35,7 @@ describe("runServiceRestart token drift", () => {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
runtimeLogs.length = 0;
|
||||
resetLifecycleRuntimeLogs();
|
||||
loadConfig.mockReset();
|
||||
loadConfig.mockReturnValue({
|
||||
gateway: {
|
||||
|
|
@ -58,19 +44,11 @@ describe("runServiceRestart token drift", () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
service.isLoaded.mockClear();
|
||||
service.readCommand.mockClear();
|
||||
service.restart.mockClear();
|
||||
service.isLoaded.mockResolvedValue(true);
|
||||
resetLifecycleServiceMocks();
|
||||
service.readCommand.mockResolvedValue({
|
||||
environment: { OPENCLAW_GATEWAY_TOKEN: "service-token" },
|
||||
});
|
||||
service.restart.mockResolvedValue({ outcome: "completed" });
|
||||
vi.unstubAllEnvs();
|
||||
vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "");
|
||||
vi.stubEnv("CLAWDBOT_GATEWAY_TOKEN", "");
|
||||
vi.stubEnv("OPENCLAW_GATEWAY_URL", "");
|
||||
vi.stubEnv("CLAWDBOT_GATEWAY_URL", "");
|
||||
stubEmptyGatewayEnv();
|
||||
});
|
||||
|
||||
it("emits drift warning when enabled", async () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
import { vi } from "vitest";
|
||||
|
||||
export const runtimeLogs: string[] = [];
|
||||
|
||||
export const defaultRuntime = {
|
||||
log: (message: string) => runtimeLogs.push(message),
|
||||
error: vi.fn(),
|
||||
exit: (code: number) => {
|
||||
throw new Error(`__exit__:${code}`);
|
||||
},
|
||||
};
|
||||
|
||||
export const service = {
|
||||
label: "TestService",
|
||||
loadedText: "loaded",
|
||||
notLoadedText: "not loaded",
|
||||
install: vi.fn(),
|
||||
uninstall: vi.fn(),
|
||||
stop: vi.fn(),
|
||||
isLoaded: vi.fn(),
|
||||
readCommand: vi.fn(),
|
||||
readRuntime: vi.fn(),
|
||||
restart: vi.fn(),
|
||||
};
|
||||
|
||||
export function resetLifecycleRuntimeLogs() {
|
||||
runtimeLogs.length = 0;
|
||||
}
|
||||
|
||||
export function resetLifecycleServiceMocks() {
|
||||
service.isLoaded.mockClear();
|
||||
service.readCommand.mockClear();
|
||||
service.restart.mockClear();
|
||||
service.isLoaded.mockResolvedValue(true);
|
||||
service.readCommand.mockResolvedValue({ environment: {} });
|
||||
service.restart.mockResolvedValue({ outcome: "completed" });
|
||||
}
|
||||
|
||||
export function stubEmptyGatewayEnv() {
|
||||
vi.unstubAllEnvs();
|
||||
vi.stubEnv("OPENCLAW_GATEWAY_TOKEN", "");
|
||||
vi.stubEnv("CLAWDBOT_GATEWAY_TOKEN", "");
|
||||
vi.stubEnv("OPENCLAW_GATEWAY_URL", "");
|
||||
vi.stubEnv("CLAWDBOT_GATEWAY_URL", "");
|
||||
}
|
||||
|
|
@ -1,34 +1,19 @@
|
|||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { PassThrough } from "node:stream";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { quoteCmdScriptArg } from "./cmd-argv.js";
|
||||
|
||||
const schtasksResponses = vi.hoisted(
|
||||
() => [] as Array<{ code: number; stdout: string; stderr: string }>,
|
||||
);
|
||||
const schtasksCalls = vi.hoisted(() => [] as string[][]);
|
||||
const inspectPortUsage = vi.hoisted(() => vi.fn());
|
||||
const killProcessTree = vi.hoisted(() => vi.fn());
|
||||
import "./test-helpers/schtasks-base-mocks.js";
|
||||
import {
|
||||
inspectPortUsage,
|
||||
killProcessTree,
|
||||
resetSchtasksBaseMocks,
|
||||
schtasksResponses,
|
||||
withWindowsEnv,
|
||||
} from "./test-helpers/schtasks-fixtures.js";
|
||||
const childUnref = vi.hoisted(() => vi.fn());
|
||||
const spawn = vi.hoisted(() => vi.fn(() => ({ unref: childUnref })));
|
||||
|
||||
vi.mock("./schtasks-exec.js", () => ({
|
||||
execSchtasks: async (argv: string[]) => {
|
||||
schtasksCalls.push(argv);
|
||||
return schtasksResponses.shift() ?? { code: 0, stdout: "", stderr: "" };
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../infra/ports.js", () => ({
|
||||
inspectPortUsage: (...args: unknown[]) => inspectPortUsage(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../process/kill-tree.js", () => ({
|
||||
killProcessTree: (...args: unknown[]) => killProcessTree(...args),
|
||||
}));
|
||||
|
||||
vi.mock("node:child_process", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("node:child_process")>();
|
||||
return {
|
||||
|
|
@ -58,6 +43,7 @@ function resolveStartupEntryPath(env: Record<string, string>) {
|
|||
);
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
async function withWindowsEnv(
|
||||
run: (params: { tmpDir: string; env: Record<string, string> }) => Promise<void>,
|
||||
) {
|
||||
|
|
@ -90,11 +76,28 @@ async function writeGatewayScript(env: Record<string, string>, port = 18789) {
|
|||
);
|
||||
}
|
||||
|
||||
||||||| parent of 8fb2c3f894 (refactor: share windows daemon test fixtures)
|
||||
async function withWindowsEnv(
|
||||
run: (params: { tmpDir: string; env: Record<string, string> }) => Promise<void>,
|
||||
) {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-win-startup-"));
|
||||
const env = {
|
||||
USERPROFILE: tmpDir,
|
||||
APPDATA: path.join(tmpDir, "AppData", "Roaming"),
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_GATEWAY_PORT: "18789",
|
||||
};
|
||||
try {
|
||||
await run({ tmpDir, env });
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
=======
|
||||
>>>>>>> 8fb2c3f894 (refactor: share windows daemon test fixtures)
|
||||
beforeEach(() => {
|
||||
schtasksResponses.length = 0;
|
||||
schtasksCalls.length = 0;
|
||||
inspectPortUsage.mockReset();
|
||||
killProcessTree.mockReset();
|
||||
resetSchtasksBaseMocks();
|
||||
spawn.mockClear();
|
||||
childUnref.mockClear();
|
||||
});
|
||||
|
|
@ -105,7 +108,7 @@ afterEach(() => {
|
|||
|
||||
describe("Windows startup fallback", () => {
|
||||
it("falls back to a Startup-folder launcher when schtasks create is denied", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-startup-", async ({ env }) => {
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
{ code: 5, stdout: "", stderr: "ERROR: Access is denied." },
|
||||
|
|
@ -140,7 +143,7 @@ describe("Windows startup fallback", () => {
|
|||
});
|
||||
|
||||
it("falls back to a Startup-folder launcher when schtasks create hangs", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-startup-", async ({ env }) => {
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
{ code: 124, stdout: "", stderr: "schtasks timed out after 15000ms" },
|
||||
|
|
@ -164,7 +167,7 @@ describe("Windows startup fallback", () => {
|
|||
});
|
||||
|
||||
it("treats an installed Startup-folder launcher as loaded", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-startup-", async ({ env }) => {
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
{ code: 1, stdout: "", stderr: "not found" },
|
||||
|
|
@ -177,7 +180,7 @@ describe("Windows startup fallback", () => {
|
|||
});
|
||||
|
||||
it("reports runtime from the gateway listener when using the Startup fallback", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-startup-", async ({ env }) => {
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
{ code: 1, stdout: "", stderr: "not found" },
|
||||
|
|
@ -199,7 +202,7 @@ describe("Windows startup fallback", () => {
|
|||
});
|
||||
|
||||
it("restarts the Startup fallback by killing the current pid and relaunching the entry", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-startup-", async ({ env }) => {
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
{ code: 1, stdout: "", stderr: "not found" },
|
||||
|
|
|
|||
|
|
@ -1,34 +1,20 @@
|
|||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { PassThrough } from "node:stream";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const schtasksResponses = vi.hoisted(
|
||||
() => [] as Array<{ code: number; stdout: string; stderr: string }>,
|
||||
);
|
||||
const schtasksCalls = vi.hoisted(() => [] as string[][]);
|
||||
const inspectPortUsage = vi.hoisted(() => vi.fn());
|
||||
const killProcessTree = vi.hoisted(() => vi.fn());
|
||||
import "./test-helpers/schtasks-base-mocks.js";
|
||||
import {
|
||||
inspectPortUsage,
|
||||
killProcessTree,
|
||||
resetSchtasksBaseMocks,
|
||||
schtasksCalls,
|
||||
schtasksResponses,
|
||||
withWindowsEnv,
|
||||
} from "./test-helpers/schtasks-fixtures.js";
|
||||
const findVerifiedGatewayListenerPidsOnPortSync = vi.hoisted(() =>
|
||||
vi.fn<(port: number) => number[]>(() => []),
|
||||
);
|
||||
|
||||
vi.mock("./schtasks-exec.js", () => ({
|
||||
execSchtasks: async (argv: string[]) => {
|
||||
schtasksCalls.push(argv);
|
||||
return schtasksResponses.shift() ?? { code: 0, stdout: "", stderr: "" };
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../infra/ports.js", () => ({
|
||||
inspectPortUsage: (...args: unknown[]) => inspectPortUsage(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../process/kill-tree.js", () => ({
|
||||
killProcessTree: (...args: unknown[]) => killProcessTree(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../infra/gateway-processes.js", () => ({
|
||||
findVerifiedGatewayListenerPidsOnPortSync: (port: number) =>
|
||||
findVerifiedGatewayListenerPidsOnPortSync(port),
|
||||
|
|
@ -37,23 +23,6 @@ vi.mock("../infra/gateway-processes.js", () => ({
|
|||
const { restartScheduledTask, resolveTaskScriptPath, stopScheduledTask } =
|
||||
await import("./schtasks.js");
|
||||
|
||||
async function withWindowsEnv(
|
||||
run: (params: { tmpDir: string; env: Record<string, string> }) => Promise<void>,
|
||||
) {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-win-stop-"));
|
||||
const env = {
|
||||
USERPROFILE: tmpDir,
|
||||
APPDATA: path.join(tmpDir, "AppData", "Roaming"),
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_GATEWAY_PORT: "18789",
|
||||
};
|
||||
try {
|
||||
await run({ tmpDir, env });
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
async function writeGatewayScript(env: Record<string, string>, port = 18789) {
|
||||
const scriptPath = resolveTaskScriptPath(env);
|
||||
await fs.mkdir(path.dirname(scriptPath), { recursive: true });
|
||||
|
|
@ -70,10 +39,7 @@ async function writeGatewayScript(env: Record<string, string>, port = 18789) {
|
|||
}
|
||||
|
||||
beforeEach(() => {
|
||||
schtasksResponses.length = 0;
|
||||
schtasksCalls.length = 0;
|
||||
inspectPortUsage.mockReset();
|
||||
killProcessTree.mockReset();
|
||||
resetSchtasksBaseMocks();
|
||||
findVerifiedGatewayListenerPidsOnPortSync.mockReset();
|
||||
findVerifiedGatewayListenerPidsOnPortSync.mockReturnValue([]);
|
||||
inspectPortUsage.mockResolvedValue({
|
||||
|
|
@ -90,7 +56,7 @@ afterEach(() => {
|
|||
|
||||
describe("Scheduled Task stop/restart cleanup", () => {
|
||||
it("kills lingering verified gateway listeners after schtasks stop", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-stop-", async ({ env }) => {
|
||||
await writeGatewayScript(env);
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
|
|
@ -168,7 +134,7 @@ describe("Scheduled Task stop/restart cleanup", () => {
|
|||
});
|
||||
|
||||
it("falls back to inspected gateway listeners when sync verification misses on Windows", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-stop-", async ({ env }) => {
|
||||
await writeGatewayScript(env);
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
|
|
@ -206,7 +172,7 @@ describe("Scheduled Task stop/restart cleanup", () => {
|
|||
});
|
||||
|
||||
it("kills lingering verified gateway listeners and waits for port release before restart", async () => {
|
||||
await withWindowsEnv(async ({ env }) => {
|
||||
await withWindowsEnv("openclaw-win-stop-", async ({ env }) => {
|
||||
await writeGatewayScript(env);
|
||||
schtasksResponses.push(
|
||||
{ code: 0, stdout: "", stderr: "" },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
import { vi } from "vitest";
|
||||
import {
|
||||
inspectPortUsage,
|
||||
killProcessTree,
|
||||
schtasksCalls,
|
||||
schtasksResponses,
|
||||
} from "./schtasks-fixtures.js";
|
||||
|
||||
vi.mock("../schtasks-exec.js", () => ({
|
||||
execSchtasks: async (argv: string[]) => {
|
||||
schtasksCalls.push(argv);
|
||||
return schtasksResponses.shift() ?? { code: 0, stdout: "", stderr: "" };
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock("../../infra/ports.js", () => ({
|
||||
inspectPortUsage: (...args: unknown[]) => inspectPortUsage(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../process/kill-tree.js", () => ({
|
||||
killProcessTree: (...args: unknown[]) => killProcessTree(...args),
|
||||
}));
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { vi } from "vitest";
|
||||
|
||||
export const schtasksResponses: Array<{ code: number; stdout: string; stderr: string }> = [];
|
||||
export const schtasksCalls: string[][] = [];
|
||||
export const inspectPortUsage = vi.fn();
|
||||
export const killProcessTree = vi.fn();
|
||||
|
||||
export async function withWindowsEnv(
|
||||
prefix: string,
|
||||
run: (params: { tmpDir: string; env: Record<string, string> }) => Promise<void>,
|
||||
) {
|
||||
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
|
||||
const env = {
|
||||
USERPROFILE: tmpDir,
|
||||
APPDATA: path.join(tmpDir, "AppData", "Roaming"),
|
||||
OPENCLAW_PROFILE: "default",
|
||||
OPENCLAW_GATEWAY_PORT: "18789",
|
||||
};
|
||||
try {
|
||||
await run({ tmpDir, env });
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
export function resetSchtasksBaseMocks() {
|
||||
schtasksResponses.length = 0;
|
||||
schtasksCalls.length = 0;
|
||||
inspectPortUsage.mockReset();
|
||||
killProcessTree.mockReset();
|
||||
}
|
||||
Loading…
Reference in New Issue