@jsenv/test 1.8.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsenv_test.js +59 -43
- package/package.json +1 -1
- package/src/execution/execute_test_plan.js +59 -42
package/dist/jsenv_test.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os from "node:os";
|
|
1
2
|
import { chmod, stat, lstat, readdir, promises, unlink, openSync, closeSync, rmdir, readFile as readFile$1, writeFile as writeFile$1, writeFileSync as writeFileSync$1, mkdirSync, readFileSync, readdirSync, existsSync } from "node:fs";
|
|
2
3
|
import process$1, { memoryUsage } from "node:process";
|
|
3
4
|
import v8, { takeCoverage } from "node:v8";
|
|
@@ -6,7 +7,6 @@ import { URL_META, filterV8Coverage } from "./js/v8_coverage.js";
|
|
|
6
7
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
7
8
|
import crypto from "node:crypto";
|
|
8
9
|
import { dirname } from "node:path";
|
|
9
|
-
import os from "node:os";
|
|
10
10
|
import tty from "node:tty";
|
|
11
11
|
import stringWidth from "string-width";
|
|
12
12
|
import { readGitHubWorkflowEnv, startGithubCheckRun } from "@jsenv/github-check-run";
|
|
@@ -4636,7 +4636,7 @@ const ensureGlobalGc = () => {
|
|
|
4636
4636
|
* @param {Object} testPlanParameters.testPlan Object associating files with runtimes where they will be executed
|
|
4637
4637
|
* @param {boolean} [testPlanParameters.logShortForCompletedExecutions=false] Abbreviate completed execution information to shorten terminal output
|
|
4638
4638
|
* @param {boolean} [testPlanParameters.logMergeForCompletedExecutions=false] Merge completed execution logs to shorten terminal output
|
|
4639
|
-
* @param {number} [testPlanParameters.
|
|
4639
|
+
* @param {boolean|number} [testPlanParameters.concurrency=false] Maximum amount of execution running at the same time
|
|
4640
4640
|
* @param {number} [testPlanParameters.defaultMsAllocatedPerExecution=30000] Milliseconds after which execution is aborted and considered as failed by timeout
|
|
4641
4641
|
* @param {boolean} [testPlanParameters.failFast=false] Fails immediatly when a test execution fails
|
|
4642
4642
|
* @param {number} [testPlanParameters.cooldownBetweenExecutions=0] Millisecond to wait between each execution
|
|
@@ -4663,7 +4663,7 @@ const executeTestPlan = async ({
|
|
|
4663
4663
|
webServer,
|
|
4664
4664
|
testPlan,
|
|
4665
4665
|
updateProcessExitCode = true,
|
|
4666
|
-
|
|
4666
|
+
concurrency = false,
|
|
4667
4667
|
defaultMsAllocatedPerExecution = 30_000,
|
|
4668
4668
|
failFast = false,
|
|
4669
4669
|
// keepRunning: false to ensure runtime is stopped once executed
|
|
@@ -4930,6 +4930,10 @@ To fix this warning:
|
|
|
4930
4930
|
}
|
|
4931
4931
|
}
|
|
4932
4932
|
}
|
|
4933
|
+
|
|
4934
|
+
if (typeof concurrency !== "boolean" && typeof concurrency !== "number") {
|
|
4935
|
+
throw new TypeError(`concurrency must be a boolean or a number`);
|
|
4936
|
+
}
|
|
4933
4937
|
}
|
|
4934
4938
|
|
|
4935
4939
|
logger.debug(
|
|
@@ -4968,6 +4972,25 @@ To fix this warning:
|
|
|
4968
4972
|
}
|
|
4969
4973
|
}
|
|
4970
4974
|
}
|
|
4975
|
+
if (cooldownBetweenExecutions) {
|
|
4976
|
+
if (cooldownBetweenExecutions < 0) {
|
|
4977
|
+
cooldownBetweenExecutions = 0;
|
|
4978
|
+
}
|
|
4979
|
+
if (cooldownBetweenExecutions === Infinity) {
|
|
4980
|
+
cooldownBetweenExecutions = 0;
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
if (concurrency === true) {
|
|
4984
|
+
const availableCpus = os.cpus().length;
|
|
4985
|
+
concurrency =
|
|
4986
|
+
availableCpus > 2
|
|
4987
|
+
? // One CPU is used to run this code so we do availableCpus - 1
|
|
4988
|
+
availableCpus - 1
|
|
4989
|
+
: 1;
|
|
4990
|
+
}
|
|
4991
|
+
if (concurrency === false) {
|
|
4992
|
+
concurrency = 1;
|
|
4993
|
+
}
|
|
4971
4994
|
}
|
|
4972
4995
|
|
|
4973
4996
|
testPlan = {
|
|
@@ -5107,7 +5130,7 @@ To fix this warning:
|
|
|
5107
5130
|
const executionLogsEnabled = logger.levels.info;
|
|
5108
5131
|
const executionSpinner =
|
|
5109
5132
|
logRefresh &&
|
|
5110
|
-
|
|
5133
|
+
concurrency === 1 &&
|
|
5111
5134
|
!debugLogsEnabled &&
|
|
5112
5135
|
executionLogsEnabled &&
|
|
5113
5136
|
process.stdout.isTTY &&
|
|
@@ -5130,9 +5153,9 @@ To fix this warning:
|
|
|
5130
5153
|
|
|
5131
5154
|
const callWhenPreviousExecutionAreDone = createCallOrderer();
|
|
5132
5155
|
|
|
5133
|
-
await
|
|
5156
|
+
await executeConcurrently({
|
|
5134
5157
|
multipleExecutionsOperation,
|
|
5135
|
-
|
|
5158
|
+
concurrency,
|
|
5136
5159
|
cooldownBetweenExecutions,
|
|
5137
5160
|
executionSteps,
|
|
5138
5161
|
start: async (paramsFromStep) => {
|
|
@@ -5405,57 +5428,50 @@ const canOverwriteLogGetter = ({
|
|
|
5405
5428
|
return true;
|
|
5406
5429
|
};
|
|
5407
5430
|
|
|
5408
|
-
const
|
|
5431
|
+
const executeConcurrently = async ({
|
|
5409
5432
|
multipleExecutionsOperation,
|
|
5410
|
-
|
|
5433
|
+
concurrency,
|
|
5411
5434
|
cooldownBetweenExecutions,
|
|
5412
5435
|
executionSteps,
|
|
5413
5436
|
start,
|
|
5414
5437
|
}) => {
|
|
5415
|
-
const executionResults = [];
|
|
5416
5438
|
let progressionIndex = 0;
|
|
5417
|
-
let
|
|
5439
|
+
let remainingExecutionToStart = executionSteps.length;
|
|
5418
5440
|
|
|
5419
|
-
const
|
|
5420
|
-
if (
|
|
5441
|
+
const startNext = async () => {
|
|
5442
|
+
if (remainingExecutionToStart === 0) {
|
|
5421
5443
|
return;
|
|
5422
5444
|
}
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
remainingExecutionCount--;
|
|
5430
|
-
const outputPromise = executeOne(progressionIndex, previousExecPromise);
|
|
5431
|
-
previousExecPromise = outputPromise;
|
|
5432
|
-
progressionIndex++;
|
|
5433
|
-
outputPromiseArray.push(outputPromise);
|
|
5434
|
-
}
|
|
5435
|
-
if (outputPromiseArray.length) {
|
|
5436
|
-
await Promise.all(outputPromiseArray);
|
|
5437
|
-
if (remainingExecutionCount > 0) {
|
|
5438
|
-
await nextChunk();
|
|
5439
|
-
}
|
|
5440
|
-
}
|
|
5441
|
-
};
|
|
5442
|
-
|
|
5443
|
-
const executeOne = async (index, previousExecPromise) => {
|
|
5444
|
-
const input = executionSteps[index];
|
|
5445
|
-
const output = await start(input, previousExecPromise);
|
|
5446
|
-
if (!multipleExecutionsOperation.signal.aborted) {
|
|
5447
|
-
executionResults[index] = output;
|
|
5445
|
+
remainingExecutionToStart--;
|
|
5446
|
+
const input = executionSteps[progressionIndex];
|
|
5447
|
+
progressionIndex++;
|
|
5448
|
+
await start(input);
|
|
5449
|
+
if (multipleExecutionsOperation.signal.aborted) {
|
|
5450
|
+
return;
|
|
5448
5451
|
}
|
|
5449
5452
|
if (cooldownBetweenExecutions) {
|
|
5450
|
-
await new Promise((resolve) =>
|
|
5451
|
-
setTimeout(
|
|
5452
|
-
|
|
5453
|
+
await new Promise((resolve) => {
|
|
5454
|
+
const timeoutId = setTimeout(() => {
|
|
5455
|
+
removeClearTimeoutOnAbort();
|
|
5456
|
+
resolve();
|
|
5457
|
+
}, cooldownBetweenExecutions);
|
|
5458
|
+
const removeClearTimeoutOnAbort =
|
|
5459
|
+
multipleExecutionsOperation.signal.addAbortCallback(() => {
|
|
5460
|
+
clearTimeout(timeoutId);
|
|
5461
|
+
});
|
|
5462
|
+
});
|
|
5463
|
+
if (multipleExecutionsOperation.signal.aborted) {
|
|
5464
|
+
return;
|
|
5465
|
+
}
|
|
5453
5466
|
}
|
|
5467
|
+
await startNext();
|
|
5454
5468
|
};
|
|
5455
5469
|
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5470
|
+
const promises = [];
|
|
5471
|
+
while (concurrency--) {
|
|
5472
|
+
promises.push(startNext());
|
|
5473
|
+
}
|
|
5474
|
+
await Promise.all(promises);
|
|
5459
5475
|
};
|
|
5460
5476
|
|
|
5461
5477
|
const memoize = (compute) => {
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os from "node:os";
|
|
1
2
|
import { existsSync } from "node:fs";
|
|
2
3
|
import { memoryUsage } from "node:process";
|
|
3
4
|
import { takeCoverage } from "node:v8";
|
|
@@ -48,7 +49,7 @@ import { ensureGlobalGc } from "./gc.js";
|
|
|
48
49
|
* @param {Object} testPlanParameters.testPlan Object associating files with runtimes where they will be executed
|
|
49
50
|
* @param {boolean} [testPlanParameters.logShortForCompletedExecutions=false] Abbreviate completed execution information to shorten terminal output
|
|
50
51
|
* @param {boolean} [testPlanParameters.logMergeForCompletedExecutions=false] Merge completed execution logs to shorten terminal output
|
|
51
|
-
* @param {number} [testPlanParameters.
|
|
52
|
+
* @param {boolean|number} [testPlanParameters.concurrency=false] Maximum amount of execution running at the same time
|
|
52
53
|
* @param {number} [testPlanParameters.defaultMsAllocatedPerExecution=30000] Milliseconds after which execution is aborted and considered as failed by timeout
|
|
53
54
|
* @param {boolean} [testPlanParameters.failFast=false] Fails immediatly when a test execution fails
|
|
54
55
|
* @param {number} [testPlanParameters.cooldownBetweenExecutions=0] Millisecond to wait between each execution
|
|
@@ -75,7 +76,7 @@ export const executeTestPlan = async ({
|
|
|
75
76
|
webServer,
|
|
76
77
|
testPlan,
|
|
77
78
|
updateProcessExitCode = true,
|
|
78
|
-
|
|
79
|
+
concurrency = false,
|
|
79
80
|
defaultMsAllocatedPerExecution = 30_000,
|
|
80
81
|
failFast = false,
|
|
81
82
|
// keepRunning: false to ensure runtime is stopped once executed
|
|
@@ -342,6 +343,10 @@ To fix this warning:
|
|
|
342
343
|
}
|
|
343
344
|
}
|
|
344
345
|
}
|
|
346
|
+
|
|
347
|
+
if (typeof concurrency !== "boolean" && typeof concurrency !== "number") {
|
|
348
|
+
throw new TypeError(`concurrency must be a boolean or a number`);
|
|
349
|
+
}
|
|
345
350
|
}
|
|
346
351
|
|
|
347
352
|
logger.debug(
|
|
@@ -380,6 +385,25 @@ To fix this warning:
|
|
|
380
385
|
}
|
|
381
386
|
}
|
|
382
387
|
}
|
|
388
|
+
if (cooldownBetweenExecutions) {
|
|
389
|
+
if (cooldownBetweenExecutions < 0) {
|
|
390
|
+
cooldownBetweenExecutions = 0;
|
|
391
|
+
}
|
|
392
|
+
if (cooldownBetweenExecutions === Infinity) {
|
|
393
|
+
cooldownBetweenExecutions = 0;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
if (concurrency === true) {
|
|
397
|
+
const availableCpus = os.cpus().length;
|
|
398
|
+
concurrency =
|
|
399
|
+
availableCpus > 2
|
|
400
|
+
? // One CPU is used to run this code so we do availableCpus - 1
|
|
401
|
+
availableCpus - 1
|
|
402
|
+
: 1;
|
|
403
|
+
}
|
|
404
|
+
if (concurrency === false) {
|
|
405
|
+
concurrency = 1;
|
|
406
|
+
}
|
|
383
407
|
}
|
|
384
408
|
|
|
385
409
|
testPlan = {
|
|
@@ -519,7 +543,7 @@ To fix this warning:
|
|
|
519
543
|
const executionLogsEnabled = logger.levels.info;
|
|
520
544
|
const executionSpinner =
|
|
521
545
|
logRefresh &&
|
|
522
|
-
|
|
546
|
+
concurrency === 1 &&
|
|
523
547
|
!debugLogsEnabled &&
|
|
524
548
|
executionLogsEnabled &&
|
|
525
549
|
process.stdout.isTTY &&
|
|
@@ -542,9 +566,9 @@ To fix this warning:
|
|
|
542
566
|
|
|
543
567
|
const callWhenPreviousExecutionAreDone = createCallOrderer();
|
|
544
568
|
|
|
545
|
-
await
|
|
569
|
+
await executeConcurrently({
|
|
546
570
|
multipleExecutionsOperation,
|
|
547
|
-
|
|
571
|
+
concurrency,
|
|
548
572
|
cooldownBetweenExecutions,
|
|
549
573
|
executionSteps,
|
|
550
574
|
start: async (paramsFromStep) => {
|
|
@@ -817,55 +841,48 @@ const canOverwriteLogGetter = ({
|
|
|
817
841
|
return true;
|
|
818
842
|
};
|
|
819
843
|
|
|
820
|
-
const
|
|
844
|
+
const executeConcurrently = async ({
|
|
821
845
|
multipleExecutionsOperation,
|
|
822
|
-
|
|
846
|
+
concurrency,
|
|
823
847
|
cooldownBetweenExecutions,
|
|
824
848
|
executionSteps,
|
|
825
849
|
start,
|
|
826
850
|
}) => {
|
|
827
|
-
const executionResults = [];
|
|
828
851
|
let progressionIndex = 0;
|
|
829
|
-
let
|
|
852
|
+
let remainingExecutionToStart = executionSteps.length;
|
|
830
853
|
|
|
831
|
-
const
|
|
832
|
-
if (
|
|
854
|
+
const startNext = async () => {
|
|
855
|
+
if (remainingExecutionToStart === 0) {
|
|
833
856
|
return;
|
|
834
857
|
}
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
remainingExecutionCount--;
|
|
842
|
-
const outputPromise = executeOne(progressionIndex, previousExecPromise);
|
|
843
|
-
previousExecPromise = outputPromise;
|
|
844
|
-
progressionIndex++;
|
|
845
|
-
outputPromiseArray.push(outputPromise);
|
|
846
|
-
}
|
|
847
|
-
if (outputPromiseArray.length) {
|
|
848
|
-
await Promise.all(outputPromiseArray);
|
|
849
|
-
if (remainingExecutionCount > 0) {
|
|
850
|
-
await nextChunk();
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
};
|
|
854
|
-
|
|
855
|
-
const executeOne = async (index, previousExecPromise) => {
|
|
856
|
-
const input = executionSteps[index];
|
|
857
|
-
const output = await start(input, previousExecPromise);
|
|
858
|
-
if (!multipleExecutionsOperation.signal.aborted) {
|
|
859
|
-
executionResults[index] = output;
|
|
858
|
+
remainingExecutionToStart--;
|
|
859
|
+
const input = executionSteps[progressionIndex];
|
|
860
|
+
progressionIndex++;
|
|
861
|
+
await start(input);
|
|
862
|
+
if (multipleExecutionsOperation.signal.aborted) {
|
|
863
|
+
return;
|
|
860
864
|
}
|
|
861
865
|
if (cooldownBetweenExecutions) {
|
|
862
|
-
await new Promise((resolve) =>
|
|
863
|
-
setTimeout(
|
|
864
|
-
|
|
866
|
+
await new Promise((resolve) => {
|
|
867
|
+
const timeoutId = setTimeout(() => {
|
|
868
|
+
removeClearTimeoutOnAbort();
|
|
869
|
+
resolve();
|
|
870
|
+
}, cooldownBetweenExecutions);
|
|
871
|
+
const removeClearTimeoutOnAbort =
|
|
872
|
+
multipleExecutionsOperation.signal.addAbortCallback(() => {
|
|
873
|
+
clearTimeout(timeoutId);
|
|
874
|
+
});
|
|
875
|
+
});
|
|
876
|
+
if (multipleExecutionsOperation.signal.aborted) {
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
865
879
|
}
|
|
880
|
+
await startNext();
|
|
866
881
|
};
|
|
867
882
|
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
883
|
+
const promises = [];
|
|
884
|
+
while (concurrency--) {
|
|
885
|
+
promises.push(startNext());
|
|
886
|
+
}
|
|
887
|
+
await Promise.all(promises);
|
|
871
888
|
};
|