mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-03 03:03:24 -04:00
test(config): dedupe io write config test setup
This commit is contained in:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user