feat: improve IWRR implementation
[poolifier.git] / tests / pools / selection-strategies / selection-strategies.test.js
index 77713b6f03f20f8dc883cad07820b292a16d47de..6cc68a8b3cd58f26ff4911bcd9c0100de981a715 100644 (file)
@@ -1,5 +1,6 @@
 const { expect } = require('expect')
 const {
+  DynamicClusterPool,
   DynamicThreadPool,
   FixedClusterPool,
   FixedThreadPool,
@@ -65,6 +66,43 @@ describe('Selection strategies test suite', () => {
       expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
         workerChoiceStrategy
       )
+      expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
+        retries: 6,
+        runTime: { median: false },
+        waitTime: { median: false },
+        elu: { median: false }
+      })
+      expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
+        retries: 6,
+        runTime: { median: false },
+        waitTime: { median: false },
+        elu: { median: false }
+      })
+      await pool.destroy()
+    }
+    for (const workerChoiceStrategy of Object.values(WorkerChoiceStrategies)) {
+      const pool = new DynamicClusterPool(
+        min,
+        max,
+        './tests/worker-files/cluster/testWorker.js'
+      )
+      pool.setWorkerChoiceStrategy(workerChoiceStrategy, { retries: 3 })
+      expect(pool.opts.workerChoiceStrategy).toBe(workerChoiceStrategy)
+      expect(pool.workerChoiceStrategyContext.workerChoiceStrategy).toBe(
+        workerChoiceStrategy
+      )
+      expect(pool.opts.workerChoiceStrategyOptions).toStrictEqual({
+        retries: 3,
+        runTime: { median: false },
+        waitTime: { median: false },
+        elu: { median: false }
+      })
+      expect(pool.workerChoiceStrategyContext.opts).toStrictEqual({
+        retries: 3,
+        runTime: { median: false },
+        waitTime: { median: false },
+        elu: { median: false }
+      })
       await pool.destroy()
     }
   })
@@ -221,17 +259,17 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -270,17 +308,17 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -470,17 +508,17 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -518,17 +556,17 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -637,7 +675,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -646,18 +684,18 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
-        waitTime: {
+        }),
+        waitTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -695,7 +733,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -704,18 +742,18 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
-        waitTime: {
+        }),
+        waitTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -834,7 +872,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -844,24 +882,34 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
-        elu: {
-          idle: {
+        elu: expect.objectContaining({
+          idle: expect.objectContaining({
             history: expect.any(CircularArray)
-          },
-          active: {
+          }),
+          active: expect.objectContaining({
             history: expect.any(CircularArray)
-          }
-        }
+          })
+        })
       })
       expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
       expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
         max * maxMultiplier
       )
+      if (workerNode.usage.elu.active.aggregate == null) {
+        expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
+      }
+      if (workerNode.usage.elu.idle.aggregate == null) {
+        expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
+      }
       if (workerNode.usage.elu.utilization == null) {
         expect(workerNode.usage.elu.utilization).toBeUndefined()
       } else {
@@ -888,7 +936,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -898,24 +946,34 @@ describe('Selection strategies test suite', () => {
           failed: 0
         },
         runTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
-        elu: {
-          idle: {
+        elu: expect.objectContaining({
+          idle: expect.objectContaining({
             history: expect.any(CircularArray)
-          },
-          active: {
+          }),
+          active: expect.objectContaining({
             history: expect.any(CircularArray)
-          }
-        }
+          })
+        })
       })
       expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
       expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
         max * maxMultiplier
       )
+      if (workerNode.usage.elu.active.aggregate == null) {
+        expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
+      }
+      if (workerNode.usage.elu.idle.aggregate == null) {
+        expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
+      }
       if (workerNode.usage.elu.utilization == null) {
         expect(workerNode.usage.elu.utilization).toBeUndefined()
       } else {
@@ -1023,7 +1081,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -1032,20 +1090,20 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
-        elu: {
-          idle: {
+        elu: expect.objectContaining({
+          idle: expect.objectContaining({
             history: expect.any(CircularArray)
-          },
-          active: {
+          }),
+          active: expect.objectContaining({
             history: expect.any(CircularArray)
-          }
-        }
+          })
+        })
       })
       expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
       expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
@@ -1061,6 +1119,16 @@ describe('Selection strategies test suite', () => {
       } else {
         expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
       }
+      if (workerNode.usage.elu.active.aggregate == null) {
+        expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
+      }
+      if (workerNode.usage.elu.idle.aggregate == null) {
+        expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
+      }
       if (workerNode.usage.elu.utilization == null) {
         expect(workerNode.usage.elu.utilization).toBeUndefined()
       } else {
@@ -1092,7 +1160,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -1101,20 +1169,20 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
-        elu: {
-          idle: {
+        elu: expect.objectContaining({
+          idle: expect.objectContaining({
             history: expect.any(CircularArray)
-          },
-          active: {
+          }),
+          active: expect.objectContaining({
             history: expect.any(CircularArray)
-          }
-        }
+          })
+        })
       })
       expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
       expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
@@ -1130,6 +1198,16 @@ describe('Selection strategies test suite', () => {
       } else {
         expect(workerNode.usage.runTime.average).toBeGreaterThan(0)
       }
+      if (workerNode.usage.elu.active.aggregate == null) {
+        expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
+      }
+      if (workerNode.usage.elu.idle.aggregate == null) {
+        expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
+      }
       if (workerNode.usage.elu.utilization == null) {
         expect(workerNode.usage.elu.utilization).toBeUndefined()
       } else {
@@ -1166,7 +1244,7 @@ describe('Selection strategies test suite', () => {
     }
     await Promise.all(promises)
     for (const workerNode of pool.workerNodes) {
-      expect(workerNode.usage).toMatchObject({
+      expect(workerNode.usage).toStrictEqual({
         tasks: {
           executed: expect.any(Number),
           executing: 0,
@@ -1175,20 +1253,20 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
-        elu: {
-          idle: {
+        elu: expect.objectContaining({
+          idle: expect.objectContaining({
             history: expect.any(CircularArray)
-          },
-          active: {
+          }),
+          active: expect.objectContaining({
             history: expect.any(CircularArray)
-          }
-        }
+          })
+        })
       })
       expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
       expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
@@ -1204,6 +1282,16 @@ describe('Selection strategies test suite', () => {
       } else {
         expect(workerNode.usage.runTime.median).toBeGreaterThan(0)
       }
+      if (workerNode.usage.elu.active.aggregate == null) {
+        expect(workerNode.usage.elu.active.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.active.aggregate).toBeGreaterThan(0)
+      }
+      if (workerNode.usage.elu.idle.aggregate == null) {
+        expect(workerNode.usage.elu.idle.aggregate).toBeUndefined()
+      } else {
+        expect(workerNode.usage.elu.idle.aggregate).toBeGreaterThanOrEqual(0)
+      }
       if (workerNode.usage.elu.utilization == null) {
         expect(workerNode.usage.elu.utilization).toBeUndefined()
       } else {
@@ -1403,14 +1491,14 @@ describe('Selection strategies test suite', () => {
           history: expect.any(CircularArray)
         }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -1471,14 +1559,14 @@ describe('Selection strategies test suite', () => {
           history: expect.any(CircularArray)
         }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -1544,14 +1632,14 @@ describe('Selection strategies test suite', () => {
           history: expect.any(CircularArray)
         }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -1701,8 +1789,8 @@ describe('Selection strategies test suite', () => {
       pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
     ).toStrictEqual({
       runTime: {
-        aggregate: false,
-        average: false,
+        aggregate: true,
+        average: true,
         median: false
       },
       waitTime: {
@@ -1727,8 +1815,8 @@ describe('Selection strategies test suite', () => {
       pool.workerChoiceStrategyContext.getTaskStatisticsRequirements()
     ).toStrictEqual({
       runTime: {
-        aggregate: false,
-        average: false,
+        aggregate: true,
+        average: true,
         median: false
       },
       waitTime: {
@@ -1765,28 +1853,32 @@ describe('Selection strategies test suite', () => {
     for (const workerNode of pool.workerNodes) {
       expect(workerNode.usage).toStrictEqual({
         tasks: {
-          executed: maxMultiplier,
+          executed: expect.any(Number),
           executing: 0,
           queued: 0,
           maxQueued: 0,
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
+      expect(workerNode.usage.tasks.executed).toBeGreaterThanOrEqual(0)
+      expect(workerNode.usage.tasks.executed).toBeLessThanOrEqual(
+        max * maxMultiplier
+      )
     }
     expect(
       pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
@@ -1798,6 +1890,11 @@ describe('Selection strategies test suite', () => {
         pool.workerChoiceStrategyContext.workerChoiceStrategy
       ).roundId
     ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).workerNodeId
+    ).toBe(0)
     expect(
       pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
         pool.workerChoiceStrategyContext.workerChoiceStrategy
@@ -1843,18 +1940,18 @@ describe('Selection strategies test suite', () => {
           stolen: 0,
           failed: 0
         },
-        runTime: {
+        runTime: expect.objectContaining({
           history: expect.any(CircularArray)
-        },
+        }),
         waitTime: {
-          history: expect.any(CircularArray)
+          history: new CircularArray()
         },
         elu: {
           idle: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           },
           active: {
-            history: expect.any(CircularArray)
+            history: new CircularArray()
           }
         }
       })
@@ -1873,6 +1970,11 @@ describe('Selection strategies test suite', () => {
         pool.workerChoiceStrategyContext.workerChoiceStrategy
       ).roundId
     ).toBe(0)
+    expect(
+      pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
+        pool.workerChoiceStrategyContext.workerChoiceStrategy
+      ).workerNodeId
+    ).toBe(0)
     expect(
       pool.workerChoiceStrategyContext.workerChoiceStrategies.get(
         pool.workerChoiceStrategyContext.workerChoiceStrategy