File size: 2,463 Bytes
d197cf3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | // Launchd plist parser tests cover label extraction shared by lifecycle and diagnostics.
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import {
buildLaunchAgentPlist,
parseLaunchdPlistLabel,
readLaunchAgentProgramArgumentsFromFile,
} from "./launchd-plist.js";
import { decodeLaunchAgentPlistFixture } from "./launchd-plist.test-support.js";
vi.mock("../process/exec.js", async (importOriginal) => ({
...(await importOriginal<typeof import("../process/exec.js")>()),
runExec: vi.fn(
async (_command: string, _args: string[], options: { input: string | Uint8Array }) =>
decodeLaunchAgentPlistFixture(options.input),
),
}));
describe("LaunchAgent environment round-trip", () => {
it.each(["", "--max-old-space-size=24576"])(
"preserves explicit NODE_OPTIONS=%j while omitting other empty values",
async (nodeOptions) => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-plist-env-"));
const plistPath = path.join(dir, "gateway.plist");
const programArguments = ["/usr/bin/node", "--max-old-space-size=16384", "gateway.js"];
try {
await fs.writeFile(
plistPath,
buildLaunchAgentPlist({
label: "ai.openclaw.gateway",
programArguments,
stdoutPath: path.join(dir, "stdout.log"),
stderrPath: path.join(dir, "stderr.log"),
environment: { NODE_OPTIONS: nodeOptions, UNUSED: "", MISSING: undefined },
}),
);
const command = await readLaunchAgentProgramArgumentsFromFile(plistPath);
expect(command?.environment).toEqual({ NODE_OPTIONS: nodeOptions });
expect(command?.programArguments).toEqual(programArguments);
} finally {
await fs.rm(dir, { recursive: true, force: true });
}
},
);
});
describe("parseLaunchdPlistLabel", () => {
it("decodes the XML entities accepted in launchd labels", () => {
expect(
parseLaunchdPlistLabel(
"<plist><dict><key>Label</key><string>ai.openclaw.a&b</string></dict></plist>",
),
).toBe("ai.openclaw.a&b");
});
it("returns null for missing or empty labels", () => {
expect(parseLaunchdPlistLabel("<plist><dict/></plist>")).toBeNull();
expect(
parseLaunchdPlistLabel("<plist><dict><key>Label</key><string> </string></dict></plist>"),
).toBeNull();
});
});
|