mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:20:43 +00:00
test(matrix): isolate IndexedDB persistence fixtures
This commit is contained in:
@@ -29,6 +29,8 @@ let persistIdbToDisk: typeof import("./idb-persistence.js").persistIdbToDisk;
|
||||
let restoreIdbFromDisk: typeof import("./idb-persistence.js").restoreIdbFromDisk;
|
||||
type CapturedLockOptions =
|
||||
typeof import("./idb-persistence-lock.js").MATRIX_IDB_SNAPSHOT_LOCK_OPTIONS;
|
||||
const DATABASE_PREFIX = "openclaw-matrix-lock-order-test";
|
||||
const cryptoDatabaseName = `${DATABASE_PREFIX}::matrix-sdk-crypto`;
|
||||
|
||||
beforeAll(async () => {
|
||||
({ persistIdbToDisk, restoreIdbFromDisk } = await import("./idb-persistence.js"));
|
||||
@@ -43,33 +45,32 @@ describe("Matrix IndexedDB persistence lock ordering", () => {
|
||||
withFileLockMock.mockImplementation(
|
||||
async <T>(_filePath: string, _options: unknown, fn: () => Promise<T>) => await fn(),
|
||||
);
|
||||
await clearAllIndexedDbState();
|
||||
await clearAllIndexedDbState({ databasePrefix: DATABASE_PREFIX });
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await clearAllIndexedDbState();
|
||||
await clearAllIndexedDbState({ databasePrefix: DATABASE_PREFIX });
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("captures the snapshot after the file lock is acquired", async () => {
|
||||
const snapshotPath = path.join(tmpDir, "crypto-idb-snapshot.json");
|
||||
const dbName = "openclaw-matrix-test::matrix-sdk-crypto";
|
||||
await seedDatabase({
|
||||
name: dbName,
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "old-session" } }],
|
||||
});
|
||||
|
||||
withFileLockMock.mockImplementationOnce(async (_filePath, _options, fn) => {
|
||||
await seedDatabase({
|
||||
name: dbName,
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "new-session" } }],
|
||||
});
|
||||
return await fn();
|
||||
});
|
||||
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" });
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX });
|
||||
|
||||
const data = JSON.parse(fs.readFileSync(snapshotPath, "utf8")) as Array<{
|
||||
stores: Array<{
|
||||
@@ -89,7 +90,7 @@ describe("Matrix IndexedDB persistence lock ordering", () => {
|
||||
capturedOptions.push(options as CapturedLockOptions);
|
||||
return 0;
|
||||
});
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" });
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX });
|
||||
|
||||
fs.writeFileSync(snapshotPath, "[]", "utf8");
|
||||
withFileLockMock.mockImplementationOnce(async (_filePath, options) => {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
export async function clearAllIndexedDbState(): Promise<void> {
|
||||
export async function clearAllIndexedDbState(params?: { databasePrefix?: string }): Promise<void> {
|
||||
const databases = await indexedDB.databases();
|
||||
const expectedPrefix = params?.databasePrefix ? `${params.databasePrefix}::` : null;
|
||||
await Promise.all(
|
||||
databases
|
||||
.map((entry) => entry.name)
|
||||
.filter((name): name is string => Boolean(name))
|
||||
.filter((name) => !expectedPrefix || name.startsWith(expectedPrefix))
|
||||
.map(
|
||||
(name) =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
|
||||
@@ -15,6 +15,16 @@ import {
|
||||
} from "./idb-persistence.test-helpers.js";
|
||||
import { LogService } from "./logger.js";
|
||||
|
||||
const DATABASE_PREFIX = "openclaw-matrix-persistence-test";
|
||||
const OTHER_DATABASE_PREFIX = "openclaw-matrix-persistence-other-test";
|
||||
const cryptoDatabaseName = `${DATABASE_PREFIX}::matrix-sdk-crypto`;
|
||||
const otherCryptoDatabaseName = `${OTHER_DATABASE_PREFIX}::matrix-sdk-crypto`;
|
||||
|
||||
async function clearTestIndexedDbState(): Promise<void> {
|
||||
await clearAllIndexedDbState({ databasePrefix: DATABASE_PREFIX });
|
||||
await clearAllIndexedDbState({ databasePrefix: OTHER_DATABASE_PREFIX });
|
||||
}
|
||||
|
||||
describe("Matrix IndexedDB persistence", () => {
|
||||
let tmpDir: string;
|
||||
let warnSpy: ReturnType<typeof vi.spyOn>;
|
||||
@@ -22,12 +32,12 @@ describe("Matrix IndexedDB persistence", () => {
|
||||
beforeEach(async () => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "matrix-idb-persist-"));
|
||||
warnSpy = vi.spyOn(LogService, "warn").mockImplementation(() => {});
|
||||
await clearAllIndexedDbState();
|
||||
await clearTestIndexedDbState();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
warnSpy.mockRestore();
|
||||
await clearAllIndexedDbState();
|
||||
await clearTestIndexedDbState();
|
||||
resetFileLockStateForTest();
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
@@ -35,38 +45,38 @@ describe("Matrix IndexedDB persistence", () => {
|
||||
it("persists and restores database contents for the selected prefix", async () => {
|
||||
const snapshotPath = path.join(tmpDir, "crypto-idb-snapshot.json");
|
||||
await seedDatabase({
|
||||
name: "openclaw-matrix-test::matrix-sdk-crypto",
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "abc123" } }],
|
||||
});
|
||||
await seedDatabase({
|
||||
name: "other-prefix::matrix-sdk-crypto",
|
||||
name: otherCryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-2", value: { session: "should-not-restore" } }],
|
||||
});
|
||||
|
||||
await persistIdbToDisk({
|
||||
snapshotPath,
|
||||
databasePrefix: "openclaw-matrix-test",
|
||||
databasePrefix: DATABASE_PREFIX,
|
||||
});
|
||||
expect(fs.existsSync(snapshotPath)).toBe(true);
|
||||
|
||||
const mode = fs.statSync(snapshotPath).mode & 0o777;
|
||||
expect(mode).toBe(0o600);
|
||||
|
||||
await clearAllIndexedDbState();
|
||||
await clearTestIndexedDbState();
|
||||
|
||||
const restored = await restoreIdbFromDisk(snapshotPath);
|
||||
expect(restored).toBe(true);
|
||||
|
||||
const restoredRecords = await readDatabaseRecords({
|
||||
name: "openclaw-matrix-test::matrix-sdk-crypto",
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
});
|
||||
expect(restoredRecords).toEqual([{ key: "room-1", value: { session: "abc123" } }]);
|
||||
|
||||
const dbs = await indexedDB.databases();
|
||||
expect(dbs.some((entry) => entry.name === "other-prefix::matrix-sdk-crypto")).toBe(false);
|
||||
expect(dbs.some((entry) => entry.name === otherCryptoDatabaseName)).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false and logs a warning for malformed snapshots", async () => {
|
||||
@@ -103,14 +113,14 @@ describe("Matrix IndexedDB persistence", () => {
|
||||
it("serializes concurrent persist operations via file lock", async () => {
|
||||
const snapshotPath = path.join(tmpDir, "concurrent-persist.json");
|
||||
await seedDatabase({
|
||||
name: "openclaw-matrix-test::matrix-sdk-crypto",
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "abc123" } }],
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" }),
|
||||
persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" }),
|
||||
persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX }),
|
||||
persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX }),
|
||||
]);
|
||||
|
||||
expect(fs.existsSync(snapshotPath)).toBe(true);
|
||||
@@ -123,12 +133,12 @@ describe("Matrix IndexedDB persistence", () => {
|
||||
it("releases lock after persist completes", async () => {
|
||||
const snapshotPath = path.join(tmpDir, "lock-release.json");
|
||||
await seedDatabase({
|
||||
name: "openclaw-matrix-test::matrix-sdk-crypto",
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "abc123" } }],
|
||||
});
|
||||
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" });
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX });
|
||||
|
||||
const lockPath = `${snapshotPath}.lock`;
|
||||
expect(fs.existsSync(lockPath)).toBe(false);
|
||||
@@ -138,13 +148,13 @@ describe("Matrix IndexedDB persistence", () => {
|
||||
it("releases lock after restore completes", async () => {
|
||||
const snapshotPath = path.join(tmpDir, "lock-release-restore.json");
|
||||
await seedDatabase({
|
||||
name: "openclaw-matrix-test::matrix-sdk-crypto",
|
||||
name: cryptoDatabaseName,
|
||||
storeName: "sessions",
|
||||
records: [{ key: "room-1", value: { session: "abc123" } }],
|
||||
});
|
||||
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: "openclaw-matrix-test" });
|
||||
await clearAllIndexedDbState();
|
||||
await persistIdbToDisk({ snapshotPath, databasePrefix: DATABASE_PREFIX });
|
||||
await clearTestIndexedDbState();
|
||||
await drainFileLockStateForTest();
|
||||
|
||||
await restoreIdbFromDisk(snapshotPath);
|
||||
|
||||
Reference in New Issue
Block a user