feat: add ELU tasks accounting
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
index b10a7b56d26e60723e25268e0d3597e8d25501da..da261e89f930b94e52b872cff3c1c2b4796d8f26 100644 (file)
@@ -19,6 +19,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 () => {
@@ -164,7 +167,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: 0,
         runTimeHistory: expect.any(CircularArray),
@@ -177,6 +180,11 @@ describe('Selection strategies test suite', () => {
         error: 0
       })
     }
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        WorkerChoiceStrategies.ROUND_ROBIN
+      ).nextWorkerNodeId
+    ).toBe(0)
     // We need to clean up the resources after our test
     await pool.destroy()
   })
@@ -197,7 +205,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: 0,
         runTimeHistory: expect.any(CircularArray),
@@ -210,6 +218,11 @@ describe('Selection strategies test suite', () => {
         error: 0
       })
     }
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        WorkerChoiceStrategies.ROUND_ROBIN
+      ).nextWorkerNodeId
+    ).toBe(0)
     // We need to clean up the resources after our test
     await pool.destroy()
   })
@@ -333,7 +346,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: 0,
         runTimeHistory: expect.any(CircularArray),
@@ -366,7 +379,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: 0,
         runTimeHistory: expect.any(CircularArray),
@@ -436,7 +449,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: expect.any(Number),
+        ran: expect.any(Number),
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -448,8 +461,8 @@ describe('Selection strategies test suite', () => {
         medWaitTime: 0,
         error: 0
       })
-      expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
-      expect(workerNode.tasksUsage.run).toBeLessThanOrEqual(max * maxMultiplier)
+      expect(workerNode.tasksUsage.ran).toBeGreaterThan(0)
+      expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(max * maxMultiplier)
       expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
     }
     // We need to clean up the resources after our test
@@ -472,7 +485,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: expect.any(Number),
+        ran: expect.any(Number),
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -484,8 +497,8 @@ describe('Selection strategies test suite', () => {
         medWaitTime: 0,
         error: 0
       })
-      expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
-      expect(workerNode.tasksUsage.run).toBeLessThanOrEqual(max * maxMultiplier)
+      expect(workerNode.tasksUsage.ran).toBeGreaterThan(0)
+      expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(max * maxMultiplier)
       expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
     }
     // We need to clean up the resources after our test
@@ -545,7 +558,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -585,7 +598,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -630,7 +643,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: maxMultiplier,
+        ran: maxMultiplier,
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -781,7 +794,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: expect.any(Number),
+        ran: expect.any(Number),
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -793,8 +806,8 @@ describe('Selection strategies test suite', () => {
         medWaitTime: 0,
         error: 0
       })
-      expect(workerNode.tasksUsage.run).toBeGreaterThanOrEqual(0)
-      expect(workerNode.tasksUsage.run).toBeLessThanOrEqual(max * maxMultiplier)
+      expect(workerNode.tasksUsage.ran).toBeGreaterThanOrEqual(0)
+      expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(max * maxMultiplier)
       expect(workerNode.tasksUsage.runTime).toBeGreaterThanOrEqual(0)
       expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThanOrEqual(0)
     }
@@ -828,7 +841,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: expect.any(Number),
+        ran: expect.any(Number),
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -840,8 +853,8 @@ describe('Selection strategies test suite', () => {
         medWaitTime: 0,
         error: 0
       })
-      expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
-      expect(workerNode.tasksUsage.run).toBeLessThanOrEqual(max * maxMultiplier)
+      expect(workerNode.tasksUsage.ran).toBeGreaterThan(0)
+      expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(max * maxMultiplier)
       expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
       expect(workerNode.tasksUsage.avgRunTime).toBeGreaterThan(0)
     }
@@ -880,7 +893,7 @@ describe('Selection strategies test suite', () => {
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.tasksUsage).toStrictEqual({
-        run: expect.any(Number),
+        ran: expect.any(Number),
         running: 0,
         runTime: expect.any(Number),
         runTimeHistory: expect.any(CircularArray),
@@ -892,8 +905,8 @@ describe('Selection strategies test suite', () => {
         medWaitTime: 0,
         error: 0
       })
-      expect(workerNode.tasksUsage.run).toBeGreaterThan(0)
-      expect(workerNode.tasksUsage.run).toBeLessThanOrEqual(max * maxMultiplier)
+      expect(workerNode.tasksUsage.ran).toBeGreaterThan(0)
+      expect(workerNode.tasksUsage.ran).toBeLessThanOrEqual(max * maxMultiplier)
       expect(workerNode.tasksUsage.runTime).toBeGreaterThan(0)
       expect(workerNode.tasksUsage.medRunTime).toBeGreaterThan(0)
     }
@@ -989,6 +1002,266 @@ describe('Selection strategies test suite', () => {
     await pool.destroy()
   })
 
+  it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy default tasks usage statistics requirements', async () => {
+    const workerChoiceStrategy =
+      WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+    let pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      { workerChoiceStrategy }
+    )
+    expect(
+      pool.workerChoiceStrategyContext.getRequiredStatistics()
+    ).toStrictEqual({
+      runTime: false,
+      avgRunTime: false,
+      medRunTime: false,
+      waitTime: false,
+      avgWaitTime: false,
+      medWaitTime: false
+    })
+    await pool.destroy()
+    pool = new DynamicThreadPool(
+      min,
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      { workerChoiceStrategy }
+    )
+    expect(
+      pool.workerChoiceStrategyContext.getRequiredStatistics()
+    ).toStrictEqual({
+      runTime: false,
+      avgRunTime: false,
+      medRunTime: false,
+      waitTime: false,
+      avgWaitTime: false,
+      medWaitTime: false
+    })
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a fixed pool', async () => {
+    const pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      {
+        workerChoiceStrategy:
+          WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+      }
+    )
+    // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#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.tasksUsage).toStrictEqual({
+        ran: maxMultiplier,
+        running: 0,
+        runTime: 0,
+        runTimeHistory: expect.any(CircularArray),
+        avgRunTime: 0,
+        medRunTime: 0,
+        waitTime: 0,
+        waitTimeHistory: expect.any(CircularArray),
+        avgWaitTime: 0,
+        medWaitTime: 0,
+        error: 0
+      })
+    }
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ).toBeGreaterThan(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).currentRoundId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).currentWorkerNodeId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).roundWeights
+    ).toStrictEqual([
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ])
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy can be run in a dynamic pool', async () => {
+    const pool = new DynamicThreadPool(
+      min,
+      max,
+      './tests/worker-files/thread/testWorker.js',
+      {
+        workerChoiceStrategy:
+          WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+      }
+    )
+    // TODO: Create a better test to cover `InterleavedWeightedRoundRobinWorkerChoiceStrategy#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.tasksUsage).toStrictEqual({
+        ran: maxMultiplier,
+        running: 0,
+        runTime: 0,
+        runTimeHistory: expect.any(CircularArray),
+        avgRunTime: 0,
+        medRunTime: 0,
+        waitTime: 0,
+        waitTimeHistory: expect.any(CircularArray),
+        avgWaitTime: 0,
+        medWaitTime: 0,
+        error: 0
+      })
+    }
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ).toBeGreaterThan(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).currentRoundId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).currentWorkerNodeId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).roundWeights
+    ).toStrictEqual([
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ])
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
+  it('Verify INTERLEAVED_WEIGHTED_ROUND_ROBIN strategy internals are resets after setting it', async () => {
+    const workerChoiceStrategy =
+      WorkerChoiceStrategies.INTERLEAVED_WEIGHTED_ROUND_ROBIN
+    let pool = new FixedThreadPool(
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).currentRoundId
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).currentWorkerNodeId
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).defaultWorkerWeight
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).roundWeights
+    ).toBeDefined()
+    pool.setWorkerChoiceStrategy(workerChoiceStrategy)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).currentRoundId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).currentWorkerNodeId
+    ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ).toBeGreaterThan(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).roundWeights
+    ).toStrictEqual([
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ])
+    await pool.destroy()
+    pool = new DynamicThreadPool(
+      min,
+      max,
+      './tests/worker-files/thread/testWorker.js'
+    )
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).currentRoundId
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).currentWorkerNodeId
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).defaultWorkerWeight
+    ).toBeDefined()
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).roundWeights
+    ).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)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        workerChoiceStrategy
+      ).roundWeights
+    ).toStrictEqual([
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).defaultWorkerWeight
+    ])
+    // We need to clean up the resources after our test
+    await pool.destroy()
+  })
+
   it('Verify unknown strategy throw error', () => {
     expect(
       () =>