fix(tests): improve buffered task tests: add chain, concurrency and queue behavior tests
This commit is contained in:
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-02-15 - 6.1.1 - fix(tests)
|
||||||
|
improve buffered task tests: add chain, concurrency and queue behavior tests
|
||||||
|
|
||||||
|
- Replace tools.delayFor with @push.rocks/smartdelay for more deterministic timing in tests
|
||||||
|
- Add tests for afterTask chaining, bufferMax concurrency, queued-run limits, and re-trigger behavior
|
||||||
|
- Rename tasks to descriptive names and fix afterTask chaining order to avoid circular references
|
||||||
|
- Change test runner invocation to export default tap.start() instead of calling tap.start() directly
|
||||||
|
|
||||||
## 2026-02-15 - 6.1.0 - feat(taskbuffer)
|
## 2026-02-15 - 6.1.0 - feat(taskbuffer)
|
||||||
add sliding-window rate limiting and result-sharing to TaskConstraintGroup and integrate with TaskManager
|
add sliding-window rate limiting and result-sharing to TaskConstraintGroup and integrate with TaskManager
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,151 @@
|
|||||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||||
|
|
||||||
import * as taskbuffer from '../ts/index.js';
|
import * as taskbuffer from '../ts/index.js';
|
||||||
|
import * as smartdelay from '@push.rocks/smartdelay';
|
||||||
|
|
||||||
let counter1 = 0;
|
// Test 1: Basic buffered execution with afterTask chain
|
||||||
let counter2 = 0;
|
tap.test('should run buffered tasks with afterTask chain', async () => {
|
||||||
let counter3 = 0;
|
let counter1 = 0;
|
||||||
|
let counter2 = 0;
|
||||||
|
let counter3 = 0;
|
||||||
|
|
||||||
tap.test('should run buffered', async (tools) => {
|
|
||||||
const task = new taskbuffer.Task({
|
|
||||||
name: 'a buffered task',
|
|
||||||
taskFunction: async () => {
|
|
||||||
counter1++;
|
|
||||||
await tools.delayFor(2000);
|
|
||||||
console.log(`task 1 ran ${counter1} times`);
|
|
||||||
},
|
|
||||||
buffered: true,
|
|
||||||
bufferMax: 1,
|
|
||||||
afterTask: () => {
|
|
||||||
return task2;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const task2 = new taskbuffer.Task({
|
|
||||||
name: 'a buffered task',
|
|
||||||
taskFunction: async () => {
|
|
||||||
counter2++;
|
|
||||||
await tools.delayFor(2000);
|
|
||||||
console.log(`task2 ran ${counter2} times`);
|
|
||||||
},
|
|
||||||
buffered: true,
|
|
||||||
bufferMax: 1,
|
|
||||||
afterTask: () => {
|
|
||||||
return task3;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const task3 = new taskbuffer.Task({
|
const task3 = new taskbuffer.Task({
|
||||||
name: 'a buffered task',
|
name: 'buffered-chain-3',
|
||||||
taskFunction: async () => {
|
taskFunction: async () => {
|
||||||
counter3++;
|
counter3++;
|
||||||
await tools.delayFor(2000);
|
await smartdelay.delayFor(50);
|
||||||
console.log(`task3 ran ${counter3} times`);
|
|
||||||
},
|
},
|
||||||
buffered: true,
|
buffered: true,
|
||||||
bufferMax: 1,
|
bufferMax: 1,
|
||||||
});
|
});
|
||||||
while (counter1 < 10) {
|
|
||||||
await tools.delayFor(5000);
|
const task2 = new taskbuffer.Task({
|
||||||
task.trigger();
|
name: 'buffered-chain-2',
|
||||||
|
taskFunction: async () => {
|
||||||
|
counter2++;
|
||||||
|
await smartdelay.delayFor(50);
|
||||||
|
},
|
||||||
|
buffered: true,
|
||||||
|
bufferMax: 1,
|
||||||
|
afterTask: () => task3,
|
||||||
|
});
|
||||||
|
|
||||||
|
const task1 = new taskbuffer.Task({
|
||||||
|
name: 'buffered-chain-1',
|
||||||
|
taskFunction: async () => {
|
||||||
|
counter1++;
|
||||||
|
await smartdelay.delayFor(50);
|
||||||
|
},
|
||||||
|
buffered: true,
|
||||||
|
bufferMax: 1,
|
||||||
|
afterTask: () => task2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Trigger 3 times with enough spacing for the chain to complete
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
task1.trigger();
|
||||||
|
await smartdelay.delayFor(250); // enough for chain of 3 x 50ms tasks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for final chain to finish
|
||||||
|
await smartdelay.delayFor(500);
|
||||||
|
|
||||||
|
// Each task in the chain should have run at least once
|
||||||
|
expect(counter1).toBeGreaterThanOrEqual(1);
|
||||||
|
expect(counter2).toBeGreaterThanOrEqual(1);
|
||||||
|
expect(counter3).toBeGreaterThanOrEqual(1);
|
||||||
|
|
||||||
|
// afterTask chain means task2 count should match task1 (each trigger chains)
|
||||||
|
expect(counter2).toEqual(counter1);
|
||||||
|
expect(counter3).toEqual(counter1);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.start();
|
// Test 2: bufferMax limits concurrent buffered executions
|
||||||
|
tap.test('should respect bufferMax for concurrent buffered calls', async () => {
|
||||||
|
let running = 0;
|
||||||
|
let maxRunning = 0;
|
||||||
|
let totalRuns = 0;
|
||||||
|
|
||||||
|
const task = new taskbuffer.Task({
|
||||||
|
name: 'buffer-max-test',
|
||||||
|
taskFunction: async () => {
|
||||||
|
running++;
|
||||||
|
maxRunning = Math.max(maxRunning, running);
|
||||||
|
totalRuns++;
|
||||||
|
await smartdelay.delayFor(100);
|
||||||
|
running--;
|
||||||
|
},
|
||||||
|
buffered: true,
|
||||||
|
bufferMax: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fire many triggers rapidly — only bufferMax should run concurrently
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
task.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for all buffered executions to complete
|
||||||
|
await smartdelay.delayFor(1000);
|
||||||
|
|
||||||
|
expect(maxRunning).toBeLessThanOrEqual(2);
|
||||||
|
expect(totalRuns).toBeGreaterThanOrEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 3: bufferMax limits how many runs are queued during execution
|
||||||
|
tap.test('should limit queued runs to bufferMax during execution', async () => {
|
||||||
|
let runCount = 0;
|
||||||
|
|
||||||
|
const task = new taskbuffer.Task({
|
||||||
|
name: 'buffer-queue-test',
|
||||||
|
taskFunction: async () => {
|
||||||
|
runCount++;
|
||||||
|
await smartdelay.delayFor(100);
|
||||||
|
},
|
||||||
|
buffered: true,
|
||||||
|
bufferMax: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rapid-fire 5 triggers — bufferMax:2 means counter caps at 2
|
||||||
|
// so only 2 runs will happen (the initial run + 1 buffered rerun)
|
||||||
|
task.trigger();
|
||||||
|
task.trigger();
|
||||||
|
task.trigger();
|
||||||
|
task.trigger();
|
||||||
|
task.trigger();
|
||||||
|
|
||||||
|
await smartdelay.delayFor(500);
|
||||||
|
|
||||||
|
expect(runCount).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 4: Triggers spaced after completion queue new runs
|
||||||
|
tap.test('should re-trigger after previous buffered run completes', async () => {
|
||||||
|
let runCount = 0;
|
||||||
|
|
||||||
|
const task = new taskbuffer.Task({
|
||||||
|
name: 'retrigger-test',
|
||||||
|
taskFunction: async () => {
|
||||||
|
runCount++;
|
||||||
|
await smartdelay.delayFor(50);
|
||||||
|
},
|
||||||
|
buffered: true,
|
||||||
|
bufferMax: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// First trigger starts execution
|
||||||
|
task.trigger();
|
||||||
|
// Wait for it to complete
|
||||||
|
await smartdelay.delayFor(100);
|
||||||
|
|
||||||
|
// Second trigger starts a new execution (task is now idle)
|
||||||
|
task.trigger();
|
||||||
|
await smartdelay.delayFor(100);
|
||||||
|
|
||||||
|
// Third trigger
|
||||||
|
task.trigger();
|
||||||
|
await smartdelay.delayFor(100);
|
||||||
|
|
||||||
|
expect(runCount).toEqual(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/taskbuffer',
|
name: '@push.rocks/taskbuffer',
|
||||||
version: '6.1.0',
|
version: '6.1.1',
|
||||||
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/taskbuffer',
|
name: '@push.rocks/taskbuffer',
|
||||||
version: '6.1.0',
|
version: '6.1.1',
|
||||||
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
description: 'A flexible task management library supporting TypeScript, allowing for task buffering, scheduling, and execution with dependency management.'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user