Skip to content

Commit 7ccffcb

Browse files
cjihrigBridgeAR
authored andcommitted
test: improve validation of report output
This commit improves the validation of generated diagnostic reports. PR-URL: #26289 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Richard Lau <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent a70bafb commit 7ccffcb

File tree

1 file changed

+184
-5
lines changed

1 file changed

+184
-5
lines changed

test/common/report.js

+184-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
'use strict';
33
const assert = require('assert');
44
const fs = require('fs');
5+
const os = require('os');
56
const path = require('path');
67

78
function findReports(pid, dir) {
@@ -27,16 +28,194 @@ function validate(report) {
2728
}
2829

2930
function validateContent(data) {
31+
try {
32+
_validateContent(data);
33+
} catch (err) {
34+
err.stack += `\n------\nFailing Report:\n${data}`;
35+
throw err;
36+
}
37+
}
38+
39+
function _validateContent(data) {
40+
const isWindows = process.platform === 'win32';
3041
const report = JSON.parse(data);
3142

32-
// Verify that all sections are present.
33-
['header', 'javascriptStack', 'nativeStack', 'javascriptHeap',
34-
'libuv', 'environmentVariables', 'sharedObjects'].forEach((section) => {
43+
// Verify that all sections are present as own properties of the report.
44+
const sections = ['header', 'javascriptStack', 'nativeStack',
45+
'javascriptHeap', 'libuv', 'environmentVariables',
46+
'sharedObjects'];
47+
if (!isWindows)
48+
sections.push('resourceUsage', 'userLimits');
49+
50+
if (report.uvthreadResourceUsage)
51+
sections.push('uvthreadResourceUsage');
52+
53+
checkForUnknownFields(report, sections);
54+
sections.forEach((section) => {
3555
assert(report.hasOwnProperty(section));
56+
assert(typeof report[section] === 'object' && report[section] !== null);
57+
});
58+
59+
// Verify the format of the header section.
60+
const header = report.header;
61+
const headerFields = ['event', 'location', 'filename', 'dumpEventTime',
62+
'dumpEventTimeStamp', 'processId', 'commandLine',
63+
'nodejsVersion', 'wordSize', 'arch', 'platform',
64+
'componentVersions', 'release', 'osName', 'osRelease',
65+
'osVersion', 'osMachine', 'host', 'glibcVersionRuntime',
66+
'glibcVersionCompiler'];
67+
checkForUnknownFields(header, headerFields);
68+
assert.strictEqual(typeof header.event, 'string');
69+
assert.strictEqual(typeof header.location, 'string');
70+
assert(typeof header.filename === 'string' || header.filename === null);
71+
assert.notStrictEqual(new Date(header.dumpEventTime).toString(),
72+
'Invalid Date');
73+
if (isWindows)
74+
assert.strictEqual(header.dumpEventTimeStamp, undefined);
75+
else
76+
assert(String(+header.dumpEventTimeStamp), header.dumpEventTimeStamp);
77+
78+
assert(Number.isSafeInteger(header.processId));
79+
assert(Array.isArray(header.commandLine));
80+
header.commandLine.forEach((arg) => {
81+
assert.strictEqual(typeof arg, 'string');
82+
});
83+
assert.strictEqual(header.nodejsVersion, process.version);
84+
assert(Number.isSafeInteger(header.wordSize));
85+
assert.strictEqual(header.arch, os.arch());
86+
assert.strictEqual(header.platform, os.platform());
87+
assert.deepStrictEqual(header.componentVersions, process.versions);
88+
assert.deepStrictEqual(header.release, process.release);
89+
assert.strictEqual(header.osName, os.type());
90+
assert.strictEqual(header.osRelease, os.release());
91+
assert.strictEqual(typeof header.osVersion, 'string');
92+
assert.strictEqual(typeof header.osMachine, 'string');
93+
assert.strictEqual(header.host, os.hostname());
94+
95+
// Verify the format of the javascriptStack section.
96+
checkForUnknownFields(report.javascriptStack, ['message', 'stack']);
97+
assert.strictEqual(typeof report.javascriptStack.message, 'string');
98+
if (report.javascriptStack.stack !== undefined) {
99+
assert(Array.isArray(report.javascriptStack.stack));
100+
report.javascriptStack.stack.forEach((frame) => {
101+
assert.strictEqual(typeof frame, 'string');
102+
});
103+
}
104+
105+
// Verify the format of the nativeStack section.
106+
assert(Array.isArray(report.nativeStack));
107+
report.nativeStack.forEach((frame) => {
108+
assert(typeof frame === 'object' && frame !== null);
109+
checkForUnknownFields(frame, ['pc', 'symbol']);
110+
assert.strictEqual(typeof frame.pc, 'string');
111+
assert(/^0x[0-9a-f]+$/.test(frame.pc));
112+
assert.strictEqual(typeof frame.symbol, 'string');
113+
});
114+
115+
// Verify the format of the javascriptHeap section.
116+
const heap = report.javascriptHeap;
117+
const jsHeapFields = ['totalMemory', 'totalCommittedMemory', 'usedMemory',
118+
'availableMemory', 'memoryLimit', 'heapSpaces'];
119+
checkForUnknownFields(heap, jsHeapFields);
120+
assert(Number.isSafeInteger(heap.totalMemory));
121+
assert(Number.isSafeInteger(heap.totalCommittedMemory));
122+
assert(Number.isSafeInteger(heap.usedMemory));
123+
assert(Number.isSafeInteger(heap.availableMemory));
124+
assert(Number.isSafeInteger(heap.memoryLimit));
125+
assert(typeof heap.heapSpaces === 'object' && heap.heapSpaces !== null);
126+
const heapSpaceFields = ['memorySize', 'committedMemory', 'capacity', 'used',
127+
'available'];
128+
Object.keys(heap.heapSpaces).forEach((spaceName) => {
129+
const space = heap.heapSpaces[spaceName];
130+
checkForUnknownFields(space, heapSpaceFields);
131+
heapSpaceFields.forEach((field) => {
132+
assert(Number.isSafeInteger(space[field]));
133+
});
134+
});
135+
136+
// Verify the format of the resourceUsage section on non-Windows platforms.
137+
if (!isWindows) {
138+
const usage = report.resourceUsage;
139+
const resourceUsageFields = ['userCpuSeconds', 'kernelCpuSeconds',
140+
'cpuConsumptionPercent', 'maxRss',
141+
'pageFaults', 'fsActivity'];
142+
checkForUnknownFields(usage, resourceUsageFields);
143+
assert.strictEqual(typeof usage.userCpuSeconds, 'number');
144+
assert.strictEqual(typeof usage.kernelCpuSeconds, 'number');
145+
assert.strictEqual(typeof usage.cpuConsumptionPercent, 'number');
146+
assert(Number.isSafeInteger(usage.maxRss));
147+
assert(typeof usage.pageFaults === 'object' && usage.pageFaults !== null);
148+
checkForUnknownFields(usage.pageFaults, ['IORequired', 'IONotRequired']);
149+
assert(Number.isSafeInteger(usage.pageFaults.IORequired));
150+
assert(Number.isSafeInteger(usage.pageFaults.IONotRequired));
151+
assert(typeof usage.fsActivity === 'object' && usage.fsActivity !== null);
152+
checkForUnknownFields(usage.fsActivity, ['reads', 'writes']);
153+
assert(Number.isSafeInteger(usage.fsActivity.reads));
154+
assert(Number.isSafeInteger(usage.fsActivity.writes));
155+
}
156+
157+
// Verify the format of the uvthreadResourceUsage section, if present.
158+
if (report.uvthreadResourceUsage) {
159+
const usage = report.uvthreadResourceUsage;
160+
const threadUsageFields = ['userCpuSeconds', 'kernelCpuSeconds',
161+
'cpuConsumptionPercent', 'fsActivity'];
162+
checkForUnknownFields(usage, threadUsageFields);
163+
assert.strictEqual(typeof usage.userCpuSeconds, 'number');
164+
assert.strictEqual(typeof usage.kernelCpuSeconds, 'number');
165+
assert.strictEqual(typeof usage.cpuConsumptionPercent, 'number');
166+
assert(typeof usage.fsActivity === 'object' && usage.fsActivity !== null);
167+
checkForUnknownFields(usage.fsActivity, ['reads', 'writes']);
168+
assert(Number.isSafeInteger(usage.fsActivity.reads));
169+
assert(Number.isSafeInteger(usage.fsActivity.writes));
170+
}
171+
172+
// Verify the format of the libuv section.
173+
assert(Array.isArray(report.libuv));
174+
report.libuv.forEach((resource) => {
175+
assert.strictEqual(typeof resource.type, 'string');
176+
assert.strictEqual(typeof resource.address, 'string');
177+
assert(/^0x[0-9a-f]+$/.test(resource.address));
178+
assert.strictEqual(typeof resource.is_active, 'boolean');
179+
assert.strictEqual(typeof resource.is_referenced,
180+
resource.type === 'loop' ? 'undefined' : 'boolean');
36181
});
37182

38-
assert.deepStrictEqual(report.header.componentVersions, process.versions);
39-
assert.deepStrictEqual(report.header.release, process.release);
183+
// Verify the format of the environmentVariables section.
184+
for (const [key, value] of Object.entries(report.environmentVariables)) {
185+
assert.strictEqual(typeof key, 'string');
186+
assert.strictEqual(typeof value, 'string');
187+
}
188+
189+
// Verify the format of the userLimits section on non-Windows platforms.
190+
if (!isWindows) {
191+
const userLimitsFields = ['core_file_size_blocks', 'data_seg_size_kbytes',
192+
'file_size_blocks', 'max_locked_memory_bytes',
193+
'max_memory_size_kbytes', 'open_files',
194+
'stack_size_bytes', 'cpu_time_seconds',
195+
'max_user_processes', 'virtual_memory_kbytes'];
196+
checkForUnknownFields(report.userLimits, userLimitsFields);
197+
for (const [type, limits] of Object.entries(report.userLimits)) {
198+
assert.strictEqual(typeof type, 'string');
199+
assert(typeof limits === 'object' && limits !== null);
200+
checkForUnknownFields(limits, ['soft', 'hard']);
201+
assert(typeof limits.soft === 'number' || limits.soft === 'unlimited',
202+
`Invalid ${type} soft limit of ${limits.soft}`);
203+
assert(typeof limits.hard === 'number' || limits.hard === 'unlimited',
204+
`Invalid ${type} hard limit of ${limits.hard}`);
205+
}
206+
}
207+
208+
// Verify the format of the sharedObjects section.
209+
assert(Array.isArray(report.sharedObjects));
210+
report.sharedObjects.forEach((sharedObject) => {
211+
assert.strictEqual(typeof sharedObject, 'string');
212+
});
213+
}
214+
215+
function checkForUnknownFields(actual, expected) {
216+
Object.keys(actual).forEach((field) => {
217+
assert(expected.includes(field), `'${field}' not expected in ${expected}`);
218+
});
40219
}
41220

42221
module.exports = { findReports, validate, validateContent };

0 commit comments

Comments
 (0)