From 6ca6cf6bc0d26cabd5ac40083145680b39485bf9 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Sun, 15 Feb 2026 21:56:39 +0000 Subject: [PATCH] fix(tests): improve buffered task tests: add chain, concurrency and queue behavior tests --- changelog.md | 8 ++ test/test.8.bufferedrun.ts | 173 +++++++++++++++++++++++++++-------- ts/00_commitinfo_data.ts | 2 +- ts_web/00_commitinfo_data.ts | 2 +- 4 files changed, 146 insertions(+), 39 deletions(-) diff --git a/changelog.md b/changelog.md index de7f039..a6d90ad 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # 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) add sliding-window rate limiting and result-sharing to TaskConstraintGroup and integrate with TaskManager diff --git a/test/test.8.bufferedrun.ts b/test/test.8.bufferedrun.ts index 39ef88e..7eb55b3 100644 --- a/test/test.8.bufferedrun.ts +++ b/test/test.8.bufferedrun.ts @@ -1,52 +1,151 @@ import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as taskbuffer from '../ts/index.js'; +import * as smartdelay from '@push.rocks/smartdelay'; -let counter1 = 0; -let counter2 = 0; -let counter3 = 0; +// Test 1: Basic buffered execution with afterTask chain +tap.test('should run buffered tasks with afterTask chain', async () => { + 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({ - name: 'a buffered task', + name: 'buffered-chain-3', taskFunction: async () => { counter3++; - await tools.delayFor(2000); - console.log(`task3 ran ${counter3} times`); + await smartdelay.delayFor(50); }, buffered: true, bufferMax: 1, }); - while (counter1 < 10) { - await tools.delayFor(5000); - task.trigger(); + + const task2 = new taskbuffer.Task({ + 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(); diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 31cd368..994166c 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { 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.' } diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts index 31cd368..994166c 100644 --- a/ts_web/00_commitinfo_data.ts +++ b/ts_web/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { 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.' }