X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=tests%2Fpools%2Fselection-strategies%2Fselection-strategies.test.js;h=2fcbba5a95054b20311baa45892e26f24733b1fe;hb=d4aeae5aa9e260c8c2f6d28f3133de368552c108;hp=faa28a296b844c050b96706f090165f9676609e6;hpb=d2f7b7a2e327fd754babbe16dd7ef8ff72a4a7cf;p=poolifier.git diff --git a/tests/pools/selection-strategies/selection-strategies.test.js b/tests/pools/selection-strategies/selection-strategies.test.js index faa28a29..2fcbba5a 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.js +++ b/tests/pools/selection-strategies/selection-strategies.test.js @@ -2,7 +2,8 @@ const { expect } = require('expect') const { WorkerChoiceStrategies, DynamicThreadPool, - FixedThreadPool + FixedThreadPool, + FixedClusterPool } = require('../../../lib/index') describe('Selection strategies test suite', () => { @@ -11,7 +12,8 @@ describe('Selection strategies test suite', () => { it('Verify that WorkerChoiceStrategies enumeration provides string values', () => { expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN') - expect(WorkerChoiceStrategies.LESS_RECENTLY_USED).toBe('LESS_RECENTLY_USED') + expect(WorkerChoiceStrategies.LESS_USED).toBe('LESS_USED') + expect(WorkerChoiceStrategies.LESS_BUSY).toBe('LESS_BUSY') expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE') expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe( 'WEIGHTED_ROUND_ROBIN' @@ -31,56 +33,127 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify ROUND_ROBIN strategy is taken at pool creation', async () => { - const pool = new FixedThreadPool( - max, - './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } - ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.ROUND_ROBIN - ) - expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy().nextWorkerIndex - ).toBe(0) - // We need to clean up the resources after our test - await pool.destroy() + it('Verify available strategies are taken at pool creation', async () => { + for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { + const pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy) + expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe( + workerChoiceStrategy + ) + await pool.destroy() + } }) - it('Verify ROUND_ROBIN strategy can be set after pool creation', async () => { - const pool = new DynamicThreadPool( - min, + it('Verify available strategies can be set after pool creation', async () => { + for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { + const pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js' + ) + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy) + expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe( + workerChoiceStrategy + ) + await pool.destroy() + } + }) + + it('Verify available strategies default internals at pool creation', async () => { + const pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js' ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.ROUND_ROBIN) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.ROUND_ROBIN - ) - // We need to clean up the resources after our test + for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) { + if (workerChoiceStrategy === WorkerChoiceStrategies.ROUND_ROBIN) { + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).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) + } + } else if ( + workerChoiceStrategy === WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN + ) { + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).currentWorkerNodeId + ).toBe(0) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + 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) + } + } + } await pool.destroy() }) it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN let pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.ROUND_ROBIN) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime ).toBe(false) await pool.destroy() pool = new DynamicThreadPool( min, max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.ROUND_ROBIN) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime ).toBe(false) // We need to clean up the resources after our test await pool.destroy() @@ -92,9 +165,6 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.ROUND_ROBIN - ) // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` const promises = [] for (let i = 0; i < max * 2; i++) { @@ -112,9 +182,6 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy: WorkerChoiceStrategies.ROUND_ROBIN } ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.ROUND_ROBIN - ) // TODO: Create a better test to cover `RoundRobinWorkerChoiceStrategy#choose` const promises = [] for (let i = 0; i < max * 2; i++) { @@ -125,64 +192,115 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify LESS_RECENTLY_USED strategy is taken at pool creation', async () => { - const pool = new FixedThreadPool( + it('Verify ROUND_ROBIN strategy runtime behavior', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN + let pool = new FixedClusterPool( max, - './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.LESS_RECENTLY_USED } + './tests/worker-files/cluster/testWorker.js', + { workerChoiceStrategy } ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.LESS_RECENTLY_USED + let results = new Set() + for (let i = 0; i < max; i++) { + results.add(pool.chooseWorkerNode()[1].worker.id) + } + expect(results.size).toBe(max) + await pool.destroy() + pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - // We need to clean up the resources after our test + results = new Set() + for (let i = 0; i < max; i++) { + results.add(pool.chooseWorkerNode()[1].worker.threadId) + } + expect(results.size).toBe(max) await pool.destroy() }) - it('Verify LESS_RECENTLY_USED strategy can be set after pool creation', async () => { - const pool = new FixedThreadPool( + it('Verify ROUND_ROBIN strategy internals are resets after setting it', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN + let pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_RECENTLY_USED) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.LESS_RECENTLY_USED + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).nextWorkerNodeId + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).nextWorkerNodeId + ).toBe(0) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } ) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).nextWorkerNodeId + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).nextWorkerNodeId + ).toBe(0) // We need to clean up the resources after our test await pool.destroy() }) - it('Verify LESS_RECENTLY_USED strategy default tasks usage statistics requirements', async () => { + it('Verify LESS_USED strategy default tasks usage statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LESS_USED let pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_RECENTLY_USED) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime ).toBe(false) await pool.destroy() pool = new DynamicThreadPool( min, max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.LESS_RECENTLY_USED) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime ).toBe(false) // We need to clean up the resources after our test await pool.destroy() }) - it('Verify LESS_RECENTLY_USED strategy can be run in a fixed pool', async () => { + it('Verify LESS_USED strategy can be run in a fixed pool', async () => { const pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.LESS_RECENTLY_USED } + { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } ) - // TODO: Create a better test to cover `LessRecentlyUsedWorkerChoiceStrategy#choose` + // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` const promises = [] for (let i = 0; i < max * 2; i++) { promises.push(pool.execute()) @@ -192,14 +310,14 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify LESS_RECENTLY_USED strategy can be run in a dynamic pool', async () => { + it('Verify LESS_USED strategy can be run in a dynamic pool', async () => { const pool = new DynamicThreadPool( min, max, './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.LESS_RECENTLY_USED } + { workerChoiceStrategy: WorkerChoiceStrategies.LESS_USED } ) - // TODO: Create a better test to cover `LessRecentlyUsedWorkerChoiceStrategy#choose` + // TODO: Create a better test to cover `LessUsedWorkerChoiceStrategy#choose` const promises = [] for (let i = 0; i < max * 2; i++) { promises.push(pool.execute()) @@ -209,67 +327,107 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify FAIR_SHARE strategy is taken at pool creation', async () => { - const pool = new FixedThreadPool( + it('Verify LESS_BUSY strategy default tasks usage statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LESS_BUSY + let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE } + { workerChoiceStrategy } ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.FAIR_SHARE + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp.keys()) { - expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp.get(worker).start - ).toBe(0) - expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp.get(worker).end - ).toBe(0) - } + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(false) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) // We need to clean up the resources after our test await pool.destroy() }) - it('Verify FAIR_SHARE strategy can be set after pool creation', async () => { + it('Verify LESS_BUSY strategy can be run in a fixed pool', async () => { const pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy: WorkerChoiceStrategies.LESS_BUSY } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.FAIR_SHARE + // TODO: Create a better test to cover `LessBusyWorkerChoiceStrategy#choose` + const promises = [] + for (let i = 0; i < max * 2; i++) { + promises.push(pool.execute()) + } + await Promise.all(promises) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LESS_BUSY strategy can be run in a dynamic pool', async () => { + const pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { 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()) + } + await Promise.all(promises) // We need to clean up the resources after our test await pool.destroy() }) it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE let pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) await pool.destroy() pool = new DynamicThreadPool( min, max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) // We need to clean up the resources after our test await pool.destroy() }) @@ -286,6 +444,11 @@ describe('Selection strategies test suite', () => { promises.push(pool.execute()) } await Promise.all(promises) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workerLastVirtualTaskTimestamp.size + ).toBe(pool.workerNodes.length) // We need to clean up the resources after our test await pool.destroy() }) @@ -299,36 +462,46 @@ describe('Selection strategies test suite', () => { ) // TODO: Create a better test to cover `FairShareChoiceStrategy#choose` const promises = [] - for (let i = 0; i < max * 2; i++) { + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { promises.push(pool.execute()) } await Promise.all(promises) + // if (process.platform !== 'win32') { + // expect( + // pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + // pool.workerChoiceStrategyContext.workerChoiceStrategy + // ).workerLastVirtualTaskTimestamp.size + // ).toBe(pool.workerNodes.length) + // } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify FAIR_SHARE strategy statistics are resets after setting it', async () => { + it('Verify FAIR_SHARE strategy internals are resets after setting it', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js' ) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp - ).toBeUndefined() - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workerLastVirtualTaskTimestamp + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) .workerLastVirtualTaskTimestamp.keys()) { expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp.get(worker).start + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workerLastVirtualTaskTimestamp.get(workerNodeKey).start ).toBe(0) expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerLastVirtualTaskTimestamp.get(worker).end + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workerLastVirtualTaskTimestamp.get(workerNodeKey).end ).toBe(0) } await pool.destroy() @@ -338,101 +511,61 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js' ) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .workerChoiceStrategy.workerLastVirtualTaskTimestamp - ).toBeUndefined() - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.FAIR_SHARE) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerChoiceStrategy.workerLastVirtualTaskTimestamp.keys()) { + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workerLastVirtualTaskTimestamp + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workerLastVirtualTaskTimestamp.keys()) { expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerChoiceStrategy.workerLastVirtualTaskTimestamp.get(worker).start + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workerLastVirtualTaskTimestamp.get(workerNodeKey).start ).toBe(0) expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerChoiceStrategy.workerLastVirtualTaskTimestamp.get(worker).end + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workerLastVirtualTaskTimestamp.get(workerNodeKey).end ).toBe(0) } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify WEIGHTED_ROUND_ROBIN strategy is taken at pool creation', async () => { - const pool = new FixedThreadPool( - max, - './tests/worker-files/thread/testWorker.js', - { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN } - ) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN - ) - expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .previousWorkerIndex - ).toBe(0) - expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .currentWorkerIndex - ).toBe(0) - expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .defaultWorkerWeight - ).toBeGreaterThan(0) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workersTaskRunTime.keys()) { - expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workersTaskRunTime.get(worker).weight - ).toBeGreaterThan(0) - expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workersTaskRunTime.get(worker).runTime - ).toBe(0) - } - // We need to clean up the resources after our test - await pool.destroy() - }) - - it('Verify WEIGHTED_ROUND_ROBIN strategy can be set after pool creation', async () => { - const pool = new FixedThreadPool( - max, - './tests/worker-files/thread/testWorker.js' - ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN) - expect(pool.opts.workerChoiceStrategy).toBe( - WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN - ) - // We need to clean up the resources after our test - await pool.destroy() - }) - it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN let pool = new FixedThreadPool( max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) await pool.destroy() pool = new DynamicThreadPool( min, max, - './tests/worker-files/thread/testWorker.js' + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } ) - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .requiredStatistics.runTime + pool.workerChoiceStrategyContext.getRequiredStatistics().runTime ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().avgRunTime + ).toBe(true) + expect( + pool.workerChoiceStrategyContext.getRequiredStatistics().medRunTime + ).toBe(false) // We need to clean up the resources after our test await pool.destroy() }) @@ -449,6 +582,11 @@ describe('Selection strategies test suite', () => { promises.push(pool.execute()) } await Promise.all(promises) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workersTaskRunTime.size + ).toBe(pool.workerNodes.length) // We need to clean up the resources after our test await pool.destroy() }) @@ -462,31 +600,64 @@ describe('Selection strategies test suite', () => { ) // TODO: Create a better test to cover `WeightedRoundRobinWorkerChoiceStrategy#choose` const promises = [] - for (let i = 0; i < max * 2; i++) { + const maxMultiplier = + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).defaultWorkerWeight * 50 + for (let i = 0; i < max * maxMultiplier; i++) { promises.push(pool.execute()) } await Promise.all(promises) + if (process.platform !== 'win32') { + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).workersTaskRunTime.size + ).toBe(pool.workerNodes.length) + } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify WEIGHTED_ROUND_ROBIN strategy statistics are resets after setting it', async () => { + it('Verify WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js' ) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .workersTaskRunTime - ).toBeUndefined() - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).currentWorkerNodeId + ).toBeDefined() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).defaultWorkerWeight + ).toBeDefined() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersTaskRunTime + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).currentWorkerNodeId + ).toBe(0) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).defaultWorkerWeight + ).toBeGreaterThan(0) + for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) .workersTaskRunTime.keys()) { expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workersTaskRunTime.get(worker).runTime + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workersTaskRunTime.get(workerNodeKey).runTime ).toBe(0) } await pool.destroy() @@ -496,24 +667,45 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js' ) expect( - pool.workerChoiceStrategyContext.getWorkerChoiceStrategy() - .workerChoiceStrategy.workersTaskRunTime - ).toBeUndefined() - pool.setWorkerChoiceStrategy(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN) - for (const worker of pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerChoiceStrategy.workersTaskRunTime.keys()) { + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).currentWorkerNodeId + ).toBeDefined() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).defaultWorkerWeight + ).toBeDefined() + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + workerChoiceStrategy + ).workersTaskRunTime + ).toBeDefined() + pool.setWorkerChoiceStrategy(workerChoiceStrategy) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).currentWorkerNodeId + ).toBe(0) + expect( + pool.workerChoiceStrategyContext.workerChoiceStrategies.get( + pool.workerChoiceStrategyContext.workerChoiceStrategy + ).defaultWorkerWeight + ).toBeGreaterThan(0) + for (const workerNodeKey of pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workersTaskRunTime.keys()) { expect( - pool.workerChoiceStrategyContext - .getWorkerChoiceStrategy() - .workerChoiceStrategy.workersTaskRunTime.get(worker).runTime + pool.workerChoiceStrategyContext.workerChoiceStrategies + .get(pool.workerChoiceStrategyContext.workerChoiceStrategy) + .workersTaskRunTime.get(workerNodeKey).runTime ).toBe(0) } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify unknown strategies throw error', () => { + it('Verify unknown strategy throw error', () => { expect( () => new DynamicThreadPool( @@ -522,8 +714,6 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy: 'UNKNOWN_STRATEGY' } ) - ).toThrowError( - new Error("Worker choice strategy 'UNKNOWN_STRATEGY' not found") - ) + ).toThrowError("Invalid worker choice strategy 'UNKNOWN_STRATEGY'") }) })