test(config): align snapshot fixtures and isolation

This commit is contained in:
Peter Steinberger
2026-03-30 00:14:47 +01:00
parent 89a4f2a34e
commit f928b81279
12 changed files with 108 additions and 10 deletions

View File

@@ -62,7 +62,7 @@ describe("config io write", () => {
}
async function writeTokenAuthAndReadConfig(params: {
io: { writeConfigFile: (config: Record<string, unknown>) => Promise<void> };
io: { writeConfigFile: (config: Record<string, unknown>) => Promise<unknown> };
snapshot: { config: Record<string, unknown> };
configPath: string;
}) {

58
src/config/mutate.test.ts Normal file
View File

@@ -0,0 +1,58 @@
import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
ConfigMutationConflictError,
mutateConfigFile,
readSourceConfigSnapshot,
replaceConfigFile,
} from "./config.js";
import { withTempHome } from "./home-env.test-harness.js";
describe("config mutate helpers", () => {
it("mutates source config with optimistic hash protection", async () => {
await withTempHome("openclaw-config-mutate-source-", 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)}\n`);
const snapshot = await readSourceConfigSnapshot();
await mutateConfigFile({
baseHash: snapshot.hash,
base: "source",
mutate(draft) {
draft.gateway = {
...draft.gateway,
auth: { mode: "token" },
};
},
});
const persisted = JSON.parse(await fs.readFile(configPath, "utf8")) as {
gateway?: { port?: number; auth?: unknown };
};
expect(persisted.gateway).toEqual({
port: 18789,
auth: { mode: "token" },
});
});
});
it("rejects stale replace attempts when the base hash changed", async () => {
await withTempHome("openclaw-config-replace-conflict-", 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)}\n`);
const snapshot = await readSourceConfigSnapshot();
await fs.writeFile(configPath, `${JSON.stringify({ gateway: { port: 19001 } }, null, 2)}\n`);
await expect(
replaceConfigFile({
baseHash: snapshot.hash,
nextConfig: { gateway: { port: 19002 } },
}),
).rejects.toBeInstanceOf(ConfigMutationConflictError);
});
});
});

View File

@@ -5,7 +5,9 @@ import type { ConfigFileSnapshot } from "./types.openclaw.js";
export type TestSnapshot<TConfig extends Record<string, unknown>> = ConfigFileSnapshot & {
parsed: TConfig;
sourceConfig: TConfig;
resolved: TConfig;
runtimeConfig: TConfig;
config: TConfig;
};
@@ -18,8 +20,10 @@ export function makeSnapshot<TConfig extends Record<string, unknown>>(
exists: true,
raw: raw ?? JSON.stringify(config),
parsed: config,
sourceConfig: config as ConfigFileSnapshot["sourceConfig"],
resolved: config as ConfigFileSnapshot["resolved"],
valid: true,
runtimeConfig: config as ConfigFileSnapshot["runtimeConfig"],
config: config as ConfigFileSnapshot["config"],
hash: "abc123",
issues: [],

View File

@@ -401,8 +401,10 @@ describe("redactConfigSnapshot", () => {
exists: false,
raw: null,
parsed: null,
sourceConfig: {} as ConfigFileSnapshot["sourceConfig"],
resolved: {} as ConfigFileSnapshot["resolved"],
valid: false,
runtimeConfig: {} as ConfigFileSnapshot["runtimeConfig"],
config: {} as ConfigFileSnapshot["config"],
issues: [],
warnings: [],
@@ -419,8 +421,12 @@ describe("redactConfigSnapshot", () => {
exists: true,
raw: '{ "gateway": { "auth": { "token": "leaky-secret" } } }',
parsed: { gateway: { auth: { token: "leaky-secret" } } },
sourceConfig: {
gateway: { auth: { token: "leaky-secret" } },
} as ConfigFileSnapshot["sourceConfig"],
resolved: { gateway: { auth: { token: "leaky-secret" } } } as ConfigFileSnapshot["resolved"],
valid: false,
runtimeConfig: {} as ConfigFileSnapshot["runtimeConfig"],
config: {} as ConfigFileSnapshot["config"],
issues: [{ path: "", message: "invalid config" }],
warnings: [],

View File

@@ -25,8 +25,10 @@ function makeSnapshot(params: { valid: boolean; config?: OpenClawConfig }): Conf
raw: "{}",
parsed: params.config ?? {},
resolved: params.config ?? {},
sourceConfig: params.config ?? {},
valid: params.valid,
config: params.config ?? {},
runtimeConfig: params.config ?? {},
issues: params.valid ? [] : [{ path: "gateway", message: "invalid" }],
warnings: [],
legacyIssues: [],

View File

@@ -1,10 +1,15 @@
import fs from "node:fs/promises";
import path from "node:path";
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
import type { OpenClawConfig } from "./config.js";
import { resetConfigRuntimeState, type OpenClawConfig } from "./config.js";
export async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
return withTempHomeBase(fn, { prefix: "openclaw-config-" });
resetConfigRuntimeState();
try {
return await withTempHomeBase(fn, { prefix: "openclaw-config-" });
} finally {
resetConfigRuntimeState();
}
}
export async function writeOpenClawConfig(home: string, config: unknown): Promise<string> {