import { afterEach, assert, beforeAll, describe, expect, it } from "vitest"; import { migrations } from "./routines"; import { acquireLock, isDBLocked, refreshLock, releaseLock } from "./lock"; import { Semaphores } from "$lib/types/Semaphore"; import { collections } from "$lib/server/database"; describe( "migrations", { retry: 3, }, () => { beforeAll(async () => { try { await collections.semaphores.createIndex({ key: 1 }, { unique: true }); } catch (e) { // Index might already exist, ignore error } }); it("should not have duplicates guid", async () => { const guids = migrations.map((m) => m._id.toString()); const uniqueGuids = [...new Set(guids)]; expect(uniqueGuids.length).toBe(guids.length); }); it("should acquire only one lock on DB", async () => { const results = await Promise.all( new Array(1000).fill(0).map(() => acquireLock(Semaphores.TEST_MIGRATION)) ); const locks = results.filter((r) => r); const semaphores = await collections.semaphores.find({}).toArray(); expect(locks.length).toBe(1); expect(semaphores).toBeDefined(); expect(semaphores.length).toBe(1); expect(semaphores?.[0].key).toBe(Semaphores.TEST_MIGRATION); }); it("should read the lock correctly", async () => { const lockId = await acquireLock(Semaphores.TEST_MIGRATION); assert(lockId); expect(await isDBLocked(Semaphores.TEST_MIGRATION)).toBe(true); expect(!!(await acquireLock(Semaphores.TEST_MIGRATION))).toBe(false); await releaseLock(Semaphores.TEST_MIGRATION, lockId); expect(await isDBLocked(Semaphores.TEST_MIGRATION)).toBe(false); }); it("should refresh the lock", async () => { const lockId = await acquireLock(Semaphores.TEST_MIGRATION); assert(lockId); // get the updatedAt time const updatedAtInitially = (await collections.semaphores.findOne({}))?.updatedAt; await refreshLock(Semaphores.TEST_MIGRATION, lockId); const updatedAtAfterRefresh = (await collections.semaphores.findOne({}))?.updatedAt; expect(updatedAtInitially).toBeDefined(); expect(updatedAtAfterRefresh).toBeDefined(); expect(updatedAtInitially).not.toBe(updatedAtAfterRefresh); }); afterEach(async () => { await collections.semaphores.deleteMany({}); await collections.migrationResults.deleteMany({}); }); } );