lik/test/test.asyncexecutionstack.both.ts

92 lines
3.3 KiB
TypeScript

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<void>[] = [];
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();