test(config): dedupe io write config test setup

This commit is contained in:
Peter Steinberger
2026-02-18 12:20:56 +00:00
parent eabf187fa5
commit 514e318df9

View File

@@ -14,6 +14,7 @@ describe("config io write", () => {
home: string;
initialConfig: Record<string, unknown>;
env?: NodeJS.ProcessEnv;
logger?: { warn: (msg: string) => void; error: (msg: string) => void };
}) {
const configPath = path.join(params.home, ".openclaw", "openclaw.json");
await fs.mkdir(path.dirname(configPath), { recursive: true });
@@ -22,32 +23,69 @@ describe("config io write", () => {
const io = createConfigIO({
env: params.env ?? {},
homedir: () => params.home,
logger: silentLogger,
logger: params.logger ?? silentLogger,
});
const snapshot = await io.readConfigFileSnapshot();
expect(snapshot.valid).toBe(true);
return { configPath, io, snapshot };
}
async function writeTokenAuthAndReadConfig(params: {
io: { writeConfigFile: (config: Record<string, unknown>) => Promise<void> };
snapshot: { config: Record<string, unknown> };
configPath: string;
}) {
const next = structuredClone(params.snapshot.config);
const gateway =
next.gateway && typeof next.gateway === "object"
? (next.gateway as Record<string, unknown>)
: {};
next.gateway = {
...gateway,
auth: { mode: "token" },
};
await params.io.writeConfigFile(next);
return JSON.parse(await fs.readFile(params.configPath, "utf-8")) as Record<string, unknown>;
}
async function writeGatewayPatchAndReadLastAuditEntry(params: {
home: string;
initialConfig: Record<string, unknown>;
gatewayPatch: Record<string, unknown>;
env?: NodeJS.ProcessEnv;
}) {
const { io, snapshot, configPath } = await writeConfigAndCreateIo({
home: params.home,
initialConfig: params.initialConfig,
env: params.env,
logger: {
warn: vi.fn(),
error: vi.fn(),
},
});
const auditPath = path.join(params.home, ".openclaw", "logs", "config-audit.jsonl");
const next = structuredClone(snapshot.config);
const gateway =
next.gateway && typeof next.gateway === "object"
? (next.gateway as Record<string, unknown>)
: {};
next.gateway = {
...gateway,
...params.gatewayPatch,
};
await io.writeConfigFile(next);
const lines = (await fs.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
const last = JSON.parse(lines.at(-1) ?? "{}") as Record<string, unknown>;
return { last, lines, configPath };
}
it("persists caller changes onto resolved config without leaking runtime defaults", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const { configPath, io, snapshot } = await writeConfigAndCreateIo({
home,
initialConfig: { gateway: { port: 18789 } },
});
const next = structuredClone(snapshot.config);
next.gateway = {
...next.gateway,
auth: { mode: "token" },
};
await io.writeConfigFile(next);
const persisted = JSON.parse(await fs.readFile(configPath, "utf-8")) as Record<
string,
unknown
>;
const persisted = await writeTokenAuthAndReadConfig({ io, snapshot, configPath });
expect(persisted.gateway).toEqual({
port: 18789,
auth: { mode: "token" },
@@ -79,16 +117,7 @@ describe("config io write", () => {
gateway: { port: 18789 },
},
});
const next = structuredClone(snapshot.config);
next.gateway = {
...next.gateway,
auth: { mode: "token" },
};
await io.writeConfigFile(next);
const persisted = JSON.parse(await fs.readFile(configPath, "utf-8")) as {
const persisted = (await writeTokenAuthAndReadConfig({ io, snapshot, configPath })) as {
agents: { defaults: { cliBackends: { codex: { env: { OPENAI_API_KEY: string } } } } };
gateway: { port: number; auth: { mode: string } };
};
@@ -223,25 +252,16 @@ describe("config io write", () => {
it("logs an overwrite audit entry when replacing an existing config file", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const configPath = path.join(home, ".openclaw", "openclaw.json");
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(
configPath,
JSON.stringify({ gateway: { port: 18789 } }, null, 2),
"utf-8",
);
const warn = vi.fn();
const io = createConfigIO({
const { configPath, io, snapshot } = await writeConfigAndCreateIo({
home,
initialConfig: { gateway: { port: 18789 } },
env: {} as NodeJS.ProcessEnv,
homedir: () => home,
logger: {
warn,
error: vi.fn(),
warn: warn as (msg: string) => void,
error: vi.fn() as (msg: string) => void,
},
});
const snapshot = await io.readConfigFileSnapshot();
expect(snapshot.valid).toBe(true);
const next = structuredClone(snapshot.config);
next.gateway = {
...next.gateway,
@@ -285,38 +305,13 @@ describe("config io write", () => {
it("appends config write audit JSONL entries with forensic metadata", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const configPath = path.join(home, ".openclaw", "openclaw.json");
const auditPath = path.join(home, ".openclaw", "logs", "config-audit.jsonl");
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(
configPath,
JSON.stringify({ gateway: { port: 18789 } }, null, 2),
"utf-8",
);
const io = createConfigIO({
const { configPath, lines, last } = await writeGatewayPatchAndReadLastAuditEntry({
home,
initialConfig: { gateway: { port: 18789 } },
gatewayPatch: { mode: "local" },
env: {} as NodeJS.ProcessEnv,
homedir: () => home,
logger: {
warn: vi.fn(),
error: vi.fn(),
},
});
const snapshot = await io.readConfigFileSnapshot();
expect(snapshot.valid).toBe(true);
const next = structuredClone(snapshot.config);
next.gateway = {
...next.gateway,
mode: "local",
};
await io.writeConfigFile(next);
const lines = (await fs.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
expect(lines.length).toBeGreaterThan(0);
const last = JSON.parse(lines.at(-1) ?? "{}") as Record<string, unknown>;
expect(last.source).toBe("config-io");
expect(last.event).toBe("config.write");
expect(last.configPath).toBe(configPath);
@@ -330,40 +325,16 @@ describe("config io write", () => {
it("records gateway watch session markers in config audit entries", async () => {
await withTempHome("openclaw-config-io-", async (home) => {
const configPath = path.join(home, ".openclaw", "openclaw.json");
const auditPath = path.join(home, ".openclaw", "logs", "config-audit.jsonl");
await fs.mkdir(path.dirname(configPath), { recursive: true });
await fs.writeFile(
configPath,
JSON.stringify({ gateway: { mode: "local" } }, null, 2),
"utf-8",
);
const io = createConfigIO({
const { last } = await writeGatewayPatchAndReadLastAuditEntry({
home,
initialConfig: { gateway: { mode: "local" } },
gatewayPatch: { bind: "loopback" },
env: {
OPENCLAW_WATCH_MODE: "1",
OPENCLAW_WATCH_SESSION: "watch-session-1",
OPENCLAW_WATCH_COMMAND: "gateway --force",
} as NodeJS.ProcessEnv,
homedir: () => home,
logger: {
warn: vi.fn(),
error: vi.fn(),
},
});
const snapshot = await io.readConfigFileSnapshot();
expect(snapshot.valid).toBe(true);
const next = structuredClone(snapshot.config);
next.gateway = {
...next.gateway,
bind: "loopback",
};
await io.writeConfigFile(next);
const lines = (await fs.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
const last = JSON.parse(lines.at(-1) ?? "{}") as Record<string, unknown>;
expect(last.watchMode).toBe(true);
expect(last.watchSession).toBe("watch-session-1");
expect(last.watchCommand).toBe("gateway --force");