22'use strict' ;
33const assert = require ( 'assert' ) ;
44const fs = require ( 'fs' ) ;
5+ const os = require ( 'os' ) ;
56const path = require ( 'path' ) ;
67
78function findReports ( pid , dir ) {
@@ -27,16 +28,194 @@ function validate(report) {
2728}
2829
2930function 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 ( / ^ 0 x [ 0 - 9 a - 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 ( / ^ 0 x [ 0 - 9 a - 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
42221module . exports = { findReports, validate, validateContent } ;
0 commit comments