X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=tests%2Fpools%2Fselection-strategies%2Fselection-strategies.test.js;h=6091bf080f327a3218f53522fcfd1780ef543a70;hb=1f95d54467e83cf9fb877f053ee0fb932a8d6264;hp=62e2e5220abbb936df71809787486ad27fbb4720;hpb=1dfe8965df029a366c040227fb61ae47b3d59a3a;p=poolifier.git diff --git a/tests/pools/selection-strategies/selection-strategies.test.js b/tests/pools/selection-strategies/selection-strategies.test.js index 62e2e522..6091bf08 100644 --- a/tests/pools/selection-strategies/selection-strategies.test.js +++ b/tests/pools/selection-strategies/selection-strategies.test.js @@ -15,6 +15,7 @@ describe('Selection strategies test suite', () => { expect(WorkerChoiceStrategies.ROUND_ROBIN).toBe('ROUND_ROBIN') expect(WorkerChoiceStrategies.LEAST_USED).toBe('LEAST_USED') expect(WorkerChoiceStrategies.LEAST_BUSY).toBe('LEAST_BUSY') + expect(WorkerChoiceStrategies.LEAST_ELU).toBe('LEAST_ELU') expect(WorkerChoiceStrategies.FAIR_SHARE).toBe('FAIR_SHARE') expect(WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN).toBe( 'WEIGHTED_ROUND_ROBIN' @@ -97,7 +98,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -114,21 +115,15 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { + it('Verify ROUND_ROBIN strategy default policy', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -137,14 +132,64 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify ROUND_ROBIN strategy default tasks statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.ROUND_ROBIN + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -172,18 +217,32 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) } expect( @@ -218,18 +277,32 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) } expect( @@ -307,21 +380,55 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify LEAST_USED strategy default tasks usage statistics requirements', async () => { + it('Verify LEAST_USED strategy default policy', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_USED strategy default tasks statistics requirements', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_USED let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) await pool.destroy() pool = new DynamicThreadPool( @@ -330,14 +437,24 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -359,25 +476,43 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.workerUsage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) } // We need to clean up the resources after our test await pool.destroy() @@ -400,46 +535,57 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.workerUsage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify LEAST_BUSY strategy default tasks usage statistics requirements', async () => { + it('Verify LEAST_BUSY strategy default policy', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false }) await pool.destroy() pool = new DynamicThreadPool( @@ -448,14 +594,64 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_BUSY strategy default tasks statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_BUSY + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: false, + median: false + }, + waitTime: { + aggregate: true, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: false, + median: false + }, + waitTime: { + aggregate: true, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -483,24 +679,39 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: expect.any(Number), average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThanOrEqual( + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThanOrEqual( 0 ) } @@ -531,44 +742,256 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + waitTime: { + aggregate: expect.any(Number), + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } + }) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.waitTime.aggregate).toBeGreaterThanOrEqual( + 0 + ) + } + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_ELU strategy default policy', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_ELU strategy default tasks statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.LEAST_ELU + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: true, + average: false, + median: false + } + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: true, + average: false, + median: false + } + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_ELU strategy can be run in a fixed pool', async () => { + const pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU } + ) + // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose` + const promises = new Set() + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + promises.add(pool.execute()) + } + await Promise.all(promises) + for (const workerNode of pool.workerNodes) { + expect(workerNode.workerUsage).toStrictEqual({ + tasks: { + executed: expect.any(Number), + executing: 0, + queued: 0, + failed: 0 + }, + runTime: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + waitTime: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: expect.any(Number), + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: expect.any(Number) + } + }) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) + expect(workerNode.workerUsage.elu.utilization).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeLessThanOrEqual(1) + } + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify LEAST_ELU strategy can be run in a dynamic pool', async () => { + const pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy: WorkerChoiceStrategies.LEAST_ELU } + ) + // TODO: Create a better test to cover `LeastEluWorkerChoiceStrategy#choose` + const promises = new Set() + const maxMultiplier = 2 + for (let i = 0; i < max * maxMultiplier; i++) { + promises.add(pool.execute()) + } + await Promise.all(promises) + for (const workerNode of pool.workerNodes) { + expect(workerNode.workerUsage).toStrictEqual({ + tasks: { + executed: expect.any(Number), + executing: 0, + queued: 0, + failed: 0 + }, + runTime: { + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: expect.any(Number), + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: expect.any(Number) + } }) - expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) + expect(workerNode.workerUsage.elu.utilization).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeLessThanOrEqual(1) } // We need to clean up the resources after our test await pool.destroy() }) - it('Verify FAIR_SHARE strategy default tasks usage statistics requirements', async () => { + it('Verify FAIR_SHARE strategy default policy', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: true, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false }) await pool.destroy() pool = new DynamicThreadPool( @@ -577,14 +1000,64 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: true, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: false + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify FAIR_SHARE strategy default tasks statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.FAIR_SHARE + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: true, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: true, + average: true, + median: false + } + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: true, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: true, + average: true, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -606,27 +1079,47 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.workerUsage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: expect.any(Number), median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: expect.any(Number), + average: expect.any(Number), + median: 0, + history: expect.any(CircularArray) + }, + utilization: expect.any(Number) + } }) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) - expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeLessThanOrEqual(1) } expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -654,27 +1147,47 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.workerUsage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: expect.any(Number), median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: expect.any(Number), + average: expect.any(Number), + median: 0, + history: expect.any(CircularArray) + }, + utilization: expect.any(Number) + } }) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) - expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeLessThanOrEqual(1) } expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -693,7 +1206,7 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.FAIR_SHARE, workerChoiceStrategyOptions: { - medRunTime: true + runTime: { median: true } } } ) @@ -707,27 +1220,47 @@ describe('Selection strategies test suite', () => { for (const workerNode of pool.workerNodes) { expect(workerNode.workerUsage).toStrictEqual({ tasks: { - executed: maxMultiplier, + executed: expect.any(Number), executing: 0, queued: 0, failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: 0, median: expect.any(Number), history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: expect.any(Number), + average: expect.any(Number), + median: 0, + history: expect.any(CircularArray) + }, + utilization: expect.any(Number) + } }) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) - expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( + max * maxMultiplier + ) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.runTime.median).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeGreaterThanOrEqual(0) + expect(workerNode.workerUsage.elu.utilization).toBeLessThanOrEqual(1) } expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -812,21 +1345,15 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { + it('Verify WEIGHTED_ROUND_ROBIN strategy default policy', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN let pool = new FixedThreadPool( max, './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: true, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true }) await pool.destroy() pool = new DynamicThreadPool( @@ -835,14 +1362,64 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: true, - avgRunTime: true, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => { + const workerChoiceStrategy = WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: true, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: true, + average: true, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -870,26 +1447,38 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: expect.any(Number), median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThanOrEqual( - 0 - ) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.runTime.average).toBeGreaterThanOrEqual(0) } expect( @@ -929,24 +1518,38 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: expect.any(Number), median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) - expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0) expect(workerNode.workerUsage.runTime.average).toBeGreaterThan(0) } expect( @@ -971,7 +1574,7 @@ describe('Selection strategies test suite', () => { { workerChoiceStrategy: WorkerChoiceStrategies.WEIGHTED_ROUND_ROBIN, workerChoiceStrategyOptions: { - medRunTime: true + runTime: { median: true } } } ) @@ -991,24 +1594,38 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: expect.any(Number), + aggregate: expect.any(Number), average: 0, median: expect.any(Number), history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) - expect(workerNode.workerUsage.tasks.executed).toBeGreaterThan(0) + expect(workerNode.workerUsage.tasks.executed).toBeGreaterThanOrEqual(0) expect(workerNode.workerUsage.tasks.executed).toBeLessThanOrEqual( max * maxMultiplier ) - expect(workerNode.workerUsage.runTime.aggregation).toBeGreaterThan(0) + expect(workerNode.workerUsage.runTime.aggregate).toBeGreaterThan(0) expect(workerNode.workerUsage.runTime.median).toBeGreaterThan(0) } expect( @@ -1034,7 +1651,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1050,7 +1667,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1071,7 +1688,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1087,7 +1704,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1103,7 +1720,32 @@ describe('Selection strategies test suite', () => { await pool.destroy() }) - it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => { + it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default policy', async () => { + const workerChoiceStrategy = + WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN + let pool = new FixedThreadPool( + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true + }) + await pool.destroy() + pool = new DynamicThreadPool( + min, + max, + './tests/worker-files/thread/testWorker.js', + { workerChoiceStrategy } + ) + expect(pool.workerChoiceStrategyContext.getStrategyPolicy()).toStrictEqual({ + useDynamicWorker: true + }) + // We need to clean up the resources after our test + await pool.destroy() + }) + + it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks statistics requirements', async () => { const workerChoiceStrategy = WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN let pool = new FixedThreadPool( @@ -1111,14 +1753,24 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) await pool.destroy() pool = new DynamicThreadPool( @@ -1127,14 +1779,24 @@ describe('Selection strategies test suite', () => { './tests/worker-files/thread/testWorker.js', { workerChoiceStrategy } ) - expect(pool.workerChoiceStrategyContext.getTaskStatistics()).toStrictEqual({ - runTime: false, - avgRunTime: false, - medRunTime: false, - waitTime: false, - avgWaitTime: false, - medWaitTime: false, - elu: false + expect( + pool.workerChoiceStrategyContext.getTaskStatisticsRequirements() + ).toStrictEqual({ + runTime: { + aggregate: false, + average: false, + median: false + }, + waitTime: { + aggregate: false, + average: false, + median: false + }, + elu: { + aggregate: false, + average: false, + median: false + } }) // We need to clean up the resources after our test await pool.destroy() @@ -1165,18 +1827,32 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) } expect( @@ -1187,12 +1863,12 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentRoundId + ).roundId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1233,18 +1909,32 @@ describe('Selection strategies test suite', () => { failed: 0 }, runTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, waitTime: { - aggregation: 0, + aggregate: 0, average: 0, median: 0, history: expect.any(CircularArray) }, - elu: undefined + elu: { + idle: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + active: { + aggregate: 0, + average: 0, + median: 0, + history: expect.any(CircularArray) + }, + utilization: 0 + } }) } expect( @@ -1255,12 +1945,12 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentRoundId + ).roundId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1285,12 +1975,12 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentRoundId + ).roundId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1306,12 +1996,12 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentRoundId + ).roundId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1336,12 +2026,12 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentRoundId + ).roundId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBeDefined() expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( @@ -1357,7 +2047,7 @@ describe('Selection strategies test suite', () => { expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get( pool.workerChoiceStrategyContext.workerChoiceStrategy - ).currentWorkerNodeId + ).nextWorkerNodeId ).toBe(0) expect( pool.workerChoiceStrategyContext.workerChoiceStrategies.get(