Commit | Line | Data |
---|---|---|
a074ffee JB |
1 | import { expect } from 'expect' |
2 | import { DynamicThreadPool, PoolEvents } from '../../../lib/index.js' | |
3 | import { TaskFunctions } from '../../test-types.js' | |
4 | import { sleep, waitWorkerEvents } from '../../test-utils.js' | |
506c2a14 | 5 | |
a35560ba | 6 | describe('Dynamic thread pool test suite', () => { |
e1ffb94f JB |
7 | const min = 1 |
8 | const max = 3 | |
9 | const pool = new DynamicThreadPool( | |
10 | min, | |
11 | max, | |
b2fd3f4a | 12 | './tests/worker-files/thread/testWorker.mjs', |
e1ffb94f | 13 | { |
041dc05b | 14 | errorHandler: e => console.error(e) |
e1ffb94f JB |
15 | } |
16 | ) | |
17 | ||
506c2a14 | 18 | it('Verify that the function is executed in a worker thread', async () => { |
6db75ad9 | 19 | let result = await pool.execute({ |
dbca3be9 | 20 | function: TaskFunctions.fibonacci |
6db75ad9 | 21 | }) |
024daf59 | 22 | expect(result).toBe(75025) |
6db75ad9 | 23 | result = await pool.execute({ |
dbca3be9 | 24 | function: TaskFunctions.factorial |
6db75ad9 | 25 | }) |
70a4f5ea | 26 | expect(result).toBe(9.33262154439441e157) |
506c2a14 | 27 | }) |
28 | ||
29 | it('Verify that new workers are created when required, max size is not exceeded and that after a while new workers will die', async () => { | |
7c0ba920 | 30 | let poolBusy = 0 |
aee46736 | 31 | pool.emitter.on(PoolEvents.busy, () => ++poolBusy) |
cf9aa6c3 | 32 | for (let i = 0; i < max * 2; i++) { |
8cbb82eb | 33 | pool.execute() |
506c2a14 | 34 | } |
f06e48d8 JB |
35 | expect(pool.workerNodes.length).toBeLessThanOrEqual(max) |
36 | expect(pool.workerNodes.length).toBeGreaterThan(min) | |
94407def | 37 | expect(poolBusy).toBe(1) |
bac873bd | 38 | const numberOfExitEvents = await waitWorkerEvents(pool, 'exit', max - min) |
bdacc2d2 | 39 | expect(numberOfExitEvents).toBe(max - min) |
506c2a14 | 40 | }) |
41 | ||
bcf04003 | 42 | it('Verify scale thread up and down is working', async () => { |
f06e48d8 | 43 | expect(pool.workerNodes.length).toBe(min) |
e211bc18 | 44 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 45 | pool.execute() |
bcf04003 | 46 | } |
f06e48d8 | 47 | expect(pool.workerNodes.length).toBe(max) |
bac873bd | 48 | await waitWorkerEvents(pool, 'exit', max - min) |
f06e48d8 | 49 | expect(pool.workerNodes.length).toBe(min) |
e211bc18 | 50 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 51 | pool.execute() |
bcf04003 | 52 | } |
f06e48d8 | 53 | expect(pool.workerNodes.length).toBe(max) |
bac873bd | 54 | await waitWorkerEvents(pool, 'exit', max - min) |
f06e48d8 | 55 | expect(pool.workerNodes.length).toBe(min) |
bcf04003 | 56 | }) |
c01733f1 | 57 | |
506c2a14 | 58 | it('Shutdown test', async () => { |
bac873bd | 59 | const exitPromise = waitWorkerEvents(pool, 'exit', min) |
c726f66c | 60 | expect(pool.emitter.eventNames()).toStrictEqual([PoolEvents.busy]) |
ef3891a3 JB |
61 | let poolDestroy = 0 |
62 | pool.emitter.on(PoolEvents.destroy, () => ++poolDestroy) | |
c726f66c JB |
63 | expect(pool.emitter.eventNames()).toStrictEqual([ |
64 | PoolEvents.busy, | |
65 | PoolEvents.destroy | |
66 | ]) | |
1f9a5a44 | 67 | await pool.destroy() |
cf597bc5 | 68 | const numberOfExitEvents = await exitPromise |
bb9423b7 | 69 | expect(pool.started).toBe(false) |
55082af9 | 70 | expect(pool.readyEventEmitted).toBe(false) |
bb9423b7 | 71 | expect(pool.workerNodes.length).toBe(0) |
cf597bc5 | 72 | expect(numberOfExitEvents).toBe(min) |
ef3891a3 | 73 | expect(poolDestroy).toBe(1) |
506c2a14 | 74 | }) |
75 | ||
8d3782fa | 76 | it('Validation of inputs test', () => { |
948faff7 | 77 | expect(() => new DynamicThreadPool(min)).toThrow( |
fa015370 | 78 | "Cannot find the worker file 'undefined'" |
85a3f8a7 | 79 | ) |
506c2a14 | 80 | }) |
81 | ||
82 | it('Should work even without opts in input', async () => { | |
0fe39c97 | 83 | const pool = new DynamicThreadPool( |
e1ffb94f JB |
84 | min, |
85 | max, | |
b2fd3f4a | 86 | './tests/worker-files/thread/testWorker.mjs' |
325f50bc | 87 | ) |
0fe39c97 | 88 | const res = await pool.execute() |
30b963d4 | 89 | expect(res).toStrictEqual({ ok: 1 }) |
0e2503fc | 90 | // We need to clean up the resources after our test |
0fe39c97 | 91 | await pool.destroy() |
506c2a14 | 92 | }) |
c01733f1 | 93 | |
1c6fe997 | 94 | it('Verify scale thread up and down is working when long executing task is used:hard', async () => { |
c01733f1 | 95 | const longRunningPool = new DynamicThreadPool( |
96 | min, | |
97 | max, | |
b2fd3f4a | 98 | './tests/worker-files/thread/longRunningWorkerHardBehavior.mjs', |
4c35177b | 99 | { |
041dc05b | 100 | errorHandler: e => console.error(e), |
73bfd59d JB |
101 | onlineHandler: () => console.info('long executing worker is online'), |
102 | exitHandler: () => console.info('long executing worker exited') | |
4c35177b | 103 | } |
104 | ) | |
f06e48d8 | 105 | expect(longRunningPool.workerNodes.length).toBe(min) |
e211bc18 | 106 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 107 | longRunningPool.execute() |
4c35177b | 108 | } |
f06e48d8 | 109 | expect(longRunningPool.workerNodes.length).toBe(max) |
bac873bd | 110 | await waitWorkerEvents(longRunningPool, 'exit', max - min) |
f06e48d8 | 111 | expect(longRunningPool.workerNodes.length).toBe(min) |
d710242d JB |
112 | expect( |
113 | longRunningPool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
114 | longRunningPool.workerChoiceStrategyContext.workerChoiceStrategy | |
9b106837 | 115 | ).nextWorkerNodeKey |
d710242d | 116 | ).toBeLessThan(longRunningPool.workerNodes.length) |
0e2503fc JB |
117 | // We need to clean up the resources after our test |
118 | await longRunningPool.destroy() | |
4c35177b | 119 | }) |
120 | ||
1c6fe997 | 121 | it('Verify scale thread up and down is working when long executing task is used:soft', async () => { |
4c35177b | 122 | const longRunningPool = new DynamicThreadPool( |
123 | min, | |
124 | max, | |
b2fd3f4a | 125 | './tests/worker-files/thread/longRunningWorkerSoftBehavior.mjs', |
c01733f1 | 126 | { |
041dc05b | 127 | errorHandler: e => console.error(e), |
73bfd59d JB |
128 | onlineHandler: () => console.info('long executing worker is online'), |
129 | exitHandler: () => console.info('long executing worker exited') | |
c01733f1 | 130 | } |
131 | ) | |
f06e48d8 | 132 | expect(longRunningPool.workerNodes.length).toBe(min) |
e211bc18 | 133 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 134 | longRunningPool.execute() |
c01733f1 | 135 | } |
f06e48d8 | 136 | expect(longRunningPool.workerNodes.length).toBe(max) |
920278a2 | 137 | await sleep(1000) |
1c6fe997 | 138 | // Here we expect the workerNodes to be at the max size since the task is still executing |
f06e48d8 | 139 | expect(longRunningPool.workerNodes.length).toBe(max) |
0e2503fc JB |
140 | // We need to clean up the resources after our test |
141 | await longRunningPool.destroy() | |
c01733f1 | 142 | }) |
8d3782fa JB |
143 | |
144 | it('Verify that a pool with zero worker can be instantiated', async () => { | |
145 | const pool = new DynamicThreadPool( | |
146 | 0, | |
147 | max, | |
b2fd3f4a | 148 | './tests/worker-files/thread/testWorker.mjs' |
8d3782fa JB |
149 | ) |
150 | expect(pool).toBeInstanceOf(DynamicThreadPool) | |
151 | // We need to clean up the resources after our test | |
152 | await pool.destroy() | |
153 | }) | |
506c2a14 | 154 | }) |