Files
openclaw/extensions/msteams/src/sqlite-state.test.ts
Peter Steinberger 83d82c9302 refactor(channels): persist runtime state in plugin SQLite (#109380)
* refactor(channels): move reef, msteams, matrix, zalouser file state to SQLite with doctor imports

* fix(channels): harden SQLite state migrations

* test(reef): use SQLite flow stores in receipt suites

* fix(reef): validate restored request policy

* fix(reef): retain replay state through relay window

* docs(reef): describe durable state import

* fix(reef): honor configured legacy state path

* chore: leave changelog to release flow

* fix(reef): use managed temp root in flow tests

* fix(matrix): omit undefined device id from state
2026-07-16 17:05:28 -07:00

48 lines
1.6 KiB
TypeScript

import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { setMSTeamsRuntime } from "./runtime.js";
import { withMSTeamsSqliteMutationLock } from "./sqlite-state.js";
import { msteamsRuntimeStub } from "./test-support/runtime.js";
describe("MSTeams SQLite mutation lock", () => {
let stateDir = "";
beforeEach(() => {
setMSTeamsRuntime(msteamsRuntimeStub);
stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-msteams-lock-"));
});
afterEach(() => {
fs.rmSync(stateDir, { recursive: true, force: true });
});
it("serializes concurrent mutations for the same state file", async () => {
let releaseFirst: (() => void) | undefined;
const firstEntered = vi.fn();
const secondEntered = vi.fn();
const first = withMSTeamsSqliteMutationLock({ stateDir }, "polls", async () => {
firstEntered();
await new Promise<void>((resolve) => {
releaseFirst = resolve;
});
return "first";
});
await vi.waitFor(() => expect(firstEntered).toHaveBeenCalledOnce());
const second = withMSTeamsSqliteMutationLock({ stateDir }, "polls", async () => {
secondEntered();
return "second";
});
await new Promise<void>((resolve) => {
setTimeout(resolve, 25);
});
expect(secondEntered).not.toHaveBeenCalled();
releaseFirst?.();
await expect(first).resolves.toBe("first");
await expect(second).resolves.toBe("second");
expect(secondEntered).toHaveBeenCalledOnce();
});
});