import { tap, expect } from '@push.rocks/tapbundle'; import * as lik from '../ts/index.js'; let testAsyncExecutionStack: lik.AsyncExecutionStack; tap.test('should create a valid instance of AsyncExectionStack', async () => { testAsyncExecutionStack = new lik.AsyncExecutionStack(); expect(testAsyncExecutionStack).toBeInstanceOf(lik.AsyncExecutionStack); }); tap.test('should run in parallel', async (toolsArg) => { await testAsyncExecutionStack.getExclusiveExecutionSlot(async () => { await toolsArg.delayFor(2000); console.log('should run first'); }, 2500); testAsyncExecutionStack.getNonExclusiveExecutionSlot(async () => { await toolsArg.delayFor(2000); console.log('should run third'); }, 2500); testAsyncExecutionStack.getNonExclusiveExecutionSlot(async () => { await toolsArg.delayFor(1000); console.log('should run second'); }, 2500); await testAsyncExecutionStack.getExclusiveExecutionSlot(async () => { console.log('should run fourth'); }, 0); }); // Test default non-exclusive has no concurrency limit property (Infinity) tap.test('default non-exclusive has no concurrency limit', () => { const stack = new lik.AsyncExecutionStack(); // default maxConcurrency is Infinity (not finite) expect(Number.isFinite(stack.getNonExclusiveMaxConcurrency())).toBeFalse(); }); // Test respecting a non-exclusive concurrency limit tap.test('non-exclusive respects maxConcurrency', async (tools) => { const stack = new lik.AsyncExecutionStack(); stack.setNonExclusiveMaxConcurrency(2); const activeCounts: number[] = []; const tasks: Promise[] = []; for (let i = 0; i < 5; i++) { tasks.push( stack.getNonExclusiveExecutionSlot(async () => { activeCounts.push(stack.getActiveNonExclusiveCount()); await tools.delayFor(50); }) ); } await Promise.all(tasks); // never more than 2 at once const maxActive = Math.max(...activeCounts); expect(maxActive).toBeLessThanOrEqual(2); }); // Test concurrency stats (active vs pending) for non-exclusive tasks tap.test('non-exclusive concurrency stats reflect active and pending', async (tools) => { const stack = new lik.AsyncExecutionStack(); stack.setNonExclusiveMaxConcurrency(2); // initially, no tasks expect(stack.getActiveNonExclusiveCount()).toEqual(0); expect(stack.getPendingNonExclusiveCount()).toEqual(0); // enqueue four tasks const p1 = stack.getNonExclusiveExecutionSlot(async () => { await tools.delayFor(30); }); const p2 = stack.getNonExclusiveExecutionSlot(async () => { await tools.delayFor(30); }); const p3 = stack.getNonExclusiveExecutionSlot(async () => { await tools.delayFor(30); }); const p4 = stack.getNonExclusiveExecutionSlot(async () => { await tools.delayFor(30); }); // wait for first task to finish and scheduling of next batch await p1; await tools.delayFor(0); // second batch: two active, one pending (4 tasks, limit=2) expect(stack.getActiveNonExclusiveCount()).toEqual(2); expect(stack.getPendingNonExclusiveCount()).toEqual(1); // wait for remaining tasks to complete await Promise.all([p2, p3, p4]); // after completion, counts reset expect(stack.getActiveNonExclusiveCount()).toEqual(0); expect(stack.getPendingNonExclusiveCount()).toEqual(0); }); export default tap.start();