@tshifhiwa/ohrm-ui-automation-framework
Version:
Playwright and TypeScript–based test automation framework for validating core UI features and workflows of the OrangeHRM demo application.
86 lines (75 loc) • 3.14 kB
text/typescript
import * as os from "os";
import type { AllocatorType } from "./workerAllocator.type.js";
import ErrorHandler from "../errorHandling/errorHandler.js";
export default class WorkerAllocator {
private static readonly totalCores = os.cpus().length;
private static readonly MIN_WORKERS = 1;
/**
* Optimal worker count for the current environment.
* Uses sharding in CI or the provided local strategy otherwise.
*/
public static getOptimalWorkerCount(localStrategy: AllocatorType): number {
return this.shardingEnabled
? this.getWorkersForCIShard()
: this.getWorkersForLocalStrategy(localStrategy);
}
/**
* Whether sharding is enabled for the current test run.
*/
private static get shardingEnabled(): boolean {
return !!(process.env.SHARD_INDEX && process.env.SHARD_TOTAL);
}
/**
* Worker count for CI environments with sharding enabled.
* Distributes cores evenly across shards, with remainder cores
* allocated to the first shards.
*/
private static getWorkersForCIShard(): number {
const shardTotal = parseInt(process.env.SHARD_TOTAL || "1", 10);
const shardIndex = parseInt(process.env.SHARD_INDEX || "0", 10);
// Validate shard configuration
if (shardIndex >= shardTotal) {
return ErrorHandler.logAndThrow(
"WorkerAllocator",
`Invalid shard config: SHARD_INDEX (${shardIndex}) must be less than SHARD_TOTAL (${shardTotal}).`,
);
}
if (shardTotal < 1) {
return ErrorHandler.logAndThrow(
"WorkerAllocator",
`Invalid shard config: SHARD_TOTAL must be at least 1, got ${shardTotal}.`,
);
}
// Calculate base workers per shard
const baseWorkersPerShard = Math.floor(this.totalCores / shardTotal);
const remainingCores = this.totalCores % shardTotal;
// Distribute remaining cores to first shards
const workersForThisShard =
shardIndex < remainingCores ? baseWorkersPerShard + 1 : baseWorkersPerShard;
return Math.max(this.MIN_WORKERS, workersForThisShard);
}
/**
* Worker count for local development based on the given allocation strategy.
*/
private static getWorkersForLocalStrategy(strategy: AllocatorType): number {
switch (strategy) {
case "all-cores":
return this.totalCores;
case "75-percent":
return Math.max(this.MIN_WORKERS, Math.ceil(this.totalCores * 0.75));
case "50-percent":
return Math.max(this.MIN_WORKERS, Math.ceil(this.totalCores * 0.5));
case "25-percent":
return Math.max(this.MIN_WORKERS, Math.ceil(this.totalCores * 0.25));
case "10-percent":
return Math.max(this.MIN_WORKERS, Math.ceil(this.totalCores * 0.1));
default:
// Exhaustive check - this should never be reached
const _exhaustive: never = strategy;
return ErrorHandler.logAndThrow(
"WorkerAllocator",
`Unknown allocation strategy: ${strategy}. Valid strategies: all-cores, 75-percent, 50-percent, 25-percent, 10-percent.`,
);
}
}
}