Commit | Line | Data |
---|---|---|
a61a0724 | 1 | const { expect } = require('expect') |
cdace0e5 | 2 | const { DynamicThreadPool, PoolEvents } = require('../../../lib') |
2d2e32c2 | 3 | const { WorkerFunctions } = require('../../test-types') |
85a3f8a7 | 4 | const TestUtils = require('../../test-utils') |
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, | |
12 | './tests/worker-files/thread/testWorker.js', | |
13 | { | |
14 | errorHandler: e => console.error(e) | |
15 | } | |
16 | ) | |
17 | ||
506c2a14 | 18 | it('Verify that the function is executed in a worker thread', async () => { |
6db75ad9 JB |
19 | let result = await pool.execute({ |
20 | function: WorkerFunctions.fibonacci | |
21 | }) | |
024daf59 | 22 | expect(result).toBe(75025) |
6db75ad9 JB |
23 | result = await pool.execute({ |
24 | function: WorkerFunctions.factorial | |
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) | |
14916bf9 JB |
37 | // The `busy` event is triggered when the number of submitted tasks at once reach the max number of workers in the dynamic pool. |
38 | // So in total numberOfWorkers + 1 times for a loop submitting up to numberOfWorkers * 2 tasks to the dynamic pool. | |
8620fb25 | 39 | expect(poolBusy).toBe(max + 1) |
2c039e43 JB |
40 | const numberOfExitEvents = await TestUtils.waitWorkerEvents( |
41 | pool, | |
42 | 'exit', | |
43 | max - min | |
44 | ) | |
bdacc2d2 | 45 | expect(numberOfExitEvents).toBe(max - min) |
506c2a14 | 46 | }) |
47 | ||
bcf04003 | 48 | it('Verify scale thread up and down is working', async () => { |
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) |
2c039e43 | 54 | await TestUtils.waitWorkerEvents(pool, 'exit', max - min) |
f06e48d8 | 55 | expect(pool.workerNodes.length).toBe(min) |
e211bc18 | 56 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 57 | pool.execute() |
bcf04003 | 58 | } |
f06e48d8 | 59 | expect(pool.workerNodes.length).toBe(max) |
2c039e43 | 60 | await TestUtils.waitWorkerEvents(pool, 'exit', max - min) |
f06e48d8 | 61 | expect(pool.workerNodes.length).toBe(min) |
bcf04003 | 62 | }) |
c01733f1 | 63 | |
506c2a14 | 64 | it('Shutdown test', async () => { |
2c039e43 | 65 | const exitPromise = TestUtils.waitWorkerEvents(pool, 'exit', min) |
1f9a5a44 | 66 | await pool.destroy() |
cf597bc5 JB |
67 | const numberOfExitEvents = await exitPromise |
68 | expect(numberOfExitEvents).toBe(min) | |
506c2a14 | 69 | }) |
70 | ||
8d3782fa JB |
71 | it('Validation of inputs test', () => { |
72 | expect(() => new DynamicThreadPool(min)).toThrowError( | |
d4aeae5a | 73 | 'Please specify a file with a worker implementation' |
85a3f8a7 | 74 | ) |
506c2a14 | 75 | }) |
76 | ||
77 | it('Should work even without opts in input', async () => { | |
325f50bc | 78 | const pool1 = new DynamicThreadPool( |
e1ffb94f JB |
79 | min, |
80 | max, | |
76b1e974 | 81 | './tests/worker-files/thread/testWorker.js' |
325f50bc | 82 | ) |
6db75ad9 JB |
83 | const res = await pool1.execute() |
84 | expect(res).toBe(false) | |
0e2503fc JB |
85 | // We need to clean up the resources after our test |
86 | await pool1.destroy() | |
506c2a14 | 87 | }) |
c01733f1 | 88 | |
1c6fe997 | 89 | it('Verify scale thread up and down is working when long executing task is used:hard', async () => { |
c01733f1 | 90 | const longRunningPool = new DynamicThreadPool( |
91 | min, | |
92 | max, | |
85a3f8a7 | 93 | './tests/worker-files/thread/longRunningWorkerHardBehavior.js', |
4c35177b | 94 | { |
95 | errorHandler: e => console.error(e), | |
1c6fe997 JB |
96 | onlineHandler: () => console.log('long executing worker is online'), |
97 | exitHandler: () => console.log('long executing worker exited') | |
4c35177b | 98 | } |
99 | ) | |
f06e48d8 | 100 | expect(longRunningPool.workerNodes.length).toBe(min) |
e211bc18 | 101 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 102 | longRunningPool.execute() |
4c35177b | 103 | } |
f06e48d8 | 104 | expect(longRunningPool.workerNodes.length).toBe(max) |
2c039e43 | 105 | await TestUtils.waitWorkerEvents(longRunningPool, 'exit', max - min) |
f06e48d8 | 106 | expect(longRunningPool.workerNodes.length).toBe(min) |
d710242d JB |
107 | expect( |
108 | longRunningPool.workerChoiceStrategyContext.workerChoiceStrategies.get( | |
109 | longRunningPool.workerChoiceStrategyContext.workerChoiceStrategy | |
110 | ).nextWorkerNodeId | |
111 | ).toBeLessThan(longRunningPool.workerNodes.length) | |
0e2503fc JB |
112 | // We need to clean up the resources after our test |
113 | await longRunningPool.destroy() | |
4c35177b | 114 | }) |
115 | ||
1c6fe997 | 116 | it('Verify scale thread up and down is working when long executing task is used:soft', async () => { |
4c35177b | 117 | const longRunningPool = new DynamicThreadPool( |
118 | min, | |
119 | max, | |
85a3f8a7 | 120 | './tests/worker-files/thread/longRunningWorkerSoftBehavior.js', |
c01733f1 | 121 | { |
122 | errorHandler: e => console.error(e), | |
1c6fe997 JB |
123 | onlineHandler: () => console.log('long executing worker is online'), |
124 | exitHandler: () => console.log('long executing worker exited') | |
c01733f1 | 125 | } |
126 | ) | |
f06e48d8 | 127 | expect(longRunningPool.workerNodes.length).toBe(min) |
e211bc18 | 128 | for (let i = 0; i < max * 2; i++) { |
6db75ad9 | 129 | longRunningPool.execute() |
c01733f1 | 130 | } |
f06e48d8 | 131 | expect(longRunningPool.workerNodes.length).toBe(max) |
85a3f8a7 | 132 | await TestUtils.sleep(1500) |
1c6fe997 | 133 | // Here we expect the workerNodes to be at the max size since the task is still executing |
f06e48d8 | 134 | expect(longRunningPool.workerNodes.length).toBe(max) |
0e2503fc JB |
135 | // We need to clean up the resources after our test |
136 | await longRunningPool.destroy() | |
c01733f1 | 137 | }) |
8d3782fa JB |
138 | |
139 | it('Verify that a pool with zero worker can be instantiated', async () => { | |
140 | const pool = new DynamicThreadPool( | |
141 | 0, | |
142 | max, | |
143 | './tests/worker-files/thread/testWorker.js' | |
144 | ) | |
145 | expect(pool).toBeInstanceOf(DynamicThreadPool) | |
146 | // We need to clean up the resources after our test | |
147 | await pool.destroy() | |
148 | }) | |
506c2a14 | 149 | }) |