From 26fb3c18b678a1daab6b18a351a238fb5a3ed5df Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 26 Aug 2023 23:43:27 +0200 Subject: [PATCH] test: add worker node tests MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/pools/worker-node.ts | 12 +- src/pools/worker.ts | 8 +- tests/pools/abstract/worker-node.test.js | 163 +++++++++++++++++++++++ 3 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 tests/pools/abstract/worker-node.test.js diff --git a/src/pools/worker-node.ts b/src/pools/worker-node.ts index 079881b9..4799e11c 100644 --- a/src/pools/worker-node.ts +++ b/src/pools/worker-node.ts @@ -30,18 +30,18 @@ implements IWorkerNode { /** @inheritdoc */ public readonly info: WorkerInfo /** @inheritdoc */ - public messageChannel?: MessageChannel - /** @inheritdoc */ public usage: WorkerUsage /** @inheritdoc */ + public messageChannel?: MessageChannel + /** @inheritdoc */ public tasksQueueBackPressureSize: number /** @inheritdoc */ public onBackPressure?: (workerId: number) => void /** @inheritdoc */ public onEmptyQueue?: (workerId: number) => void - private readonly taskFunctionsUsage: Map private readonly tasksQueue: Deque> private onEmptyQueueCount: number + private readonly taskFunctionsUsage: Map /** * Constructs a new worker node. @@ -75,14 +75,14 @@ implements IWorkerNode { } this.worker = worker this.info = this.initWorkerInfo(worker, workerType) + this.usage = this.initWorkerUsage() if (workerType === WorkerTypes.thread) { this.messageChannel = new MessageChannel() } - this.usage = this.initWorkerUsage() - this.taskFunctionsUsage = new Map() - this.tasksQueue = new Deque>() this.tasksQueueBackPressureSize = tasksQueueBackPressureSize + this.tasksQueue = new Deque>() this.onEmptyQueueCount = 0 + this.taskFunctionsUsage = new Map() } /** @inheritdoc */ diff --git a/src/pools/worker.ts b/src/pools/worker.ts index 52b56a24..bfd73325 100644 --- a/src/pools/worker.ts +++ b/src/pools/worker.ts @@ -215,14 +215,14 @@ export interface IWorkerNode { * Worker info. */ readonly info: WorkerInfo - /** - * Message channel (worker_threads only). - */ - readonly messageChannel?: MessageChannel /** * Worker usage statistics. */ usage: WorkerUsage + /** + * Message channel (worker_threads only). + */ + readonly messageChannel?: MessageChannel /** * Tasks queue back pressure size. * This is the number of tasks that can be enqueued before the worker node has back pressure. diff --git a/tests/pools/abstract/worker-node.test.js b/tests/pools/abstract/worker-node.test.js new file mode 100644 index 00000000..9401eb1a --- /dev/null +++ b/tests/pools/abstract/worker-node.test.js @@ -0,0 +1,163 @@ +const { MessageChannel, Worker } = require('worker_threads') +const { expect } = require('expect') +const { WorkerNode } = require('../../../lib/pools/worker-node') +const { WorkerTypes } = require('../../../lib') +const { CircularArray } = require('../../../lib/circular-array') +const { Deque } = require('../../../lib/deque') + +describe('Worker node test suite', () => { + const worker = new Worker('./tests/worker-files/thread/testWorker.js') + const workerNode = new WorkerNode(worker, WorkerTypes.thread, 12) + + it('Worker node instantiation', () => { + expect(() => new WorkerNode()).toThrowError( + new TypeError('Cannot construct a worker node without a worker') + ) + expect(() => new WorkerNode(worker)).toThrowError( + new TypeError('Cannot construct a worker node without a worker type') + ) + expect(() => new WorkerNode(worker, WorkerTypes.thread)).toThrowError( + new TypeError( + 'Cannot construct a worker node without a tasks queue back pressure size' + ) + ) + expect( + () => + new WorkerNode( + worker, + WorkerTypes.thread, + 'invalidTasksQueueBackPressureSize' + ) + ).toThrowError( + new TypeError( + 'Cannot construct a worker node with a tasks queue back pressure size that is not an integer' + ) + ) + expect(workerNode).toBeInstanceOf(WorkerNode) + expect(workerNode.worker).toBe(worker) + expect(workerNode.info).toStrictEqual({ + id: worker.threadId, + type: WorkerTypes.thread, + dynamic: false, + ready: false + }) + expect(workerNode.usage).toStrictEqual({ + tasks: { + executed: 0, + executing: 0, + queued: 0, + maxQueued: 0, + stolen: 0, + failed: 0 + }, + runTime: { + history: expect.any(CircularArray) + }, + waitTime: { + history: expect.any(CircularArray) + }, + elu: { + idle: { + history: expect.any(CircularArray) + }, + active: { + history: expect.any(CircularArray) + } + } + }) + expect(workerNode.messageChannel).toBeInstanceOf(MessageChannel) + expect(workerNode.tasksQueueBackPressureSize).toBe(12) + expect(workerNode.tasksQueue).toBeInstanceOf(Deque) + expect(workerNode.tasksQueue.size).toBe(0) + expect(workerNode.taskFunctionsUsage).toBeInstanceOf(Map) + }) + + it('Worker node getTaskFunctionWorkerUsage()', () => { + expect(() => + workerNode.getTaskFunctionWorkerUsage('invalidTaskFunction') + ).toThrowError( + new TypeError( + "Cannot get task function worker usage for task function name 'invalidTaskFunction' when task function names list is not yet defined" + ) + ) + workerNode.info.taskFunctions = ['default', 'fn1'] + expect(() => + workerNode.getTaskFunctionWorkerUsage('invalidTaskFunction') + ).toThrowError( + new TypeError( + "Cannot get task function worker usage for task function name 'invalidTaskFunction' when task function names list has less than 3 elements" + ) + ) + workerNode.info.taskFunctions = ['default', 'fn1', 'fn2'] + expect(workerNode.getTaskFunctionWorkerUsage('default')).toStrictEqual({ + tasks: { + executed: 0, + executing: 0, + queued: 0, + stolen: 0, + failed: 0 + }, + runTime: { + history: expect.any(CircularArray) + }, + waitTime: { + history: expect.any(CircularArray) + }, + elu: { + idle: { + history: expect.any(CircularArray) + }, + active: { + history: expect.any(CircularArray) + } + } + }) + expect(workerNode.getTaskFunctionWorkerUsage('fn1')).toStrictEqual({ + tasks: { + executed: 0, + executing: 0, + queued: 0, + stolen: 0, + failed: 0 + }, + runTime: { + history: expect.any(CircularArray) + }, + waitTime: { + history: expect.any(CircularArray) + }, + elu: { + idle: { + history: expect.any(CircularArray) + }, + active: { + history: expect.any(CircularArray) + } + } + }) + expect(workerNode.getTaskFunctionWorkerUsage('fn2')).toStrictEqual({ + tasks: { + executed: 0, + executing: 0, + queued: 0, + stolen: 0, + failed: 0 + }, + runTime: { + history: expect.any(CircularArray) + }, + waitTime: { + history: expect.any(CircularArray) + }, + elu: { + idle: { + history: expect.any(CircularArray) + }, + active: { + history: expect.any(CircularArray) + } + } + }) + expect(workerNode.taskFunctionsUsage.size).toBe(2) + }) +}) -- 2.34.1