| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a70bafb commit 7ccffcb
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | 'use strict'; | |
| 3 | 3 | const assert = require('assert'); | |
| 4 | 4 | const fs = require('fs'); | |
| 5 | + const os = require('os'); | ||
| 5 | 6 | const path = require('path'); | |
| 6 | 7 | ||
| 7 | 8 | function findReports(pid, dir) { | |
@@ -27,16 +28,194 @@ function validate(report) { | |||
| 27 | 28 | } | |
| 28 | 29 | ||
| 29 | 30 | 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'; | ||
| 30 | 41 | const report = JSON.parse(data); | |
| 31 | 42 | ||
| 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) => { | ||
| 35 | 55 | 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'); | ||
| 36 | 181 | }); | |
| 37 | 182 | ||
| 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 | + }); | ||
| 40 | 219 | } | |
| 41 | 220 | ||
| 42 | 221 | module.exports = { findReports, validate, validateContent }; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments