mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 20:24:46 +00:00
test: cover sync clobber snapshot collisions
This commit is contained in:
@@ -75,6 +75,23 @@ describe("config clobber snapshots", () => {
|
||||
}
|
||||
}
|
||||
|
||||
function touchClobberFilesByContentOrderSync(configPath: string): void {
|
||||
const dir = path.dirname(configPath);
|
||||
const prefix = `${path.basename(configPath)}.clobbered.`;
|
||||
for (const entry of fs.readdirSync(dir)) {
|
||||
if (!entry.startsWith(prefix)) {
|
||||
continue;
|
||||
}
|
||||
const targetPath = path.join(dir, entry);
|
||||
const match = /^polluted-(\d+)\n$/.exec(fs.readFileSync(targetPath, "utf-8"));
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
const touchedAt = new Date(`2026-05-03T00:00:${match[1].padStart(2, "0")}.000Z`);
|
||||
fs.utimesSync(targetPath, touchedAt, touchedAt);
|
||||
}
|
||||
}
|
||||
|
||||
it("keeps concurrent async snapshots under the per-path cap by rotating oldest files", async () => {
|
||||
await withCase(async (configPath) => {
|
||||
const warn = vi.fn();
|
||||
@@ -227,4 +244,42 @@ describe("config clobber snapshots", () => {
|
||||
expect(capWarnings).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps rotating same-timestamp sync snapshots after the base artifact is reused", async () => {
|
||||
await withCase(async (configPath) => {
|
||||
const warn = vi.fn();
|
||||
const observedAt = "2026-05-03T00:00:00.000Z";
|
||||
|
||||
for (let index = 0; index < CONFIG_CLOBBER_SNAPSHOT_LIMIT; index++) {
|
||||
persistBoundedClobberedConfigSnapshotSync({
|
||||
deps: { fs, logger: { warn } },
|
||||
configPath,
|
||||
raw: `polluted-${index}\n`,
|
||||
observedAt,
|
||||
});
|
||||
}
|
||||
touchClobberFilesByContentOrderSync(configPath);
|
||||
|
||||
for (
|
||||
let index = CONFIG_CLOBBER_SNAPSHOT_LIMIT;
|
||||
index < CONFIG_CLOBBER_SNAPSHOT_LIMIT + 3;
|
||||
index++
|
||||
) {
|
||||
persistBoundedClobberedConfigSnapshotSync({
|
||||
deps: { fs, logger: { warn } },
|
||||
configPath,
|
||||
raw: `polluted-${index}\n`,
|
||||
observedAt,
|
||||
});
|
||||
}
|
||||
|
||||
const clobberFiles = await listClobberFiles(configPath);
|
||||
expect(clobberFiles).toHaveLength(CONFIG_CLOBBER_SNAPSHOT_LIMIT);
|
||||
const contents = await readClobberFileContents(configPath);
|
||||
expect(contents).not.toContain("polluted-0\n");
|
||||
expect(contents).not.toContain("polluted-1\n");
|
||||
expect(contents).not.toContain("polluted-2\n");
|
||||
expect(contents).toContain(`polluted-${CONFIG_CLOBBER_SNAPSHOT_LIMIT + 2}\n`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -137,6 +137,20 @@ function compareClobberedSiblings(
|
||||
);
|
||||
}
|
||||
|
||||
function createClobberedSiblingSnapshot(params: {
|
||||
dir: string;
|
||||
entry: string;
|
||||
prefix: string;
|
||||
mtimeMs: number;
|
||||
}): ClobberedSiblingSnapshot {
|
||||
return {
|
||||
name: params.entry,
|
||||
path: path.join(params.dir, params.entry),
|
||||
timestampKey: params.entry.slice(params.prefix.length).replace(/-\d{2}$/, ""),
|
||||
mtimeMs: params.mtimeMs,
|
||||
};
|
||||
}
|
||||
|
||||
async function listClobberedSiblings(
|
||||
deps: ConfigClobberSnapshotDeps,
|
||||
dir: string,
|
||||
@@ -149,14 +163,15 @@ async function listClobberedSiblings(
|
||||
if (!entry.startsWith(prefix)) {
|
||||
continue;
|
||||
}
|
||||
const snapshotPath = path.join(dir, entry);
|
||||
const stat = await deps.fs.promises.stat(snapshotPath).catch(() => null);
|
||||
snapshots.push({
|
||||
name: entry,
|
||||
path: snapshotPath,
|
||||
timestampKey: entry.slice(prefix.length).replace(/-\d{2}$/, ""),
|
||||
mtimeMs: stat?.mtimeMs ?? 0,
|
||||
});
|
||||
const stat = await deps.fs.promises.stat(path.join(dir, entry)).catch(() => null);
|
||||
snapshots.push(
|
||||
createClobberedSiblingSnapshot({
|
||||
dir,
|
||||
entry,
|
||||
prefix,
|
||||
mtimeMs: stat?.mtimeMs ?? 0,
|
||||
}),
|
||||
);
|
||||
}
|
||||
return snapshots.toSorted(compareClobberedSiblings);
|
||||
} catch {
|
||||
@@ -175,14 +190,15 @@ function listClobberedSiblingsSync(
|
||||
if (!entry.startsWith(prefix)) {
|
||||
continue;
|
||||
}
|
||||
const snapshotPath = path.join(dir, entry);
|
||||
const stat = deps.fs.statSync(snapshotPath, { throwIfNoEntry: false });
|
||||
snapshots.push({
|
||||
name: entry,
|
||||
path: snapshotPath,
|
||||
timestampKey: entry.slice(prefix.length).replace(/-\d{2}$/, ""),
|
||||
mtimeMs: stat?.mtimeMs ?? 0,
|
||||
});
|
||||
const stat = deps.fs.statSync(path.join(dir, entry), { throwIfNoEntry: false });
|
||||
snapshots.push(
|
||||
createClobberedSiblingSnapshot({
|
||||
dir,
|
||||
entry,
|
||||
prefix,
|
||||
mtimeMs: stat?.mtimeMs ?? 0,
|
||||
}),
|
||||
);
|
||||
}
|
||||
return snapshots.toSorted(compareClobberedSiblings);
|
||||
} catch {
|
||||
|
||||
Reference in New Issue
Block a user