mega-plant/lib/clock-lock.test.ts

22 lines
1.4 KiB
TypeScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { acquireEmployeeLock, type LockBackend } from './clock-lock';
const now=Date.parse('2026-10-21T08:00:00Z');
function backend(age:number) {
let current:{id:string;created:string}|null={id:'old',created:new Date(now-age).toISOString()};
const api:LockBackend={create:async()=>{if(current)throw {status:400};current={id:'new',created:new Date(now).toISOString()};return current;},find:async()=>current,remove:async id=>{if(current?.id!==id)throw{status:404};current=null;}};
return {api,current:()=>current};
}
test('live locks block another device; abandoned locks are recoverable',async()=>{
await assert.rejects(()=>acquireEmployeeLock(backend(60_000).api,'worker',now),/Another scan/);
const expired=backend(121_000);assert.equal(await acquireEmployeeLock(expired.api,'worker',now),'new');
});
test('release of an expired owner never deletes a newer lock',async()=>{
const expired=backend(121_000);await acquireEmployeeLock(expired.api,'worker',now);
await assert.rejects(()=>expired.api.remove('old'));
assert.equal(expired.current()?.id,'new');
});
test('database outages do not lead to stealing a lock',async()=>{
const b=backend(121_000);b.api.create=async()=>{throw{status:503};};
await assert.rejects(()=>acquireEmployeeLock(b.api,'worker',now));assert.equal(b.current()?.id,'old');
});