@jsenv/test 3.0.9 → 3.0.11
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 +299 -114
- package/package.json +1 -1
- package/src/execution/execute_test_plan.js +137 -29
- package/src/execution/reporters/reporter_list.js +149 -85
- package/src/helpers/cpu_usage.js +55 -1
- package/src/helpers/cpu_usage.test_manual.js +10 -2
package/dist/jsenv_test.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import os, { cpus,
|
|
1
|
+
import os, { cpus, release, totalmem, availableParallelism, freemem } from "node:os";
|
|
2
|
+
import process$1, { cpuUsage, memoryUsage } from "node:process";
|
|
2
3
|
import { readdir, chmod, stat, lstat, promises, readFile as readFile$1, writeFileSync as writeFileSync$1, mkdirSync, unlink, openSync, closeSync, rmdir, chmodSync, statSync, lstatSync, unlinkSync, readdirSync, rmdirSync, readFileSync, existsSync } from "node:fs";
|
|
3
4
|
import { takeCoverage } from "node:v8";
|
|
4
5
|
import stripAnsi from "strip-ansi";
|
|
5
6
|
import { URL_META, createException } from "./js/exception.js";
|
|
6
7
|
import stringWidth from "string-width";
|
|
7
|
-
import process$1, { memoryUsage } from "node:process";
|
|
8
8
|
import tty from "node:tty";
|
|
9
9
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
10
10
|
import { dirname } from "node:path";
|
|
@@ -1456,7 +1456,7 @@ const humanizeFileSize = (numberOfBytes, { decimals, short } = {}) => {
|
|
|
1456
1456
|
return inspectBytes(numberOfBytes, { decimals, short });
|
|
1457
1457
|
};
|
|
1458
1458
|
|
|
1459
|
-
const
|
|
1459
|
+
const humanizeMemory = (metricValue, { decimals, short } = {}) => {
|
|
1460
1460
|
return inspectBytes(metricValue, { decimals, fixedDecimals: true, short });
|
|
1461
1461
|
};
|
|
1462
1462
|
|
|
@@ -3292,9 +3292,10 @@ process.platform === "linux";
|
|
|
3292
3292
|
// https://gist.github.com/GaetanoPiazzolla/c40e1ebb9f709d091208e89baf9f4e00
|
|
3293
3293
|
|
|
3294
3294
|
|
|
3295
|
-
const
|
|
3295
|
+
const startMeasuringTotalCpuUsage = () => {
|
|
3296
3296
|
let previousCpuArray = cpus();
|
|
3297
3297
|
let previousMs = Date.now();
|
|
3298
|
+
let previousCpuUsage = cpuUsage();
|
|
3298
3299
|
|
|
3299
3300
|
const overall = {
|
|
3300
3301
|
inactive: 100,
|
|
@@ -3302,6 +3303,12 @@ const startMeasuringCpuUsage = () => {
|
|
|
3302
3303
|
system: 0,
|
|
3303
3304
|
user: 0,
|
|
3304
3305
|
};
|
|
3306
|
+
|
|
3307
|
+
const thisProcess = {
|
|
3308
|
+
active: 0,
|
|
3309
|
+
system: 0,
|
|
3310
|
+
user: 0,
|
|
3311
|
+
};
|
|
3305
3312
|
const details = previousCpuArray.map(() => {
|
|
3306
3313
|
return {
|
|
3307
3314
|
inactive: 100,
|
|
@@ -3358,6 +3365,19 @@ const startMeasuringCpuUsage = () => {
|
|
|
3358
3365
|
overallUsageSample,
|
|
3359
3366
|
});
|
|
3360
3367
|
|
|
3368
|
+
const processCpuUsage = cpuUsage();
|
|
3369
|
+
const thisProcessSystemMs = Math.round(
|
|
3370
|
+
(processCpuUsage.system - previousCpuUsage.system) / 1000,
|
|
3371
|
+
);
|
|
3372
|
+
const thisProcessUserMs = Math.round(
|
|
3373
|
+
(processCpuUsage.user - previousCpuUsage.user) / 1000,
|
|
3374
|
+
);
|
|
3375
|
+
previousCpuUsage = processCpuUsage;
|
|
3376
|
+
const thisProcessActiveMs = thisProcessSystemMs + thisProcessUserMs;
|
|
3377
|
+
thisProcess.active = thisProcessActiveMs / overallMsEllapsed;
|
|
3378
|
+
thisProcess.system = thisProcessSystemMs / overallMsEllapsed;
|
|
3379
|
+
thisProcess.user = thisProcessUserMs / overallMsEllapsed;
|
|
3380
|
+
|
|
3361
3381
|
if (samples.length === 10) {
|
|
3362
3382
|
let index = 0;
|
|
3363
3383
|
for (const detail of details) {
|
|
@@ -3407,6 +3427,7 @@ const startMeasuringCpuUsage = () => {
|
|
|
3407
3427
|
|
|
3408
3428
|
return {
|
|
3409
3429
|
overall,
|
|
3430
|
+
thisProcess,
|
|
3410
3431
|
details,
|
|
3411
3432
|
stop: () => {
|
|
3412
3433
|
clearInterval(interval);
|
|
@@ -4946,7 +4967,9 @@ const replaceUrls = (source, replace) => {
|
|
|
4946
4967
|
const reporterList = ({
|
|
4947
4968
|
animated = true,
|
|
4948
4969
|
mockFluctuatingValues, // used for snapshot testing logs
|
|
4949
|
-
|
|
4970
|
+
platformInfo,
|
|
4971
|
+
memoryUsage: memoryUsage$1,
|
|
4972
|
+
cpuUsage,
|
|
4950
4973
|
spy = () => {
|
|
4951
4974
|
return {
|
|
4952
4975
|
write: (log) => {
|
|
@@ -4967,7 +4990,9 @@ const reporterList = ({
|
|
|
4967
4990
|
process.exitCode !== 1;
|
|
4968
4991
|
|
|
4969
4992
|
const logOptions = {
|
|
4970
|
-
|
|
4993
|
+
platformInfo,
|
|
4994
|
+
memoryUsage: memoryUsage$1,
|
|
4995
|
+
cpuUsage,
|
|
4971
4996
|
mockFluctuatingValues,
|
|
4972
4997
|
group: false,
|
|
4973
4998
|
intermediateSummary: !animatedLogEnabled,
|
|
@@ -5028,7 +5053,7 @@ const reporterList = ({
|
|
|
5028
5053
|
});
|
|
5029
5054
|
infos.push(ANSI.color(duration, ANSI.GREY));
|
|
5030
5055
|
const memoryHeapUsed = memoryUsage().heapUsed;
|
|
5031
|
-
const memoryHeapUsedFormatted =
|
|
5056
|
+
const memoryHeapUsedFormatted = humanizeMemory(memoryHeapUsed, {
|
|
5032
5057
|
short: true,
|
|
5033
5058
|
decimals: 0,
|
|
5034
5059
|
});
|
|
@@ -5079,8 +5104,10 @@ const reporterList = ({
|
|
|
5079
5104
|
reporters.push(
|
|
5080
5105
|
reporterList({
|
|
5081
5106
|
animated: false,
|
|
5107
|
+
platformInfo,
|
|
5108
|
+
memoryUsage: memoryUsage$1,
|
|
5109
|
+
cpuUsage,
|
|
5082
5110
|
mockFluctuatingValues, // used for snapshot testing logs
|
|
5083
|
-
showMemoryUsage,
|
|
5084
5111
|
spy: () => {
|
|
5085
5112
|
let rawOutput = "";
|
|
5086
5113
|
|
|
@@ -5100,58 +5127,59 @@ const reporterList = ({
|
|
|
5100
5127
|
};
|
|
5101
5128
|
|
|
5102
5129
|
const renderIntro = (testPlanResult, logOptions) => {
|
|
5103
|
-
const
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5130
|
+
const lines = [];
|
|
5131
|
+
if (logOptions.platformInfo) {
|
|
5132
|
+
{
|
|
5133
|
+
let osLine = `os: `;
|
|
5134
|
+
if (logOptions.mockFluctuatingValues) {
|
|
5135
|
+
osLine += `os@<mock>`;
|
|
5136
|
+
} else {
|
|
5137
|
+
osLine += `${testPlanResult.os.name}@${testPlanResult.os.version}`;
|
|
5138
|
+
}
|
|
5139
|
+
osLine += renderDetails({
|
|
5140
|
+
cpu: logOptions.mockFluctuatingValues
|
|
5141
|
+
? "<mock>"
|
|
5142
|
+
: testPlanResult.os.availableCpu,
|
|
5143
|
+
memory: logOptions.mockFluctuatingValues
|
|
5144
|
+
? "<mock>GB"
|
|
5145
|
+
: humanizeMemory(testPlanResult.os.availableMemory, {
|
|
5146
|
+
short: true,
|
|
5147
|
+
decimals: 0,
|
|
5148
|
+
}),
|
|
5149
|
+
});
|
|
5150
|
+
lines.push(osLine);
|
|
5151
|
+
}
|
|
5152
|
+
{
|
|
5153
|
+
const process = logOptions.mockFluctuatingValues
|
|
5154
|
+
? `node@mock`
|
|
5155
|
+
: `${testPlanResult.process.name}@${testPlanResult.process.version}`;
|
|
5156
|
+
let processLine = `process: ${process}`;
|
|
5157
|
+
lines.push(processLine);
|
|
5158
|
+
}
|
|
5159
|
+
}
|
|
5160
|
+
|
|
5161
|
+
const directory = logOptions.mockFluctuatingValues
|
|
5162
|
+
? "/mock/"
|
|
5163
|
+
: urlToFileSystemPath(testPlanResult.rootDirectoryUrl);
|
|
5164
|
+
const numberOfFiles = Object.keys(testPlanResult.results).length;
|
|
5165
|
+
let fileFoundLine = "";
|
|
5166
|
+
if (numberOfFiles === 0) {
|
|
5167
|
+
fileFoundLine += `no file matching "testPlan" in ${directory}:
|
|
5168
|
+
${testPlanResult.patterns.join("\n")}`;
|
|
5169
|
+
} else if (numberOfFiles === 1) {
|
|
5170
|
+
fileFoundLine += `1 file matching "testPlan" in ${directory}`;
|
|
5171
|
+
} else {
|
|
5172
|
+
fileFoundLine += `${numberOfFiles} files matching "testPlan" in ${directory}`;
|
|
5140
5173
|
}
|
|
5174
|
+
|
|
5175
|
+
lines.push(fileFoundLine);
|
|
5176
|
+
|
|
5141
5177
|
return `${renderBigSection({
|
|
5142
|
-
title:
|
|
5143
|
-
content:
|
|
5178
|
+
title: "execution start",
|
|
5179
|
+
content: lines.join("\n"),
|
|
5144
5180
|
})}\n\n`;
|
|
5145
5181
|
};
|
|
5146
5182
|
|
|
5147
|
-
const getGroupRenderedName = (groupInfo, logOptions) => {
|
|
5148
|
-
let { runtimeName, runtimeVersion } = groupInfo;
|
|
5149
|
-
if (logOptions.mockFluctuatingValues && groupInfo.runtimeType === "node") {
|
|
5150
|
-
runtimeVersion = "<mock>";
|
|
5151
|
-
}
|
|
5152
|
-
return `${runtimeName}@${runtimeVersion}`;
|
|
5153
|
-
};
|
|
5154
|
-
|
|
5155
5183
|
const renderExecutionLog = (execution, logOptions) => {
|
|
5156
5184
|
let log = "";
|
|
5157
5185
|
// label
|
|
@@ -5206,10 +5234,10 @@ const renderExecutionLabel = (execution, logOptions) => {
|
|
|
5206
5234
|
: humanizeDuration(duration, { short: true });
|
|
5207
5235
|
infos.push(ANSI.color(durationFormatted, ANSI.GREY));
|
|
5208
5236
|
}
|
|
5209
|
-
if (logOptions.
|
|
5237
|
+
if (logOptions.memoryUsage && typeof memoryUsage === "number") {
|
|
5210
5238
|
const memoryUsageFormatted = logOptions.mockFluctuatingValues
|
|
5211
5239
|
? `<mock>MB`
|
|
5212
|
-
:
|
|
5240
|
+
: humanizeMemory(memoryUsage, { short: true });
|
|
5213
5241
|
infos.push(ANSI.color(memoryUsageFormatted, ANSI.GREY));
|
|
5214
5242
|
}
|
|
5215
5243
|
if (infos.length) {
|
|
@@ -5471,55 +5499,88 @@ const renderErrors = (execution, logOptions) => {
|
|
|
5471
5499
|
};
|
|
5472
5500
|
|
|
5473
5501
|
const renderOutro = (testPlanResult, logOptions = {}) => {
|
|
5474
|
-
|
|
5502
|
+
const lines = [];
|
|
5475
5503
|
const { counters } = testPlanResult;
|
|
5476
5504
|
const { planified } = counters;
|
|
5477
5505
|
|
|
5478
|
-
|
|
5479
|
-
|
|
5506
|
+
let executionLine = "";
|
|
5507
|
+
if (planified === 0) {
|
|
5508
|
+
executionLine += `no execution`;
|
|
5509
|
+
} else if (planified === 1) {
|
|
5510
|
+
executionLine += `1 execution: `;
|
|
5480
5511
|
} else {
|
|
5481
|
-
|
|
5512
|
+
executionLine += `${planified} executions: `;
|
|
5482
5513
|
}
|
|
5483
|
-
|
|
5514
|
+
executionLine += renderStatusRepartition(counters);
|
|
5515
|
+
lines.push(executionLine);
|
|
5484
5516
|
|
|
5485
|
-
let
|
|
5517
|
+
let durationLine = `duration: `;
|
|
5486
5518
|
const { timings } = testPlanResult;
|
|
5487
5519
|
if (logOptions.mockFluctuatingValues) {
|
|
5488
|
-
|
|
5520
|
+
durationLine += "<mock>s";
|
|
5489
5521
|
} else {
|
|
5490
|
-
|
|
5522
|
+
durationLine += humanizeDuration(timings.end, { short: true });
|
|
5491
5523
|
const namedTimings = {
|
|
5492
|
-
setup: timings.executionStart,
|
|
5493
|
-
execution: timings.executionEnd,
|
|
5494
|
-
teardown: timings.teardownEnd - timings.executionEnd,
|
|
5524
|
+
setup: humanizeTiming(timings.executionStart),
|
|
5525
|
+
execution: humanizeTiming(timings.executionEnd),
|
|
5526
|
+
teardown: humanizeTiming(timings.teardownEnd - timings.executionEnd),
|
|
5495
5527
|
...(testPlanResult.coverage
|
|
5496
|
-
? {
|
|
5528
|
+
? {
|
|
5529
|
+
coverage: humanizeTiming(
|
|
5530
|
+
timings.coverageTeardownEnd - timings.teardownEnd,
|
|
5531
|
+
),
|
|
5532
|
+
}
|
|
5497
5533
|
: {}),
|
|
5498
5534
|
};
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5535
|
+
durationLine += renderDetails(namedTimings);
|
|
5536
|
+
}
|
|
5537
|
+
lines.push(durationLine);
|
|
5538
|
+
|
|
5539
|
+
if (logOptions.cpuUsage) {
|
|
5540
|
+
const processCpuUsage = testPlanResult.cpuUsage.process;
|
|
5541
|
+
let cpuUsageLine = "cpu: ";
|
|
5542
|
+
cpuUsageLine += `${humanizeProcessCpuUsage(processCpuUsage.end)}`;
|
|
5543
|
+
cpuUsageLine += renderDetails({
|
|
5544
|
+
med: humanizeProcessCpuUsage(processCpuUsage.median),
|
|
5545
|
+
min: humanizeProcessCpuUsage(processCpuUsage.min),
|
|
5546
|
+
max: humanizeProcessCpuUsage(processCpuUsage.max),
|
|
5547
|
+
});
|
|
5548
|
+
lines.push(cpuUsageLine);
|
|
5549
|
+
}
|
|
5550
|
+
if (logOptions.memoryUsage) {
|
|
5551
|
+
const processMemoryUsage = testPlanResult.memoryUsage.process;
|
|
5552
|
+
let memoryUsageLine = "memory: ";
|
|
5553
|
+
memoryUsageLine += `${humanizeProcessMemoryUsage(processMemoryUsage.end)}`;
|
|
5554
|
+
debugger;
|
|
5555
|
+
memoryUsageLine += renderDetails({
|
|
5556
|
+
med: humanizeProcessMemoryUsage(processMemoryUsage.median),
|
|
5557
|
+
min: humanizeProcessMemoryUsage(processMemoryUsage.min),
|
|
5558
|
+
max: humanizeProcessMemoryUsage(processMemoryUsage.max),
|
|
5559
|
+
});
|
|
5560
|
+
lines.push(memoryUsageLine);
|
|
5514
5561
|
}
|
|
5515
|
-
finalSummary += `\nduration: ${durationLog}`;
|
|
5516
5562
|
|
|
5517
|
-
return `\n${renderBigSection({ title: "summary", content:
|
|
5563
|
+
return `\n${renderBigSection({ title: "summary", content: lines.join("\n") })}\n`;
|
|
5564
|
+
};
|
|
5565
|
+
|
|
5566
|
+
const humanizeTiming = (value) => {
|
|
5567
|
+
return humanizeDuration(value, { short: true });
|
|
5568
|
+
};
|
|
5569
|
+
|
|
5570
|
+
const humanizeProcessCpuUsage = (ratio) => {
|
|
5571
|
+
const percentageAsNumber = ratio * 100;
|
|
5572
|
+
const percentageAsNumberRounded = Math.round(percentageAsNumber);
|
|
5573
|
+
const percentage = `${percentageAsNumberRounded}%`;
|
|
5574
|
+
return percentage;
|
|
5575
|
+
};
|
|
5576
|
+
|
|
5577
|
+
const humanizeProcessMemoryUsage = (value) => {
|
|
5578
|
+
return humanizeMemory(value, { short: true, decimals: 0 });
|
|
5518
5579
|
};
|
|
5519
5580
|
|
|
5520
5581
|
const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
5521
5582
|
if (counters.planified === 0) {
|
|
5522
|
-
return
|
|
5583
|
+
return ``;
|
|
5523
5584
|
}
|
|
5524
5585
|
if (counters.aborted === counters.planified) {
|
|
5525
5586
|
return `all ${ANSI.color(`aborted`, COLOR_ABORTED)}`;
|
|
@@ -5606,6 +5667,29 @@ const renderSection = ({
|
|
|
5606
5667
|
return section;
|
|
5607
5668
|
};
|
|
5608
5669
|
|
|
5670
|
+
const renderDetails = (data) => {
|
|
5671
|
+
const details = [];
|
|
5672
|
+
for (const key of Object.keys(data)) {
|
|
5673
|
+
const value = data[key];
|
|
5674
|
+
let valueString = "";
|
|
5675
|
+
valueString += ANSI.color(`${key}:`, ANSI.GREY);
|
|
5676
|
+
const useNonGreyAnsiColor =
|
|
5677
|
+
typeof value === "string" && value.includes("\x1b");
|
|
5678
|
+
valueString += " ";
|
|
5679
|
+
valueString += useNonGreyAnsiColor ? value : ANSI.color(value, ANSI.GREY);
|
|
5680
|
+
details.push(valueString);
|
|
5681
|
+
}
|
|
5682
|
+
if (details.length === 0) {
|
|
5683
|
+
return "";
|
|
5684
|
+
}
|
|
5685
|
+
|
|
5686
|
+
let string = "";
|
|
5687
|
+
string += ` ${ANSI.color("(", ANSI.GREY)}`;
|
|
5688
|
+
string += details.join(ANSI.color(", ", ANSI.GREY));
|
|
5689
|
+
string += ANSI.color(")", ANSI.GREY);
|
|
5690
|
+
return string;
|
|
5691
|
+
};
|
|
5692
|
+
|
|
5609
5693
|
/*
|
|
5610
5694
|
*
|
|
5611
5695
|
*/
|
|
@@ -5627,6 +5711,9 @@ const logsDefault = {
|
|
|
5627
5711
|
level: "info",
|
|
5628
5712
|
type: "list",
|
|
5629
5713
|
animated: true,
|
|
5714
|
+
platformInfo: false,
|
|
5715
|
+
memoryUsage: false,
|
|
5716
|
+
cpuUsage: false,
|
|
5630
5717
|
fileUrl: undefined,
|
|
5631
5718
|
};
|
|
5632
5719
|
const githubCheckDefault = {
|
|
@@ -5671,8 +5758,8 @@ const coverageDefault = {
|
|
|
5671
5758
|
};
|
|
5672
5759
|
const parallelDefault = {
|
|
5673
5760
|
max: "80%", // percentage resolved against the available cpus
|
|
5674
|
-
maxCpu: "
|
|
5675
|
-
maxMemory: "
|
|
5761
|
+
maxCpu: "80%",
|
|
5762
|
+
maxMemory: "50%",
|
|
5676
5763
|
};
|
|
5677
5764
|
|
|
5678
5765
|
const executeTestPlan = async ({
|
|
@@ -5723,12 +5810,63 @@ const executeTestPlan = async ({
|
|
|
5723
5810
|
});
|
|
5724
5811
|
}
|
|
5725
5812
|
|
|
5726
|
-
const
|
|
5813
|
+
const cpuUsage = startMeasuringTotalCpuUsage();
|
|
5814
|
+
operation.addEndCallback(cpuUsage.stop);
|
|
5815
|
+
const processCpuUsageMonitoring = startMonitoringMetric(() => {
|
|
5816
|
+
return cpuUsage.thisProcess.active;
|
|
5817
|
+
});
|
|
5818
|
+
const osCpuUsageMonitoring = startMonitoringMetric(() => {
|
|
5819
|
+
return cpuUsage.overall.active;
|
|
5820
|
+
});
|
|
5821
|
+
const processMemoryUsageMonitoring = startMonitoringMetric(() => {
|
|
5822
|
+
return memoryUsage().rss;
|
|
5823
|
+
});
|
|
5824
|
+
const osMemoryUsageMonitoring = startMonitoringMetric(() => {
|
|
5825
|
+
const total = totalmem();
|
|
5826
|
+
const free = freemem();
|
|
5827
|
+
return total - free;
|
|
5828
|
+
});
|
|
5829
|
+
|
|
5830
|
+
const timingsOrigin = Date.now();
|
|
5727
5831
|
const takeTiming = () => {
|
|
5728
|
-
return Date.now() -
|
|
5832
|
+
return Date.now() - timingsOrigin;
|
|
5729
5833
|
};
|
|
5730
5834
|
const testPlanResult = {
|
|
5835
|
+
os: {
|
|
5836
|
+
name:
|
|
5837
|
+
process.platform === "darwin"
|
|
5838
|
+
? "mac"
|
|
5839
|
+
: process.platform === "win32" || process.platform === "win64"
|
|
5840
|
+
? "windows"
|
|
5841
|
+
: process.platform === "linux"
|
|
5842
|
+
? "linux"
|
|
5843
|
+
: "other",
|
|
5844
|
+
version: release(),
|
|
5845
|
+
availableCpu: countAvailableCpus(),
|
|
5846
|
+
availableMemory: totalmem(),
|
|
5847
|
+
},
|
|
5848
|
+
process: {
|
|
5849
|
+
name: "node",
|
|
5850
|
+
version: process.version.slice(1),
|
|
5851
|
+
},
|
|
5852
|
+
memoryUsage: {
|
|
5853
|
+
os: osMemoryUsageMonitoring.info,
|
|
5854
|
+
process: processMemoryUsageMonitoring.info,
|
|
5855
|
+
},
|
|
5856
|
+
cpuUsage: {
|
|
5857
|
+
os: osCpuUsageMonitoring.info,
|
|
5858
|
+
process: processCpuUsageMonitoring.info,
|
|
5859
|
+
},
|
|
5860
|
+
timings: {
|
|
5861
|
+
origin: timingsOrigin,
|
|
5862
|
+
executionStart: null,
|
|
5863
|
+
executionEnd: null,
|
|
5864
|
+
teardownEnd: null,
|
|
5865
|
+
coverageTeardownEnd: null,
|
|
5866
|
+
end: null,
|
|
5867
|
+
},
|
|
5731
5868
|
rootDirectoryUrl: String(rootDirectoryUrl),
|
|
5869
|
+
patterns: Object.keys(testPlan),
|
|
5732
5870
|
groups: {},
|
|
5733
5871
|
counters: {
|
|
5734
5872
|
planified: 0,
|
|
@@ -5745,14 +5883,6 @@ const executeTestPlan = async ({
|
|
|
5745
5883
|
},
|
|
5746
5884
|
aborted: false,
|
|
5747
5885
|
failed: false,
|
|
5748
|
-
timings: {
|
|
5749
|
-
origin: timingOrigin,
|
|
5750
|
-
executionStart: null,
|
|
5751
|
-
executionEnd: null,
|
|
5752
|
-
teardownEnd: null,
|
|
5753
|
-
coverageTeardownEnd: null,
|
|
5754
|
-
end: null,
|
|
5755
|
-
},
|
|
5756
5886
|
coverage: null,
|
|
5757
5887
|
results: {},
|
|
5758
5888
|
};
|
|
@@ -5780,9 +5910,6 @@ const executeTestPlan = async ({
|
|
|
5780
5910
|
let finalizeCoverage;
|
|
5781
5911
|
|
|
5782
5912
|
try {
|
|
5783
|
-
const cpuUsage = startMeasuringCpuUsage();
|
|
5784
|
-
operation.addEndCallback(cpuUsage.stop);
|
|
5785
|
-
|
|
5786
5913
|
let logger;
|
|
5787
5914
|
const runtimeInfo = {
|
|
5788
5915
|
someNeedsServer: false,
|
|
@@ -5813,6 +5940,10 @@ const executeTestPlan = async ({
|
|
|
5813
5940
|
|
|
5814
5941
|
if (logs.type === "list" && logger.levels.info) {
|
|
5815
5942
|
const listReporterOptions = {
|
|
5943
|
+
mockFluctuatingValues: logs.mockFluctuatingValues,
|
|
5944
|
+
platformInfo: logs.platformInfo,
|
|
5945
|
+
memoryUsage: logs.memoryUsage,
|
|
5946
|
+
cpuUsage: logs.cpuUsage,
|
|
5816
5947
|
animated: logger.levels.debug ? false : logs.animated,
|
|
5817
5948
|
fileUrl:
|
|
5818
5949
|
logs.fileUrl === undefined
|
|
@@ -5871,8 +6002,8 @@ const executeTestPlan = async ({
|
|
|
5871
6002
|
const max = parallel.max;
|
|
5872
6003
|
if (typeof max === "string") {
|
|
5873
6004
|
const maxAsRatio = assertPercentageAndConvertToRatio(max);
|
|
5874
|
-
|
|
5875
|
-
|
|
6005
|
+
parallel.max =
|
|
6006
|
+
Math.round(maxAsRatio * testPlanResult.os.availableCpu) || 1;
|
|
5876
6007
|
} else if (typeof max === "number") {
|
|
5877
6008
|
if (max < 1) {
|
|
5878
6009
|
parallel.max = 1;
|
|
@@ -5886,8 +6017,9 @@ const executeTestPlan = async ({
|
|
|
5886
6017
|
const maxMemory = parallel.maxMemory;
|
|
5887
6018
|
if (typeof maxMemory === "string") {
|
|
5888
6019
|
const maxMemoryAsRatio = assertPercentageAndConvertToRatio(maxMemory);
|
|
5889
|
-
|
|
5890
|
-
|
|
6020
|
+
parallel.maxMemory = Math.round(
|
|
6021
|
+
maxMemoryAsRatio * testPlanResult.os.availableMemory,
|
|
6022
|
+
);
|
|
5891
6023
|
} else if (typeof maxMemory !== "number") {
|
|
5892
6024
|
throw new TypeError(
|
|
5893
6025
|
`parallel.maxMemory must be a number or a percentage, got ${maxMemory}`,
|
|
@@ -6425,18 +6557,22 @@ To fix this warning:
|
|
|
6425
6557
|
// if nothing is executing these limitations don't apply
|
|
6426
6558
|
executionExecutingSet.size > 0
|
|
6427
6559
|
) {
|
|
6428
|
-
|
|
6429
|
-
const totalMemory = totalmem();
|
|
6430
|
-
const usedMemory = totalMemory - freeMemory;
|
|
6431
|
-
if (usedMemory > parallel.maxMemory) {
|
|
6560
|
+
if (processMemoryUsageMonitoring.measure() > parallel.maxMemory) {
|
|
6432
6561
|
// retry after Xms in case memory usage decreases
|
|
6433
|
-
const promise =
|
|
6562
|
+
const promise = (async () => {
|
|
6563
|
+
await operation.wait(200);
|
|
6564
|
+
await startAsMuchAsPossible();
|
|
6565
|
+
})();
|
|
6434
6566
|
promises.push(promise);
|
|
6435
6567
|
break;
|
|
6436
6568
|
}
|
|
6437
|
-
|
|
6569
|
+
|
|
6570
|
+
if (processCpuUsageMonitoring.measure() > parallel.maxCpu) {
|
|
6438
6571
|
// retry after Xms in case cpu usage decreases
|
|
6439
|
-
const promise =
|
|
6572
|
+
const promise = (async () => {
|
|
6573
|
+
await operation.wait(200);
|
|
6574
|
+
await startAsMuchAsPossible();
|
|
6575
|
+
})();
|
|
6440
6576
|
promises.push(promise);
|
|
6441
6577
|
break;
|
|
6442
6578
|
}
|
|
@@ -6460,7 +6596,6 @@ To fix this warning:
|
|
|
6460
6596
|
if (promises.length) {
|
|
6461
6597
|
await Promise.all(promises);
|
|
6462
6598
|
promises.length = 0;
|
|
6463
|
-
await startAsMuchAsPossible();
|
|
6464
6599
|
}
|
|
6465
6600
|
};
|
|
6466
6601
|
|
|
@@ -6539,6 +6674,11 @@ To fix this warning:
|
|
|
6539
6674
|
timings.coverageTeardownEnd = takeTiming();
|
|
6540
6675
|
timings.end = takeTiming();
|
|
6541
6676
|
|
|
6677
|
+
osMemoryUsageMonitoring.end();
|
|
6678
|
+
processMemoryUsageMonitoring.end();
|
|
6679
|
+
osCpuUsageMonitoring.end();
|
|
6680
|
+
processCpuUsageMonitoring.end();
|
|
6681
|
+
|
|
6542
6682
|
afterEachCallbackSet.clear();
|
|
6543
6683
|
afterEachInOrderCallbackSet.clear();
|
|
6544
6684
|
for (const afterAllCallback of afterAllCallbackSet) {
|
|
@@ -6551,6 +6691,51 @@ To fix this warning:
|
|
|
6551
6691
|
return testPlanResult;
|
|
6552
6692
|
};
|
|
6553
6693
|
|
|
6694
|
+
const startMonitoringMetric = (measure) => {
|
|
6695
|
+
const metrics = [];
|
|
6696
|
+
const takeMeasure = () => {
|
|
6697
|
+
const value = measure();
|
|
6698
|
+
metrics.push(value);
|
|
6699
|
+
return value;
|
|
6700
|
+
};
|
|
6701
|
+
|
|
6702
|
+
const info = {
|
|
6703
|
+
start: takeMeasure(),
|
|
6704
|
+
min: null,
|
|
6705
|
+
max: null,
|
|
6706
|
+
median: null,
|
|
6707
|
+
end: null,
|
|
6708
|
+
};
|
|
6709
|
+
return {
|
|
6710
|
+
info,
|
|
6711
|
+
measure: takeMeasure,
|
|
6712
|
+
end: () => {
|
|
6713
|
+
info.end = takeMeasure();
|
|
6714
|
+
metrics.sort((a, b) => a - b);
|
|
6715
|
+
info.min = metrics[0];
|
|
6716
|
+
info.max = metrics[metrics.length - 1];
|
|
6717
|
+
info.median = medianFromSortedArray(metrics);
|
|
6718
|
+
metrics.length = 0;
|
|
6719
|
+
},
|
|
6720
|
+
};
|
|
6721
|
+
};
|
|
6722
|
+
|
|
6723
|
+
const medianFromSortedArray = (array) => {
|
|
6724
|
+
const length = array.length;
|
|
6725
|
+
const isOdd = length % 2 === 1;
|
|
6726
|
+
if (isOdd) {
|
|
6727
|
+
const medianNumberIndex = (length - 1) / 2;
|
|
6728
|
+
const medianNumber = array[medianNumberIndex];
|
|
6729
|
+
return medianNumber;
|
|
6730
|
+
}
|
|
6731
|
+
const rightMiddleNumberIndex = length / 2;
|
|
6732
|
+
const leftMiddleNumberIndex = rightMiddleNumberIndex - 1;
|
|
6733
|
+
const leftMiddleNumber = array[leftMiddleNumberIndex];
|
|
6734
|
+
const rightMiddleNumber = array[rightMiddleNumberIndex];
|
|
6735
|
+
const medianNumber = (leftMiddleNumber + rightMiddleNumber) / 2;
|
|
6736
|
+
return medianNumber;
|
|
6737
|
+
};
|
|
6738
|
+
|
|
6554
6739
|
const countAvailableCpus = () => {
|
|
6555
6740
|
if (typeof availableParallelism === "function") {
|
|
6556
6741
|
return availableParallelism();
|
package/package.json
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
*
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
release,
|
|
7
|
+
cpus,
|
|
8
|
+
availableParallelism,
|
|
9
|
+
totalmem,
|
|
10
|
+
freemem,
|
|
11
|
+
} from "node:os";
|
|
12
|
+
import { memoryUsage } from "node:process";
|
|
6
13
|
import { existsSync } from "node:fs";
|
|
7
14
|
import { takeCoverage } from "node:v8";
|
|
8
15
|
import stripAnsi from "strip-ansi";
|
|
@@ -19,7 +26,7 @@ import {
|
|
|
19
26
|
readGitHubWorkflowEnv,
|
|
20
27
|
} from "@jsenv/github-check-run";
|
|
21
28
|
|
|
22
|
-
import {
|
|
29
|
+
import { startMeasuringTotalCpuUsage } from "../helpers/cpu_usage.js";
|
|
23
30
|
import { createCallOrderer } from "../helpers/call_orderer.js";
|
|
24
31
|
import { generateCoverage } from "../coverage/generate_coverage.js";
|
|
25
32
|
import { assertAndNormalizeWebServer } from "./web_server_param.js";
|
|
@@ -43,6 +50,9 @@ const logsDefault = {
|
|
|
43
50
|
level: "info",
|
|
44
51
|
type: "list",
|
|
45
52
|
animated: true,
|
|
53
|
+
platformInfo: false,
|
|
54
|
+
memoryUsage: false,
|
|
55
|
+
cpuUsage: false,
|
|
46
56
|
fileUrl: undefined,
|
|
47
57
|
};
|
|
48
58
|
const githubCheckDefault = {
|
|
@@ -87,8 +97,8 @@ const coverageDefault = {
|
|
|
87
97
|
};
|
|
88
98
|
const parallelDefault = {
|
|
89
99
|
max: "80%", // percentage resolved against the available cpus
|
|
90
|
-
maxCpu: "
|
|
91
|
-
maxMemory: "
|
|
100
|
+
maxCpu: "80%",
|
|
101
|
+
maxMemory: "50%",
|
|
92
102
|
};
|
|
93
103
|
|
|
94
104
|
export const executeTestPlan = async ({
|
|
@@ -139,12 +149,63 @@ export const executeTestPlan = async ({
|
|
|
139
149
|
});
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
const
|
|
152
|
+
const cpuUsage = startMeasuringTotalCpuUsage();
|
|
153
|
+
operation.addEndCallback(cpuUsage.stop);
|
|
154
|
+
const processCpuUsageMonitoring = startMonitoringMetric(() => {
|
|
155
|
+
return cpuUsage.thisProcess.active;
|
|
156
|
+
});
|
|
157
|
+
const osCpuUsageMonitoring = startMonitoringMetric(() => {
|
|
158
|
+
return cpuUsage.overall.active;
|
|
159
|
+
});
|
|
160
|
+
const processMemoryUsageMonitoring = startMonitoringMetric(() => {
|
|
161
|
+
return memoryUsage().rss;
|
|
162
|
+
});
|
|
163
|
+
const osMemoryUsageMonitoring = startMonitoringMetric(() => {
|
|
164
|
+
const total = totalmem();
|
|
165
|
+
const free = freemem();
|
|
166
|
+
return total - free;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const timingsOrigin = Date.now();
|
|
143
170
|
const takeTiming = () => {
|
|
144
|
-
return Date.now() -
|
|
171
|
+
return Date.now() - timingsOrigin;
|
|
145
172
|
};
|
|
146
173
|
const testPlanResult = {
|
|
174
|
+
os: {
|
|
175
|
+
name:
|
|
176
|
+
process.platform === "darwin"
|
|
177
|
+
? "mac"
|
|
178
|
+
: process.platform === "win32" || process.platform === "win64"
|
|
179
|
+
? "windows"
|
|
180
|
+
: process.platform === "linux"
|
|
181
|
+
? "linux"
|
|
182
|
+
: "other",
|
|
183
|
+
version: release(),
|
|
184
|
+
availableCpu: countAvailableCpus(),
|
|
185
|
+
availableMemory: totalmem(),
|
|
186
|
+
},
|
|
187
|
+
process: {
|
|
188
|
+
name: "node",
|
|
189
|
+
version: process.version.slice(1),
|
|
190
|
+
},
|
|
191
|
+
memoryUsage: {
|
|
192
|
+
os: osMemoryUsageMonitoring.info,
|
|
193
|
+
process: processMemoryUsageMonitoring.info,
|
|
194
|
+
},
|
|
195
|
+
cpuUsage: {
|
|
196
|
+
os: osCpuUsageMonitoring.info,
|
|
197
|
+
process: processCpuUsageMonitoring.info,
|
|
198
|
+
},
|
|
199
|
+
timings: {
|
|
200
|
+
origin: timingsOrigin,
|
|
201
|
+
executionStart: null,
|
|
202
|
+
executionEnd: null,
|
|
203
|
+
teardownEnd: null,
|
|
204
|
+
coverageTeardownEnd: null,
|
|
205
|
+
end: null,
|
|
206
|
+
},
|
|
147
207
|
rootDirectoryUrl: String(rootDirectoryUrl),
|
|
208
|
+
patterns: Object.keys(testPlan),
|
|
148
209
|
groups: {},
|
|
149
210
|
counters: {
|
|
150
211
|
planified: 0,
|
|
@@ -161,14 +222,6 @@ export const executeTestPlan = async ({
|
|
|
161
222
|
},
|
|
162
223
|
aborted: false,
|
|
163
224
|
failed: false,
|
|
164
|
-
timings: {
|
|
165
|
-
origin: timingOrigin,
|
|
166
|
-
executionStart: null,
|
|
167
|
-
executionEnd: null,
|
|
168
|
-
teardownEnd: null,
|
|
169
|
-
coverageTeardownEnd: null,
|
|
170
|
-
end: null,
|
|
171
|
-
},
|
|
172
225
|
coverage: null,
|
|
173
226
|
results: {},
|
|
174
227
|
};
|
|
@@ -196,9 +249,6 @@ export const executeTestPlan = async ({
|
|
|
196
249
|
let finalizeCoverage;
|
|
197
250
|
|
|
198
251
|
try {
|
|
199
|
-
const cpuUsage = startMeasuringCpuUsage();
|
|
200
|
-
operation.addEndCallback(cpuUsage.stop);
|
|
201
|
-
|
|
202
252
|
let logger;
|
|
203
253
|
const runtimeInfo = {
|
|
204
254
|
someNeedsServer: false,
|
|
@@ -229,6 +279,10 @@ export const executeTestPlan = async ({
|
|
|
229
279
|
|
|
230
280
|
if (logs.type === "list" && logger.levels.info) {
|
|
231
281
|
const listReporterOptions = {
|
|
282
|
+
mockFluctuatingValues: logs.mockFluctuatingValues,
|
|
283
|
+
platformInfo: logs.platformInfo,
|
|
284
|
+
memoryUsage: logs.memoryUsage,
|
|
285
|
+
cpuUsage: logs.cpuUsage,
|
|
232
286
|
animated: logger.levels.debug ? false : logs.animated,
|
|
233
287
|
fileUrl:
|
|
234
288
|
logs.fileUrl === undefined
|
|
@@ -287,8 +341,8 @@ export const executeTestPlan = async ({
|
|
|
287
341
|
const max = parallel.max;
|
|
288
342
|
if (typeof max === "string") {
|
|
289
343
|
const maxAsRatio = assertPercentageAndConvertToRatio(max);
|
|
290
|
-
|
|
291
|
-
|
|
344
|
+
parallel.max =
|
|
345
|
+
Math.round(maxAsRatio * testPlanResult.os.availableCpu) || 1;
|
|
292
346
|
} else if (typeof max === "number") {
|
|
293
347
|
if (max < 1) {
|
|
294
348
|
parallel.max = 1;
|
|
@@ -302,8 +356,9 @@ export const executeTestPlan = async ({
|
|
|
302
356
|
const maxMemory = parallel.maxMemory;
|
|
303
357
|
if (typeof maxMemory === "string") {
|
|
304
358
|
const maxMemoryAsRatio = assertPercentageAndConvertToRatio(maxMemory);
|
|
305
|
-
|
|
306
|
-
|
|
359
|
+
parallel.maxMemory = Math.round(
|
|
360
|
+
maxMemoryAsRatio * testPlanResult.os.availableMemory,
|
|
361
|
+
);
|
|
307
362
|
} else if (typeof maxMemory !== "number") {
|
|
308
363
|
throw new TypeError(
|
|
309
364
|
`parallel.maxMemory must be a number or a percentage, got ${maxMemory}`,
|
|
@@ -841,18 +896,22 @@ To fix this warning:
|
|
|
841
896
|
// if nothing is executing these limitations don't apply
|
|
842
897
|
executionExecutingSet.size > 0
|
|
843
898
|
) {
|
|
844
|
-
|
|
845
|
-
const totalMemory = totalmem();
|
|
846
|
-
const usedMemory = totalMemory - freeMemory;
|
|
847
|
-
if (usedMemory > parallel.maxMemory) {
|
|
899
|
+
if (processMemoryUsageMonitoring.measure() > parallel.maxMemory) {
|
|
848
900
|
// retry after Xms in case memory usage decreases
|
|
849
|
-
const promise =
|
|
901
|
+
const promise = (async () => {
|
|
902
|
+
await operation.wait(200);
|
|
903
|
+
await startAsMuchAsPossible();
|
|
904
|
+
})();
|
|
850
905
|
promises.push(promise);
|
|
851
906
|
break;
|
|
852
907
|
}
|
|
853
|
-
|
|
908
|
+
|
|
909
|
+
if (processCpuUsageMonitoring.measure() > parallel.maxCpu) {
|
|
854
910
|
// retry after Xms in case cpu usage decreases
|
|
855
|
-
const promise =
|
|
911
|
+
const promise = (async () => {
|
|
912
|
+
await operation.wait(200);
|
|
913
|
+
await startAsMuchAsPossible();
|
|
914
|
+
})();
|
|
856
915
|
promises.push(promise);
|
|
857
916
|
break;
|
|
858
917
|
}
|
|
@@ -876,7 +935,6 @@ To fix this warning:
|
|
|
876
935
|
if (promises.length) {
|
|
877
936
|
await Promise.all(promises);
|
|
878
937
|
promises.length = 0;
|
|
879
|
-
await startAsMuchAsPossible();
|
|
880
938
|
}
|
|
881
939
|
};
|
|
882
940
|
|
|
@@ -956,6 +1014,11 @@ To fix this warning:
|
|
|
956
1014
|
timings.coverageTeardownEnd = takeTiming();
|
|
957
1015
|
timings.end = takeTiming();
|
|
958
1016
|
|
|
1017
|
+
osMemoryUsageMonitoring.end();
|
|
1018
|
+
processMemoryUsageMonitoring.end();
|
|
1019
|
+
osCpuUsageMonitoring.end();
|
|
1020
|
+
processCpuUsageMonitoring.end();
|
|
1021
|
+
|
|
959
1022
|
afterEachCallbackSet.clear();
|
|
960
1023
|
afterEachInOrderCallbackSet.clear();
|
|
961
1024
|
for (const afterAllCallback of afterAllCallbackSet) {
|
|
@@ -968,6 +1031,51 @@ To fix this warning:
|
|
|
968
1031
|
return testPlanResult;
|
|
969
1032
|
};
|
|
970
1033
|
|
|
1034
|
+
const startMonitoringMetric = (measure) => {
|
|
1035
|
+
const metrics = [];
|
|
1036
|
+
const takeMeasure = () => {
|
|
1037
|
+
const value = measure();
|
|
1038
|
+
metrics.push(value);
|
|
1039
|
+
return value;
|
|
1040
|
+
};
|
|
1041
|
+
|
|
1042
|
+
const info = {
|
|
1043
|
+
start: takeMeasure(),
|
|
1044
|
+
min: null,
|
|
1045
|
+
max: null,
|
|
1046
|
+
median: null,
|
|
1047
|
+
end: null,
|
|
1048
|
+
};
|
|
1049
|
+
return {
|
|
1050
|
+
info,
|
|
1051
|
+
measure: takeMeasure,
|
|
1052
|
+
end: () => {
|
|
1053
|
+
info.end = takeMeasure();
|
|
1054
|
+
metrics.sort((a, b) => a - b);
|
|
1055
|
+
info.min = metrics[0];
|
|
1056
|
+
info.max = metrics[metrics.length - 1];
|
|
1057
|
+
info.median = medianFromSortedArray(metrics);
|
|
1058
|
+
metrics.length = 0;
|
|
1059
|
+
},
|
|
1060
|
+
};
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
const medianFromSortedArray = (array) => {
|
|
1064
|
+
const length = array.length;
|
|
1065
|
+
const isOdd = length % 2 === 1;
|
|
1066
|
+
if (isOdd) {
|
|
1067
|
+
const medianNumberIndex = (length - 1) / 2;
|
|
1068
|
+
const medianNumber = array[medianNumberIndex];
|
|
1069
|
+
return medianNumber;
|
|
1070
|
+
}
|
|
1071
|
+
const rightMiddleNumberIndex = length / 2;
|
|
1072
|
+
const leftMiddleNumberIndex = rightMiddleNumberIndex - 1;
|
|
1073
|
+
const leftMiddleNumber = array[leftMiddleNumberIndex];
|
|
1074
|
+
const rightMiddleNumber = array[rightMiddleNumberIndex];
|
|
1075
|
+
const medianNumber = (leftMiddleNumber + rightMiddleNumber) / 2;
|
|
1076
|
+
return medianNumber;
|
|
1077
|
+
};
|
|
1078
|
+
|
|
971
1079
|
const countAvailableCpus = () => {
|
|
972
1080
|
if (typeof availableParallelism === "function") {
|
|
973
1081
|
return availableParallelism();
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { memoryUsage } from "node:process";
|
|
1
|
+
import { memoryUsage as processMemoryUsage } from "node:process";
|
|
2
2
|
import stripAnsi from "strip-ansi";
|
|
3
3
|
import { writeFileSync } from "@jsenv/filesystem";
|
|
4
4
|
import {
|
|
5
5
|
createDynamicLog,
|
|
6
6
|
humanizeDuration,
|
|
7
|
-
|
|
7
|
+
humanizeMemory,
|
|
8
8
|
ANSI,
|
|
9
9
|
UNICODE,
|
|
10
10
|
} from "@jsenv/humanize";
|
|
11
|
+
import { urlToFileSystemPath } from "@jsenv/urls";
|
|
11
12
|
|
|
12
13
|
import { formatErrorForTerminal } from "../format_error_for_terminal.js";
|
|
13
14
|
|
|
@@ -36,7 +37,9 @@ import { formatErrorForTerminal } from "../format_error_for_terminal.js";
|
|
|
36
37
|
export const reporterList = ({
|
|
37
38
|
animated = true,
|
|
38
39
|
mockFluctuatingValues, // used for snapshot testing logs
|
|
39
|
-
|
|
40
|
+
platformInfo,
|
|
41
|
+
memoryUsage,
|
|
42
|
+
cpuUsage,
|
|
40
43
|
spy = () => {
|
|
41
44
|
return {
|
|
42
45
|
write: (log) => {
|
|
@@ -57,7 +60,9 @@ export const reporterList = ({
|
|
|
57
60
|
process.exitCode !== 1;
|
|
58
61
|
|
|
59
62
|
const logOptions = {
|
|
60
|
-
|
|
63
|
+
platformInfo,
|
|
64
|
+
memoryUsage,
|
|
65
|
+
cpuUsage,
|
|
61
66
|
mockFluctuatingValues,
|
|
62
67
|
group: false,
|
|
63
68
|
intermediateSummary: !animatedLogEnabled,
|
|
@@ -117,8 +122,8 @@ export const reporterList = ({
|
|
|
117
122
|
rounded: false,
|
|
118
123
|
});
|
|
119
124
|
infos.push(ANSI.color(duration, ANSI.GREY));
|
|
120
|
-
const memoryHeapUsed =
|
|
121
|
-
const memoryHeapUsedFormatted =
|
|
125
|
+
const memoryHeapUsed = processMemoryUsage().heapUsed;
|
|
126
|
+
const memoryHeapUsedFormatted = humanizeMemory(memoryHeapUsed, {
|
|
122
127
|
short: true,
|
|
123
128
|
decimals: 0,
|
|
124
129
|
});
|
|
@@ -169,8 +174,10 @@ export const reporterList = ({
|
|
|
169
174
|
reporters.push(
|
|
170
175
|
reporterList({
|
|
171
176
|
animated: false,
|
|
177
|
+
platformInfo,
|
|
178
|
+
memoryUsage,
|
|
179
|
+
cpuUsage,
|
|
172
180
|
mockFluctuatingValues, // used for snapshot testing logs
|
|
173
|
-
showMemoryUsage,
|
|
174
181
|
spy: () => {
|
|
175
182
|
let rawOutput = "";
|
|
176
183
|
|
|
@@ -190,58 +197,59 @@ export const reporterList = ({
|
|
|
190
197
|
};
|
|
191
198
|
|
|
192
199
|
const renderIntro = (testPlanResult, logOptions) => {
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
const lines = [];
|
|
201
|
+
if (logOptions.platformInfo) {
|
|
202
|
+
os_line: {
|
|
203
|
+
let osLine = `os: `;
|
|
204
|
+
if (logOptions.mockFluctuatingValues) {
|
|
205
|
+
osLine += `os@<mock>`;
|
|
206
|
+
} else {
|
|
207
|
+
osLine += `${testPlanResult.os.name}@${testPlanResult.os.version}`;
|
|
208
|
+
}
|
|
209
|
+
osLine += renderDetails({
|
|
210
|
+
cpu: logOptions.mockFluctuatingValues
|
|
211
|
+
? "<mock>"
|
|
212
|
+
: testPlanResult.os.availableCpu,
|
|
213
|
+
memory: logOptions.mockFluctuatingValues
|
|
214
|
+
? "<mock>GB"
|
|
215
|
+
: humanizeMemory(testPlanResult.os.availableMemory, {
|
|
216
|
+
short: true,
|
|
217
|
+
decimals: 0,
|
|
218
|
+
}),
|
|
219
|
+
});
|
|
220
|
+
lines.push(osLine);
|
|
221
|
+
}
|
|
222
|
+
process_line: {
|
|
223
|
+
const process = logOptions.mockFluctuatingValues
|
|
224
|
+
? `node@mock`
|
|
225
|
+
: `${testPlanResult.process.name}@${testPlanResult.process.version}`;
|
|
226
|
+
let processLine = `process: ${process}`;
|
|
227
|
+
lines.push(processLine);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
197
230
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
})}\n\n`;
|
|
211
|
-
}
|
|
212
|
-
if (groupNames.length === 1) {
|
|
213
|
-
const groupName = groupNames[0];
|
|
214
|
-
const groupInfo = groups[groupName];
|
|
215
|
-
return `${renderBigSection({
|
|
216
|
-
title: `${planified} executions to run`,
|
|
217
|
-
content: `${groupName} (${getGroupRenderedName(groupInfo, logOptions)})`,
|
|
218
|
-
})}\n\n`;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let introLines = [];
|
|
222
|
-
for (const groupName of groupNames) {
|
|
223
|
-
const groupInfo = groups[groupName];
|
|
224
|
-
introLines.push(
|
|
225
|
-
`${groupInfo.count} with ${groupName} (${getGroupRenderedName(
|
|
226
|
-
groupInfo,
|
|
227
|
-
logOptions,
|
|
228
|
-
)})`,
|
|
229
|
-
);
|
|
231
|
+
const directory = logOptions.mockFluctuatingValues
|
|
232
|
+
? "/mock/"
|
|
233
|
+
: urlToFileSystemPath(testPlanResult.rootDirectoryUrl);
|
|
234
|
+
const numberOfFiles = Object.keys(testPlanResult.results).length;
|
|
235
|
+
let fileFoundLine = "";
|
|
236
|
+
if (numberOfFiles === 0) {
|
|
237
|
+
fileFoundLine += `no file matching "testPlan" in ${directory}:
|
|
238
|
+
${testPlanResult.patterns.join("\n")}`;
|
|
239
|
+
} else if (numberOfFiles === 1) {
|
|
240
|
+
fileFoundLine += `1 file matching "testPlan" in ${directory}`;
|
|
241
|
+
} else {
|
|
242
|
+
fileFoundLine += `${numberOfFiles} files matching "testPlan" in ${directory}`;
|
|
230
243
|
}
|
|
244
|
+
|
|
245
|
+
lines.push(fileFoundLine);
|
|
246
|
+
|
|
231
247
|
return `${renderBigSection({
|
|
232
|
-
title:
|
|
233
|
-
content:
|
|
248
|
+
title: "execution start",
|
|
249
|
+
content: lines.join("\n"),
|
|
234
250
|
})}\n\n`;
|
|
235
251
|
};
|
|
236
252
|
|
|
237
|
-
const getGroupRenderedName = (groupInfo, logOptions) => {
|
|
238
|
-
let { runtimeName, runtimeVersion } = groupInfo;
|
|
239
|
-
if (logOptions.mockFluctuatingValues && groupInfo.runtimeType === "node") {
|
|
240
|
-
runtimeVersion = "<mock>";
|
|
241
|
-
}
|
|
242
|
-
return `${runtimeName}@${runtimeVersion}`;
|
|
243
|
-
};
|
|
244
|
-
|
|
245
253
|
const renderExecutionLog = (execution, logOptions) => {
|
|
246
254
|
let log = "";
|
|
247
255
|
// label
|
|
@@ -296,10 +304,10 @@ const renderExecutionLabel = (execution, logOptions) => {
|
|
|
296
304
|
: humanizeDuration(duration, { short: true });
|
|
297
305
|
infos.push(ANSI.color(durationFormatted, ANSI.GREY));
|
|
298
306
|
}
|
|
299
|
-
if (logOptions.
|
|
307
|
+
if (logOptions.memoryUsage && typeof memoryUsage === "number") {
|
|
300
308
|
const memoryUsageFormatted = logOptions.mockFluctuatingValues
|
|
301
309
|
? `<mock>MB`
|
|
302
|
-
:
|
|
310
|
+
: humanizeMemory(memoryUsage, { short: true });
|
|
303
311
|
infos.push(ANSI.color(memoryUsageFormatted, ANSI.GREY));
|
|
304
312
|
}
|
|
305
313
|
if (infos.length) {
|
|
@@ -561,55 +569,88 @@ const renderErrors = (execution, logOptions) => {
|
|
|
561
569
|
};
|
|
562
570
|
|
|
563
571
|
export const renderOutro = (testPlanResult, logOptions = {}) => {
|
|
564
|
-
|
|
572
|
+
const lines = [];
|
|
565
573
|
const { counters } = testPlanResult;
|
|
566
574
|
const { planified } = counters;
|
|
567
575
|
|
|
568
|
-
|
|
569
|
-
|
|
576
|
+
let executionLine = "";
|
|
577
|
+
if (planified === 0) {
|
|
578
|
+
executionLine += `no execution`;
|
|
579
|
+
} else if (planified === 1) {
|
|
580
|
+
executionLine += `1 execution: `;
|
|
570
581
|
} else {
|
|
571
|
-
|
|
582
|
+
executionLine += `${planified} executions: `;
|
|
572
583
|
}
|
|
573
|
-
|
|
584
|
+
executionLine += renderStatusRepartition(counters);
|
|
585
|
+
lines.push(executionLine);
|
|
574
586
|
|
|
575
|
-
let
|
|
587
|
+
let durationLine = `duration: `;
|
|
576
588
|
const { timings } = testPlanResult;
|
|
577
589
|
if (logOptions.mockFluctuatingValues) {
|
|
578
|
-
|
|
590
|
+
durationLine += "<mock>s";
|
|
579
591
|
} else {
|
|
580
|
-
|
|
592
|
+
durationLine += humanizeDuration(timings.end, { short: true });
|
|
581
593
|
const namedTimings = {
|
|
582
|
-
setup: timings.executionStart,
|
|
583
|
-
execution: timings.executionEnd,
|
|
584
|
-
teardown: timings.teardownEnd - timings.executionEnd,
|
|
594
|
+
setup: humanizeTiming(timings.executionStart),
|
|
595
|
+
execution: humanizeTiming(timings.executionEnd),
|
|
596
|
+
teardown: humanizeTiming(timings.teardownEnd - timings.executionEnd),
|
|
585
597
|
...(testPlanResult.coverage
|
|
586
|
-
? {
|
|
598
|
+
? {
|
|
599
|
+
coverage: humanizeTiming(
|
|
600
|
+
timings.coverageTeardownEnd - timings.teardownEnd,
|
|
601
|
+
),
|
|
602
|
+
}
|
|
587
603
|
: {}),
|
|
588
604
|
};
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
605
|
+
durationLine += renderDetails(namedTimings);
|
|
606
|
+
}
|
|
607
|
+
lines.push(durationLine);
|
|
608
|
+
|
|
609
|
+
if (logOptions.cpuUsage) {
|
|
610
|
+
const processCpuUsage = testPlanResult.cpuUsage.process;
|
|
611
|
+
let cpuUsageLine = "cpu: ";
|
|
612
|
+
cpuUsageLine += `${humanizeProcessCpuUsage(processCpuUsage.end)}`;
|
|
613
|
+
cpuUsageLine += renderDetails({
|
|
614
|
+
med: humanizeProcessCpuUsage(processCpuUsage.median),
|
|
615
|
+
min: humanizeProcessCpuUsage(processCpuUsage.min),
|
|
616
|
+
max: humanizeProcessCpuUsage(processCpuUsage.max),
|
|
617
|
+
});
|
|
618
|
+
lines.push(cpuUsageLine);
|
|
619
|
+
}
|
|
620
|
+
if (logOptions.memoryUsage) {
|
|
621
|
+
const processMemoryUsage = testPlanResult.memoryUsage.process;
|
|
622
|
+
let memoryUsageLine = "memory: ";
|
|
623
|
+
memoryUsageLine += `${humanizeProcessMemoryUsage(processMemoryUsage.end)}`;
|
|
624
|
+
debugger;
|
|
625
|
+
memoryUsageLine += renderDetails({
|
|
626
|
+
med: humanizeProcessMemoryUsage(processMemoryUsage.median),
|
|
627
|
+
min: humanizeProcessMemoryUsage(processMemoryUsage.min),
|
|
628
|
+
max: humanizeProcessMemoryUsage(processMemoryUsage.max),
|
|
629
|
+
});
|
|
630
|
+
lines.push(memoryUsageLine);
|
|
604
631
|
}
|
|
605
|
-
finalSummary += `\nduration: ${durationLog}`;
|
|
606
632
|
|
|
607
|
-
return `\n${renderBigSection({ title: "summary", content:
|
|
633
|
+
return `\n${renderBigSection({ title: "summary", content: lines.join("\n") })}\n`;
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
const humanizeTiming = (value) => {
|
|
637
|
+
return humanizeDuration(value, { short: true });
|
|
638
|
+
};
|
|
639
|
+
|
|
640
|
+
const humanizeProcessCpuUsage = (ratio) => {
|
|
641
|
+
const percentageAsNumber = ratio * 100;
|
|
642
|
+
const percentageAsNumberRounded = Math.round(percentageAsNumber);
|
|
643
|
+
const percentage = `${percentageAsNumberRounded}%`;
|
|
644
|
+
return percentage;
|
|
645
|
+
};
|
|
646
|
+
|
|
647
|
+
const humanizeProcessMemoryUsage = (value) => {
|
|
648
|
+
return humanizeMemory(value, { short: true, decimals: 0 });
|
|
608
649
|
};
|
|
609
650
|
|
|
610
651
|
const renderStatusRepartition = (counters, { showProgression } = {}) => {
|
|
611
652
|
if (counters.planified === 0) {
|
|
612
|
-
return
|
|
653
|
+
return ``;
|
|
613
654
|
}
|
|
614
655
|
if (counters.aborted === counters.planified) {
|
|
615
656
|
return `all ${ANSI.color(`aborted`, COLOR_ABORTED)}`;
|
|
@@ -695,3 +736,26 @@ const renderSection = ({
|
|
|
695
736
|
section += bottomDashes;
|
|
696
737
|
return section;
|
|
697
738
|
};
|
|
739
|
+
|
|
740
|
+
const renderDetails = (data) => {
|
|
741
|
+
const details = [];
|
|
742
|
+
for (const key of Object.keys(data)) {
|
|
743
|
+
const value = data[key];
|
|
744
|
+
let valueString = "";
|
|
745
|
+
valueString += ANSI.color(`${key}:`, ANSI.GREY);
|
|
746
|
+
const useNonGreyAnsiColor =
|
|
747
|
+
typeof value === "string" && value.includes("\x1b");
|
|
748
|
+
valueString += " ";
|
|
749
|
+
valueString += useNonGreyAnsiColor ? value : ANSI.color(value, ANSI.GREY);
|
|
750
|
+
details.push(valueString);
|
|
751
|
+
}
|
|
752
|
+
if (details.length === 0) {
|
|
753
|
+
return "";
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
let string = "";
|
|
757
|
+
string += ` ${ANSI.color("(", ANSI.GREY)}`;
|
|
758
|
+
string += details.join(ANSI.color(", ", ANSI.GREY));
|
|
759
|
+
string += ANSI.color(")", ANSI.GREY);
|
|
760
|
+
return string;
|
|
761
|
+
};
|
package/src/helpers/cpu_usage.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// https://gist.github.com/GaetanoPiazzolla/c40e1ebb9f709d091208e89baf9f4e00
|
|
2
2
|
|
|
3
3
|
import { cpus } from "node:os";
|
|
4
|
+
import { cpuUsage } from "node:process";
|
|
4
5
|
|
|
5
|
-
export const
|
|
6
|
+
export const startMeasuringTotalCpuUsage = () => {
|
|
6
7
|
let previousCpuArray = cpus();
|
|
7
8
|
let previousMs = Date.now();
|
|
9
|
+
let previousCpuUsage = cpuUsage();
|
|
8
10
|
|
|
9
11
|
const overall = {
|
|
10
12
|
inactive: 100,
|
|
@@ -12,6 +14,12 @@ export const startMeasuringCpuUsage = () => {
|
|
|
12
14
|
system: 0,
|
|
13
15
|
user: 0,
|
|
14
16
|
};
|
|
17
|
+
|
|
18
|
+
const thisProcess = {
|
|
19
|
+
active: 0,
|
|
20
|
+
system: 0,
|
|
21
|
+
user: 0,
|
|
22
|
+
};
|
|
15
23
|
const details = previousCpuArray.map(() => {
|
|
16
24
|
return {
|
|
17
25
|
inactive: 100,
|
|
@@ -68,6 +76,19 @@ export const startMeasuringCpuUsage = () => {
|
|
|
68
76
|
overallUsageSample,
|
|
69
77
|
});
|
|
70
78
|
|
|
79
|
+
const processCpuUsage = cpuUsage();
|
|
80
|
+
const thisProcessSystemMs = Math.round(
|
|
81
|
+
(processCpuUsage.system - previousCpuUsage.system) / 1000,
|
|
82
|
+
);
|
|
83
|
+
const thisProcessUserMs = Math.round(
|
|
84
|
+
(processCpuUsage.user - previousCpuUsage.user) / 1000,
|
|
85
|
+
);
|
|
86
|
+
previousCpuUsage = processCpuUsage;
|
|
87
|
+
const thisProcessActiveMs = thisProcessSystemMs + thisProcessUserMs;
|
|
88
|
+
thisProcess.active = thisProcessActiveMs / overallMsEllapsed;
|
|
89
|
+
thisProcess.system = thisProcessSystemMs / overallMsEllapsed;
|
|
90
|
+
thisProcess.user = thisProcessUserMs / overallMsEllapsed;
|
|
91
|
+
|
|
71
92
|
if (samples.length === 10) {
|
|
72
93
|
let index = 0;
|
|
73
94
|
for (const detail of details) {
|
|
@@ -117,6 +138,7 @@ export const startMeasuringCpuUsage = () => {
|
|
|
117
138
|
|
|
118
139
|
return {
|
|
119
140
|
overall,
|
|
141
|
+
thisProcess,
|
|
120
142
|
details,
|
|
121
143
|
stop: () => {
|
|
122
144
|
clearInterval(interval);
|
|
@@ -140,3 +162,35 @@ export const ratioAsPercentage = (ratio) => {
|
|
|
140
162
|
const percentage = `${percentageAsNumberRounded}%`;
|
|
141
163
|
return percentage;
|
|
142
164
|
};
|
|
165
|
+
|
|
166
|
+
export const startMeasuringCpuUsage = () => {
|
|
167
|
+
let previousHrtime = process.hrtime();
|
|
168
|
+
let previousCpuUsage = process.cpuUsage();
|
|
169
|
+
|
|
170
|
+
const info = {
|
|
171
|
+
used: 0,
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const interval = setInterval(() => {
|
|
175
|
+
const hrtime = process.hrtime(previousHrtime);
|
|
176
|
+
previousHrtime = hrtime;
|
|
177
|
+
const cpuUsage = process.cpuUsage(previousCpuUsage);
|
|
178
|
+
previousCpuUsage = cpuUsage;
|
|
179
|
+
|
|
180
|
+
const ellapsedMs = hrtime[0] * 1000 + hrtime[1] / 1000000;
|
|
181
|
+
const userMs = Math.round(cpuUsage.user / 1000);
|
|
182
|
+
const systemMs = Math.round(cpuUsage.system / 1000);
|
|
183
|
+
const activeMs = userMs + systemMs;
|
|
184
|
+
const usedRatio = activeMs / ellapsedMs;
|
|
185
|
+
const used = Math.round(usedRatio * 100) / 100;
|
|
186
|
+
info.used = used;
|
|
187
|
+
}, 15);
|
|
188
|
+
interval.unref();
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
info,
|
|
192
|
+
stop: () => {
|
|
193
|
+
clearInterval(interval);
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
};
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
startMeasuringCpuUsage,
|
|
3
|
+
startMeasuringTotalCpuUsage,
|
|
4
|
+
formatUsage,
|
|
5
|
+
} from "./cpu_usage.js";
|
|
2
6
|
|
|
3
7
|
const cpuUsage = startMeasuringCpuUsage();
|
|
8
|
+
setInterval(() => {
|
|
9
|
+
console.log(cpuUsage.info.used);
|
|
10
|
+
}, 400);
|
|
4
11
|
|
|
12
|
+
const totalCpuUsage = startMeasuringTotalCpuUsage();
|
|
5
13
|
setInterval(() => {
|
|
6
|
-
console.log(formatUsage(
|
|
14
|
+
console.log(formatUsage(totalCpuUsage.overall));
|
|
7
15
|
}, 400);
|