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) }) }); });