X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=tests%2Fpools%2Fselection-strategies%2Fselection-strategies.test.js;h=9a85c3ff9de048b9f401a7ca2530b710528219e0;hb=644992db7bd22ca02c9610f7d622d7973f861d0b;hp=7755cc341f6ec97f143ba7253dae95601345de3e;hpb=89b09b2646d240a5a30531b2fc742fdba209fa13;p=poolifier.git diff --git a/tests/pools/selection-strategies/selection-strategies.test.js b/tests/pools/selection-strategies/selection-strategies.test.js index 7755cc34..9a85c3ff 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.js +++ b/tests/pools/selection-strategies/selection-strategies.test.js @@ -4,7 +4,7 @@ const { DynamicThreadPool, FixedThreadPool, FixedClusterPool -} = require('../../../lib/index') +} = require('../../../lib') describe('Selection strategies test suite', () => { const min = 0 @@ -18,6 +18,9 @@ describe('Selection strategies test suite', () => { expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe( 'WEIGHTED_ROUND_ROBIN' ) + expect(WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN).toBe( + 'INTERLEAVED_WEIGHTED_ROUND_ROBIN' + ) }) it('Verify ROUND_ROBIN strategy is the default at pool creation', async () => { @@ -77,20 +80,16 @@ describe('Selection strategies test suite', () => { ).nextWorkerNodeId ).toBe(0) } else if (workerChoiceStrategy === WorkerChoiceStrategies.FAIR_SHARE) { - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).start - ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).end - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp + ).toBeInstanceOf(Array) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(0) } else if ( workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN ) { @@ -104,20 +103,11 @@ describe('Selection strategies test suite', () => { workerChoiceStrategy ).defaultWorkerWeight ).toBeGreaterThan(0) - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workersTaskRunTime.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workersTaskRunTime.get(workerNodeKey).weight - ).toBeGreaterThan(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(workerChoiceStrategy) - .workersTaskRunTime.get(workerNodeKey).runTime - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workerVirtualTaskRunTime + ).toBe(0) } } await pool.destroy() @@ -166,11 +156,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } ) // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -183,11 +172,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } ) // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -201,7 +189,7 @@ describe('Selection strategies test suite', () => { ) let results = new Set() for (let i = 0; i < max; i++) { - results.add(pool.chooseWorkerNode()[1].worker.id) + results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.id) } expect(results.size).toBe(max) await pool.destroy() @@ -212,7 +200,7 @@ describe('Selection strategies test suite', () => { ) results = new Set() for (let i = 0; i < max; i++) { - results.add(pool.chooseWorkerNode()[1].worker.threadId) + results.add(pool.workerNodes[pool.chooseWorkerNode()].worker.threadId) } expect(results.size).toBe(max) await pool.destroy() @@ -301,11 +289,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } ) // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -318,11 +305,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } ) // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -370,11 +356,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY } ) // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -387,11 +372,10 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY } ) // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() } - await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) @@ -439,15 +423,20 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE } ) // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() + } + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBe(0) } - await Promise.all(promises) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).workerLastVirtualTaskTimestamp.size + ).workersVirtualTaskEndTimestamp.length ).toBe(pool.workerNodes.length) // We need to clean up the resources after our test await pool.destroy() @@ -461,19 +450,53 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE } ) // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` - const promises = [] const maxMultiplier = 2 for (let i = 0; i < max * maxMultiplier; i++) { - promises.push(pool.execute()) + await pool.execute() } - await Promise.all(promises) - // if (process.platform !== 'win32') { - // expect( - // pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - // pool.workerChoiceStrategyContext.workerChoiceStrategy - // ).workerLastVirtualTaskTimestamp.size - // ).toBe(pool.workerNodes.length) - // } + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBe(0) + } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(pool.workerNodes.length) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify FAIR_SHARE strategy can be run in a dynamic pool with median run time statistic', async () => { + const pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { + workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE, + workerChoiceStrategyOptions: { + medRunTime: true + } + } + ) + // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() + } + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBe(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBeGreaterThanOrEqual(0) + } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(pool.workerNodes.length) // We need to clean up the resources after our test await pool.destroy() }) @@ -487,23 +510,32 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workerLastVirtualTaskTimestamp - ).toBeDefined() + ).workersVirtualTaskEndTimestamp + ).toBeInstanceOf(Array) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(0) + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp[0] = performance.now() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(1) pool.setWorkerChoiceStrategy(workerChoiceStrategy) - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).start - ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).end - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp + ).toBeInstanceOf(Array) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(0) await pool.destroy() pool = new DynamicThreadPool( min, @@ -513,23 +545,32 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workerLastVirtualTaskTimestamp - ).toBeDefined() + ).workersVirtualTaskEndTimestamp + ).toBeInstanceOf(Array) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(0) + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp[0] = performance.now() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(1) pool.setWorkerChoiceStrategy(workerChoiceStrategy) - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).start - ).toBe(0) - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workerLastVirtualTaskTimestamp.get(workerNodeKey).end - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp + ).toBeInstanceOf(Array) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersVirtualTaskEndTimestamp.length + ).toBe(0) // We need to clean up the resources after our test await pool.destroy() }) @@ -577,16 +618,26 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } ) // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` - const promises = [] - for (let i = 0; i < max * 2; i++) { - promises.push(pool.execute()) + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() + } + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBe(0) } - await Promise.all(promises) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).workersTaskRunTime.size - ).toBe(pool.workerNodes.length) + ).defaultWorkerWeight + ).toBeGreaterThan(0) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workerVirtualTaskRunTime + ).toBeGreaterThanOrEqual(0) // We need to clean up the resources after our test await pool.destroy() }) @@ -599,22 +650,63 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } ) // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` - const promises = [] - const maxMultiplier = + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + await pool.execute() + } + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBe(0) + } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).defaultWorkerWeight + ).toBeGreaterThan(0) + expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).defaultWorkerWeight * 50 + ).workerVirtualTaskRunTime + ).toBeGreaterThanOrEqual(0) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool with median run time statistic', async () => { + const pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { + workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN, + workerChoiceStrategyOptions: { + medRunTime: true + } + } + ) + // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` + const maxMultiplier = 2 for (let i = 0; i < max * maxMultiplier; i++) { - promises.push(pool.execute()) + await pool.execute() } - await Promise.all(promises) - if (process.platform !== 'win32') { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies.get( - pool.workerChoiceStrategyContext.workerChoiceStrategy - ).workersTaskRunTime.size - ).toBe(pool.workerNodes.length) + for (const workerNode of pool.workerNodes) { + expect(workerNode.tasksUsage.avgRunTime).toBeDefined() + expect(workerNode.tasksUsage.avgRunTime).toBe(0) + expect(workerNode.tasksUsage.medRunTime).toBeDefined() + expect(workerNode.tasksUsage.medRunTime).toBeGreaterThanOrEqual(0) } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).defaultWorkerWeight + ).toBeGreaterThan(0) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workerVirtualTaskRunTime + ).toBeGreaterThanOrEqual(0) // We need to clean up the resources after our test await pool.destroy() }) @@ -638,7 +730,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workersTaskRunTime + ).workerVirtualTaskRunTime ).toBeDefined() pool.setWorkerChoiceStrategy(workerChoiceStrategy) expect( @@ -651,15 +743,11 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).defaultWorkerWeight ).toBeGreaterThan(0) - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workersTaskRunTime.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workersTaskRunTime.get(workerNodeKey).runTime - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workerVirtualTaskRunTime + ).toBe(0) await pool.destroy() pool = new DynamicThreadPool( min, @@ -679,7 +767,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).workersTaskRunTime + ).workerVirtualTaskRunTime ).toBeDefined() pool.setWorkerChoiceStrategy(workerChoiceStrategy) expect( @@ -692,15 +780,11 @@ describe('Selection strategies test suite', () => { pool.workerChoiceStrategyContext.workerChoiceStrategy ).defaultWorkerWeight ).toBeGreaterThan(0) - for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workersTaskRunTime.keys()) { - expect( - pool.workerChoiceStrategyContext.workerChoiceStrategies - .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) - .workersTaskRunTime.get(workerNodeKey).runTime - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workerVirtualTaskRunTime + ).toBe(0) // We need to clean up the resources after our test await pool.destroy() }) @@ -714,8 +798,6 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy: 'UNKNOWN_STRATEGY' } ) - ).toThrowError( - new Error("Invalid worker choice strategy 'UNKNOWN_STRATEGY'") - ) + ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'") }) })