openclaw / src /boards /sqlite-board-store.batching.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
d197cf3 verified
Raw History Blame Contribute Delete
3.95 kB
import { afterEach, expect, it } from "vitest";
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
import {
closeOpenClawAgentDatabasesForTest,
openOpenClawAgentDatabase,
} from "../state/openclaw-agent-db.js";
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
import { createTestBoardStore, readBoardHtml } from "./board-store.test-support.js";
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
afterEach(() => {
closeOpenClawAgentDatabasesForTest();
closeOpenClawStateDatabaseForTest();
});
it("round-trips and removes a board with many tabs", async () => {
const store = createTestBoardStore();
const target = { sessionKey: "agent:main:many-tabs" };
const tabIds = Array.from({ length: 130 }, (_, index) => `tab-${index}`);
const created = await store.applyOps(
target,
tabIds.map((tabId) => ({ kind: "tab_create", tabId, title: tabId })),
);
expect(created.tabs.map((tab) => tab.tabId)).toEqual(tabIds);
expect(await store.getSnapshot(target)).toEqual(created);
expect(
await store.applyOps(
target,
tabIds.map((tabId) => ({ kind: "tab_delete", tabId })),
),
).toEqual({
...target,
revision: 2,
tabs: [],
widgets: [],
});
expect(await store.getSnapshot(target)).toEqual({
...target,
revision: 0,
tabs: [],
widgets: [],
});
});
it("rolls back late board writes and preserves surviving widget documents", async () => {
const stateDir = tempDirs.make("openclaw-board-batch-rollback-");
const env = { OPENCLAW_STATE_DIR: stateDir };
const sessionKey = "agent:main:batch-rollback";
const store = createTestBoardStore({ stateDir });
const tabIds = Array.from({ length: 130 }, (_, index) => `tab-${index}`);
await store.applyOps(
{ sessionKey },
tabIds.map((tabId) => ({
kind: "tab_create",
tabId,
title: tabId,
})),
);
const widgetNames = tabIds.slice(0, 48);
for (const name of widgetNames) {
await store.putWidget({ sessionKey, name, content: { kind: "html", html: name } });
}
const before = await store.getSnapshot({ sessionKey });
const database = openOpenClawAgentDatabase({ agentId: "main", env });
const readRows = () => ({
tabs: database.db.prepare("SELECT * FROM board_tabs ORDER BY session_key, tab_id").all(),
widgets: database.db.prepare("SELECT * FROM board_widgets ORDER BY session_key, name").all(),
});
const beforeRows = readRows();
database.db.exec(`CREATE TEMP TRIGGER reject_late_tab_write BEFORE UPDATE ON board_tabs
WHEN NEW.tab_id = 'tab-129' BEGIN SELECT RAISE(ABORT, 'late tab write'); END;`);
await expect(
store.applyOps({ sessionKey }, [
{
kind: "tab_update",
tabId: "tab-0",
title: "changed",
},
]),
).rejects.toThrow("late tab write");
expect(readRows()).toEqual(beforeRows);
database.db.exec("DROP TRIGGER reject_late_tab_write");
expect(await store.getSnapshot({ sessionKey })).toEqual(before);
const removedNames = widgetNames.slice(0, -1);
const removeOps = removedNames.map((name) => ({ kind: "widget_remove" as const, name }));
database.db.exec(`CREATE TEMP TRIGGER reject_late_widget_delete BEFORE DELETE ON board_widgets
WHEN OLD.name = 'tab-46' BEGIN SELECT RAISE(ABORT, 'late widget delete'); END;`);
await expect(store.applyOps({ sessionKey }, removeOps)).rejects.toThrow("late widget delete");
expect(readRows()).toEqual(beforeRows);
database.db.exec("DROP TRIGGER reject_late_widget_delete");
const removed = await store.applyOps({ sessionKey }, removeOps);
expect(removed.widgets.map((widget) => widget.name)).toEqual(["tab-47"]);
expect(await store.getSnapshot({ sessionKey })).toEqual(removed);
expect(await readBoardHtml(store, { sessionKey }, "tab-47")).toMatchObject({
html: "tab-47",
});
expect(await readBoardHtml(store, { sessionKey }, "tab-46")).toBeUndefined();
});