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 ( / ^ 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' ) ;
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 } ;
0 commit comments