Files
2026-10-03 19:21:53 +01:00

102 lines
2.6 KiB
TypeScript

/* eslint-disable import/prefer-default-export */
import { mkdirp } from 'fs-extra';
import { mkdtemp, utimes } from 'fs/promises';
import { FileLocker } from './fs';
import { msleep, Second } from './time';
const baseTempDir = `${__dirname}/../app-cli/tests/tmp`;
export const createTempDir = async () => {
await mkdirp(baseTempDir);
return mkdtemp(`${baseTempDir}/`);
};
describe('fs', () => {
it('should lock files', async () => {
const dirPath = await createTempDir();
const filePath = `${dirPath}/test.lock`;
const locker1 = new FileLocker(filePath, {
interval: 10 * Second,
});
expect(await locker1.lock()).toBe(true);
expect(await locker1.lock()).toBe(false);
locker1.unlockSync();
const locker2 = new FileLocker(filePath, {
interval: 1.5 * Second,
});
expect(await locker2.lock()).toBe(true);
locker2.stopMonitoring_();
const locker3 = new FileLocker(filePath, {
interval: 1.5 * Second,
});
await msleep(2 * Second);
expect(await locker3.lock()).toBe(true);
locker3.unlockSync();
});
it('should not unlock a file owned by another locker', async () => {
const dirPath = await createTempDir();
const filePath = `${dirPath}/test.lock`;
const options = { interval: 10 * Second };
const locker1 = new FileLocker(filePath, options);
const locker2 = new FileLocker(filePath, options);
const locker3 = new FileLocker(filePath, options);
expect(await locker1.lock()).toBe(true);
expect(await locker2.lock()).toBe(false);
locker2.unlockSync();
expect(await locker3.lock()).toBe(false);
locker1.unlockSync();
expect(await locker3.lock()).toBe(true);
locker3.unlockSync();
});
it('should not unlock a file taken over by another locker', async () => {
const dirPath = await createTempDir();
const filePath = `${dirPath}/test.lock`;
const options = { interval: 10 * Second };
const locker1 = new FileLocker(filePath, options);
const locker2 = new FileLocker(filePath, options);
const locker3 = new FileLocker(filePath, options);
try {
expect(await locker1.lock()).toBe(true);
// Simulate a delayed heartbeat without clearing the old owner's timer.
const staleTime = new Date(Date.now() - 2 * options.interval);
await utimes(filePath, staleTime, staleTime);
expect(await locker2.lock()).toBe(true);
locker1.unlockSync();
expect(await locker3.lock()).toBe(false);
locker2.unlockSync();
expect(await locker3.lock()).toBe(true);
// Repeated cleanup must also preserve a subsequent owner's lock.
locker2.unlockSync();
expect(await locker1.lock()).toBe(false);
} finally {
locker1.unlockSync();
locker2.unlockSync();
locker3.unlockSync();
}
});
});