nlocks/__tests__/async-lock.test.js

137 lines
3.6 KiB
JavaScript

const AsyncLock = require('../async-lock');
describe('AsyncLock', () => {
let lock;
beforeEach(() => {
lock = new AsyncLock();
});
describe('acquire and release', () => {
test('should acquire lock without waiting when not locked', async () => {
const startTime = Date.now();
await lock.acquire();
const endTime = Date.now();
// Should resolve almost immediately (no waiting)
expect(endTime - startTime).toBeLessThan(10);
lock.release();
});
test('should protect async function without waiting when not locked', async () => {
let protectedFunctionCalled = false;
const protectedFunction = async () => {
await lock.acquire();
protectedFunctionCalled = true;
// Simulate some async work
await new Promise(resolve => setTimeout(resolve, 10));
lock.release();
return 'done';
};
const result = await protectedFunction();
expect(protectedFunctionCalled).toBe(true);
expect(result).toBe('done');
});
test('should allow consecutive acquisitions and releases without queueing', async () => {
// First acquisition
await lock.acquire();
expect(lock.locked).toBe(true);
lock.release();
// Second acquisition
await lock.acquire();
expect(lock.locked).toBe(true);
lock.release();
// Third acquisition
await lock.acquire();
expect(lock.locked).toBe(true);
lock.release();
});
test('should handle multiple concurrent acquisitions correctly', async () => {
let counter = 0;
const incrementCounter = async () => {
await lock.acquire();
const temp = counter;
// Simulate some async work that could cause race condition
await new Promise(resolve => setTimeout(resolve, 1));
counter = temp + 1;
lock.release();
};
// Run multiple concurrent operations
await Promise.all([
incrementCounter(),
incrementCounter(),
incrementCounter()
]);
expect(counter).toBe(3);
});
test('should handle case where release is called without any pending acquirers', () => {
// Initially unlocked
expect(lock.locked).toBe(false);
// Calling release on unlocked lock should not error
lock.release();
expect(lock.locked).toBe(false);
});
test('should properly queue multiple concurrent requests', async () => {
let executionOrder = [];
const task = async (id) => {
await lock.acquire();
executionOrder.push(id);
// Simulate work
await new Promise(resolve => setTimeout(resolve, 10));
lock.release();
return id;
};
// Start multiple concurrent tasks
const tasks = [
task(1),
task(2),
task(3)
];
const r = await Promise.all(tasks);
// All tasks should execute in order
expect(executionOrder).toEqual([1, 2, 3]);
expect(r).toEqual([1, 2, 3]);
});
test('no await for async function',async()=>{
const results= []
async function task(prefix, count) {
await lock.acquire()
let i = 0
const h = setInterval(() => {
results.push(`${prefix}${i}`)
i++
if (i >= count) {
lock.release()
clearInterval(h)
}
},10)
}
task('a', 5)
task('b', 5)
task('c', 5)
await lock.acquire()
const r = results.join('')
expect(r.includes('a0a1a2a3a4')).toBe(true)
})
});
});