orator 2.0.4 → 2.0.10
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/.travis.yml +4 -0
- package/package.json +22 -6
- package/source/Orator.js +96 -94
- package/test/Orator-proxy_tests.js +16 -7
- package/test/Orator_basic_tests.js +115 -13
- package/test/Orator_cluster_test.js.deferred +7 -7
- package/test/Orator_logging_tests.js +56 -10
- package/.vscode/launch.json +0 -26
- package/test/Orator_chromecpu_notrace_tests.js +0 -90
- package/test/Orator_chromecpu_tests.js +0 -95
package/.travis.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orator",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "Restful web API server. Using restify 6.",
|
|
5
5
|
"main": "source/Orator.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"coverage-cluster": "./node_modules/istanbul/lib/cli.js cover --dir ./coverage/cluster ./node_modules/mocha/bin/_mocha -- --exit -u tdd -R spec ./test/Orator_cluster_test.js.deferred",
|
|
11
11
|
"coverage-report": "./node_modules/istanbul/lib/cli.js report",
|
|
12
12
|
"test": "npm run test-normal && npm run test-cluster",
|
|
13
|
+
"tests": "mocha --exit -u tdd -R spec -g",
|
|
13
14
|
"test-normal": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec",
|
|
14
15
|
"test-cluster": "./node_modules/mocha/bin/_mocha --exit -u tdd -R spec ./test/Orator_cluster_test.js.deferred"
|
|
15
16
|
},
|
|
@@ -27,6 +28,24 @@
|
|
|
27
28
|
"bugs": {
|
|
28
29
|
"url": "https://github.com/stevenvelozo/orator/issues"
|
|
29
30
|
},
|
|
31
|
+
"mocha": {
|
|
32
|
+
"diff": true,
|
|
33
|
+
"extension": [
|
|
34
|
+
"js"
|
|
35
|
+
],
|
|
36
|
+
"package": "./package.json",
|
|
37
|
+
"reporter": "spec",
|
|
38
|
+
"slow": "75",
|
|
39
|
+
"timeout": "5000",
|
|
40
|
+
"ui": "tdd",
|
|
41
|
+
"watch-files": [
|
|
42
|
+
"source/**/*.js",
|
|
43
|
+
"test/**/*.js"
|
|
44
|
+
],
|
|
45
|
+
"watch-ignore": [
|
|
46
|
+
"lib/vendor"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
30
49
|
"homepage": "https://github.com/stevenvelozo/orator",
|
|
31
50
|
"devDependencies": {
|
|
32
51
|
"async": "2.6.1",
|
|
@@ -37,18 +56,15 @@
|
|
|
37
56
|
"mocha": "5.2.0",
|
|
38
57
|
"supertest": "3.1.0"
|
|
39
58
|
},
|
|
40
|
-
"optionalDependencies": {
|
|
41
|
-
"v8-profiler": "^5.7.0"
|
|
42
|
-
},
|
|
43
59
|
"dependencies": {
|
|
44
60
|
"cachetrax": "^1.0.0",
|
|
45
61
|
"cluster": "^0.7.7",
|
|
46
62
|
"fable": "~1.0.2",
|
|
47
63
|
"fable-uuid": "~1.0.2",
|
|
48
64
|
"http-forward": "^0.1.3",
|
|
49
|
-
"request": "^2.
|
|
65
|
+
"request": "^2.88.2",
|
|
50
66
|
"restify": "^6.4.0",
|
|
51
|
-
"restify-await-promise": "^
|
|
67
|
+
"restify-await-promise": "^2.2.0",
|
|
52
68
|
"restify-cors-middleware": "^1.1.1"
|
|
53
69
|
}
|
|
54
70
|
}
|
package/source/Orator.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const libRestifyCORS = require('restify-cors-middleware');
|
|
8
8
|
const restifyPromise = require('restify-await-promise');
|
|
9
|
+
const RestifyErrors = require('restify-errors');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Orator Web API Server
|
|
@@ -25,15 +26,13 @@ var Orator = function()
|
|
|
25
26
|
|
|
26
27
|
// Restify for the routing and API serving
|
|
27
28
|
var libRestify = require('restify');
|
|
28
|
-
// NodeGrind for request profiling
|
|
29
|
-
var libV8Profiler = false;
|
|
30
29
|
// FS for writing out profiling information
|
|
31
30
|
var libFS = require('fs');
|
|
32
31
|
// Cluster API for spawning multiple worker processes
|
|
33
32
|
var libCluster = require('cluster');
|
|
34
33
|
// HTTP Forward Proxy
|
|
35
34
|
var libHttpForward = require('http-forward');
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
var _ProxyRoutes = [];
|
|
38
37
|
|
|
39
38
|
// This state is used to lazily initialize the Native Restify Modules on route creation the first time
|
|
@@ -113,7 +112,7 @@ var Orator = function()
|
|
|
113
112
|
// This is used as the base object for instantiating the server. You can add custom parsers and formatters safely with lambdas here.
|
|
114
113
|
RawServerParameters: {},
|
|
115
114
|
|
|
116
|
-
//
|
|
115
|
+
// Enable request lifecycle logging if desired, for debugging
|
|
117
116
|
Profiling: (
|
|
118
117
|
{
|
|
119
118
|
// Tracelog is just log-based request timing encapsulation.
|
|
@@ -121,16 +120,7 @@ var Orator = function()
|
|
|
121
120
|
|
|
122
121
|
// Requestlog is to log each request ID and Session ID.
|
|
123
122
|
RequestLog: false,
|
|
124
|
-
|
|
125
|
-
// These profiling settings determine if we generate cpu or call graphs
|
|
126
|
-
Enabled: false,
|
|
127
|
-
Folder: '/tmp/',
|
|
128
|
-
// Currently supported profile types: ChromeCPU
|
|
129
|
-
Type: 'ChromeCPU'
|
|
130
123
|
}),
|
|
131
|
-
|
|
132
|
-
// Turning this on logs stack traces
|
|
133
|
-
LogStackTraces: true
|
|
134
124
|
});
|
|
135
125
|
|
|
136
126
|
var _Fable = require('fable').new(pSettings);
|
|
@@ -252,7 +242,7 @@ var Orator = function()
|
|
|
252
242
|
// Lazily initialize the Restify parsers the first time we access this object.
|
|
253
243
|
// This creates a behavior where changing the "enabledModules" property does not
|
|
254
244
|
// do anything after routes have been created. We may want to eventually
|
|
255
|
-
// throw a warning (and
|
|
245
|
+
// throw a warning (and ignore the change) if someone accesses the property
|
|
256
246
|
// after _RestifyParsersInitialized is true.
|
|
257
247
|
if (!_RestifyParsersInitialized)
|
|
258
248
|
{
|
|
@@ -260,21 +250,6 @@ var Orator = function()
|
|
|
260
250
|
initializeHeaderParsers(_Fable.settings, _WebServer);
|
|
261
251
|
initializeContentParsers(_Fable.settings, _WebServer);
|
|
262
252
|
initializeLogicParsers(_Fable.settings, _WebServer);
|
|
263
|
-
_WebServer.on
|
|
264
|
-
(
|
|
265
|
-
'uncaughtException',
|
|
266
|
-
function (pRequest, pResponse, pRoute, pError)
|
|
267
|
-
{
|
|
268
|
-
if (typeof(_Fable.settings.UncaughtExceptionHook) === 'function')
|
|
269
|
-
{
|
|
270
|
-
_Fable.settings.UncaughtExceptionHook(pRequest, pResponse, pRoute, pError);
|
|
271
|
-
}
|
|
272
|
-
if (_Fable.settings.LogStackTraces)
|
|
273
|
-
{
|
|
274
|
-
_Fable.log.error('Request error', {Error:true, Stack:pError.stack});
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
);
|
|
278
253
|
}
|
|
279
254
|
};
|
|
280
255
|
|
|
@@ -300,18 +275,6 @@ var Orator = function()
|
|
|
300
275
|
_Fable.log.trace('Request start...',{RequestUUID: pRequest.RequestUUID});
|
|
301
276
|
}
|
|
302
277
|
|
|
303
|
-
if (_Fable.settings.Profiling.Enabled)
|
|
304
|
-
{
|
|
305
|
-
// Lazily load NodeGrind
|
|
306
|
-
if (!libV8Profiler)
|
|
307
|
-
{
|
|
308
|
-
libV8Profiler = require('v8-profiler');
|
|
309
|
-
}
|
|
310
|
-
// If profiling is enabled, build a callgrind file
|
|
311
|
-
_Fable.log.debug('Request '+pRequest.RequestUUID+' starting with full profiling...');
|
|
312
|
-
pRequest.ProfilerName = _Fable.settings.Product+'-'+_Fable.settings.ProductVersion+'-'+pRequest.RequestUUID;
|
|
313
|
-
libV8Profiler.startProfiling(pRequest.RequestUUID, true);
|
|
314
|
-
}
|
|
315
278
|
|
|
316
279
|
return fNext();
|
|
317
280
|
}
|
|
@@ -326,28 +289,6 @@ var Orator = function()
|
|
|
326
289
|
{
|
|
327
290
|
_Fable.log.trace("... Request finished.",{RequestUUID: pRequest.RequestUUID, ResponseCode: pResponse.code, ResponseLength: pResponse.contentLength});
|
|
328
291
|
}
|
|
329
|
-
|
|
330
|
-
if (typeof(pRequest.ProfilerName) === 'string')
|
|
331
|
-
{
|
|
332
|
-
var tmpRequestProfilePrefix = '';
|
|
333
|
-
var tmpRequestProfilePostfix = '';
|
|
334
|
-
|
|
335
|
-
// Get a Chrome *.cpuprofile.json that you can load into the Chrome
|
|
336
|
-
// profiler (right-click on 'Profiles' in left pane in the 'Profiles' tab)
|
|
337
|
-
var tmpChromeCPUProfiler = libV8Profiler.stopProfiling();
|
|
338
|
-
tmpRequestProfilePostfix = '.cpuprofile.json';
|
|
339
|
-
|
|
340
|
-
tmpChromeCPUProfiler.export(function(pError, pProfileData)
|
|
341
|
-
{
|
|
342
|
-
var tmpProfilerFileName = _Fable.settings.Profiling.Folder+tmpRequestProfilePrefix+pRequest.ProfilerName+tmpRequestProfilePostfix;
|
|
343
|
-
libFS.writeFileSync(tmpProfilerFileName, pProfileData);
|
|
344
|
-
pRequest.CPUProfiler.delete();
|
|
345
|
-
if (_Fable.settings.Profiling.TraceLog)
|
|
346
|
-
{
|
|
347
|
-
_Fable.log.trace('... Request '+pRequest.RequestUUID+' profile written to: '+tmpProfilerFileName);
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
292
|
}
|
|
352
293
|
);
|
|
353
294
|
};
|
|
@@ -361,16 +302,16 @@ var Orator = function()
|
|
|
361
302
|
*
|
|
362
303
|
* @method startWorkers
|
|
363
304
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
305
|
+
var startWorkers = function(pWorkers, fCallback)
|
|
306
|
+
{
|
|
307
|
+
if (pWorkers === 0)
|
|
308
|
+
{
|
|
309
|
+
return fCallback();
|
|
310
|
+
}
|
|
311
|
+
else if (pWorkers < 0)
|
|
312
|
+
{
|
|
313
|
+
pWorkers = require('os').cpus().length;
|
|
314
|
+
}
|
|
374
315
|
|
|
375
316
|
for (var i=0; i<pWorkers; i++)
|
|
376
317
|
{
|
|
@@ -381,25 +322,25 @@ var Orator = function()
|
|
|
381
322
|
|
|
382
323
|
libCluster.on('message', function(message)
|
|
383
324
|
{
|
|
384
|
-
|
|
325
|
+
_Fable.log.trace('Orator Worker ' + message.pid + ' started.');
|
|
385
326
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
327
|
+
if (++tmpActiveWorkers === pWorkers)
|
|
328
|
+
{
|
|
329
|
+
//The Master process fires the callback when all
|
|
330
|
+
// the workers have started. This is used by
|
|
331
|
+
// unit tests.
|
|
332
|
+
return fCallback();
|
|
333
|
+
}
|
|
393
334
|
});
|
|
394
335
|
libCluster.on('exit', function(worker, code, signal)
|
|
395
336
|
{
|
|
396
|
-
|
|
337
|
+
_Fable.log.trace('Orator Worker ' + worker.id + '/' + worker.process.pid + ' died');
|
|
397
338
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
339
|
+
// APIWorkerRestart flag auto-restarts a worker if it crashes
|
|
340
|
+
if (_Fable.settings.APIWorkerRestart)
|
|
341
|
+
{
|
|
342
|
+
libCluster.fork();
|
|
343
|
+
}
|
|
403
344
|
});
|
|
404
345
|
};
|
|
405
346
|
|
|
@@ -433,7 +374,7 @@ var Orator = function()
|
|
|
433
374
|
if (!libCluster.isMaster)
|
|
434
375
|
{
|
|
435
376
|
// notify master about the request
|
|
436
|
-
|
|
377
|
+
process.send({ signal: 'notifyListening', pid: process.pid });
|
|
437
378
|
}
|
|
438
379
|
return tmpNext();
|
|
439
380
|
}
|
|
@@ -496,7 +437,8 @@ var Orator = function()
|
|
|
496
437
|
'application/octet-stream',
|
|
497
438
|
'application/javascript',
|
|
498
439
|
'application/json'
|
|
499
|
-
]
|
|
440
|
+
],
|
|
441
|
+
handleUncaughtExceptions: true,
|
|
500
442
|
});
|
|
501
443
|
_Fable.settings.RawServerParameters = _WebServerParameters;
|
|
502
444
|
};
|
|
@@ -599,7 +541,7 @@ var Orator = function()
|
|
|
599
541
|
_Fable.log.error('Proxy error', pError);
|
|
600
542
|
}
|
|
601
543
|
|
|
602
|
-
return fNext(
|
|
544
|
+
return fNext(false);
|
|
603
545
|
});
|
|
604
546
|
};
|
|
605
547
|
|
|
@@ -647,16 +589,45 @@ var Orator = function()
|
|
|
647
589
|
);
|
|
648
590
|
};
|
|
649
591
|
|
|
592
|
+
var userErrorTransformer;
|
|
593
|
+
var registerErrorTransformer = function(transformError)
|
|
594
|
+
{
|
|
595
|
+
if (typeof(transformError) === 'function')
|
|
596
|
+
{
|
|
597
|
+
userErrorTransformer = transformError;
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
var userUnhandledErrorHandler;
|
|
602
|
+
var registerUnhandledErrorHandler = function(callback)
|
|
603
|
+
{
|
|
604
|
+
if (typeof(callback) === 'function')
|
|
605
|
+
{
|
|
606
|
+
userUnhandledErrorHandler = callback;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
|
|
650
610
|
var handleError = function(req, res, err, callback)
|
|
651
611
|
{
|
|
612
|
+
// allow application to customize this error handling
|
|
613
|
+
if (typeof userUnhandledErrorHandler == 'function' && !userUnhandledErrorHandler(req, res, err, callback))
|
|
614
|
+
{
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
652
617
|
//the default for a string error is 'Route not found', though it isn't accurate
|
|
653
618
|
err.message = err.message.replace('Route not found: ', '');
|
|
654
619
|
//log error
|
|
655
620
|
let sessionId = '';
|
|
656
621
|
if (req.UserSession && req.UserSession.SessionID)
|
|
622
|
+
{
|
|
657
623
|
sessionId = req.UserSession.SessionID;
|
|
658
|
-
|
|
659
|
-
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
if (!err.logged)
|
|
627
|
+
{
|
|
628
|
+
_Fable.log.error('REQUEST ERROR: ' + err.message || err,
|
|
629
|
+
{ SessionID: sessionId, Action: 'APIError', RequestUUID: req.RequestUUID, Error: err.message || err, Stack: err.stack, });
|
|
630
|
+
}
|
|
660
631
|
return callback();
|
|
661
632
|
}
|
|
662
633
|
|
|
@@ -677,6 +648,9 @@ var Orator = function()
|
|
|
677
648
|
serveStatic: libRestify.plugins.serveStatic,
|
|
678
649
|
getHeader: getHeader,
|
|
679
650
|
|
|
651
|
+
registerErrorTransformer: registerErrorTransformer,
|
|
652
|
+
registerUnhandledErrorHandler: registerUnhandledErrorHandler,
|
|
653
|
+
|
|
680
654
|
new: createNew
|
|
681
655
|
});
|
|
682
656
|
|
|
@@ -686,7 +660,7 @@ var Orator = function()
|
|
|
686
660
|
* @property webServer
|
|
687
661
|
* @type Object
|
|
688
662
|
*/
|
|
689
|
-
var getWebServer = function()
|
|
663
|
+
var getWebServer = function()
|
|
690
664
|
{
|
|
691
665
|
// Lazily load the webserver the first time it is accessed
|
|
692
666
|
if (typeof(_WebServer) === 'undefined')
|
|
@@ -696,7 +670,35 @@ var Orator = function()
|
|
|
696
670
|
_WebServerParameters.version = _Fable.settings.ProductVersion;
|
|
697
671
|
_WebServer = libRestify.createServer(_WebServerParameters);
|
|
698
672
|
//enable support for Promise endpoint methods
|
|
699
|
-
restifyPromise.install(_WebServer
|
|
673
|
+
restifyPromise.install(_WebServer,
|
|
674
|
+
{
|
|
675
|
+
/*
|
|
676
|
+
* We provide an error transformer here to handle uncaught exceptions, as the
|
|
677
|
+
* old code path is broken by this plugin. This at least allows us to send back
|
|
678
|
+
* some kind of error to the caller. Without this, you get a 500 with a body of {}
|
|
679
|
+
*/
|
|
680
|
+
errorTransformer:
|
|
681
|
+
{
|
|
682
|
+
transform: (originalError) =>
|
|
683
|
+
{
|
|
684
|
+
let error = originalError;
|
|
685
|
+
if (typeof userErrorTransformer == 'function')
|
|
686
|
+
{
|
|
687
|
+
error = userErrorTransformer(error);
|
|
688
|
+
}
|
|
689
|
+
// duck typing for error objects; means an exception was thrown; but status code means it was handled upstream
|
|
690
|
+
if (error && error.message && error.stack && !error.statusCode)
|
|
691
|
+
{
|
|
692
|
+
_Fable.log.fatal('Unhandled request error', { Error: error.message || error, Stack: error.stack, });
|
|
693
|
+
|
|
694
|
+
const wrappedError = new RestifyErrors.InternalError(error, error.message || 'Unhandled error');
|
|
695
|
+
wrappedError.logged = true; // dumb, but prevents double logging in handleError
|
|
696
|
+
return wrappedError;
|
|
697
|
+
}
|
|
698
|
+
return error || new Error('fail request'); // returning no error here is bad news; request can get stuck, so at least return something
|
|
699
|
+
},
|
|
700
|
+
},
|
|
701
|
+
});
|
|
700
702
|
//handle errors - DOES NOT HANDLE uncaught exceptions! (DOES work with Promises however)
|
|
701
703
|
_WebServer.on('restifyError', handleError);
|
|
702
704
|
initializeInstrumentation();
|
|
@@ -16,12 +16,12 @@ var _MockSettings = (
|
|
|
16
16
|
{
|
|
17
17
|
Product: 'MockOratorAlternate',
|
|
18
18
|
ProductVersion: '0.0.0',
|
|
19
|
-
APIServerPort: 8181
|
|
19
|
+
APIServerPort: 8181,
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
suite
|
|
23
23
|
(
|
|
24
|
-
'Orator',
|
|
24
|
+
'Orator Proxy',
|
|
25
25
|
function()
|
|
26
26
|
{
|
|
27
27
|
var _Orator;
|
|
@@ -34,6 +34,14 @@ suite
|
|
|
34
34
|
}
|
|
35
35
|
);
|
|
36
36
|
|
|
37
|
+
suiteTeardown
|
|
38
|
+
(
|
|
39
|
+
function()
|
|
40
|
+
{
|
|
41
|
+
_Orator.stopWebServer();
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
37
45
|
suite
|
|
38
46
|
(
|
|
39
47
|
'Object Sanity',
|
|
@@ -99,7 +107,7 @@ suite
|
|
|
99
107
|
fNext();
|
|
100
108
|
}
|
|
101
109
|
);
|
|
102
|
-
|
|
110
|
+
|
|
103
111
|
// Create a route to proxy HTTP requests to google, dropping the prefix for the remote request
|
|
104
112
|
_Orator.addProxyRoute('google/', 'https://www.google.com/');
|
|
105
113
|
|
|
@@ -112,7 +120,7 @@ suite
|
|
|
112
120
|
_Orator.addStaticRoute(__dirname+'/../', 'LICENSE', /\/content\/(.*)/, '/content/');
|
|
113
121
|
// You should be able to host files just with a path
|
|
114
122
|
_Orator.addStaticRoute(__dirname+'/');
|
|
115
|
-
|
|
123
|
+
|
|
116
124
|
_Orator.startWebServer(fDone);
|
|
117
125
|
}
|
|
118
126
|
);
|
|
@@ -138,13 +146,13 @@ suite
|
|
|
138
146
|
function(fDone)
|
|
139
147
|
{
|
|
140
148
|
libSuperTest('http://localhost:' + _MockSettings.APIServerPort + '/')
|
|
141
|
-
.get('google/
|
|
149
|
+
.get('google/a')
|
|
142
150
|
.end(
|
|
143
151
|
function (pError, pResponse)
|
|
144
152
|
{
|
|
145
153
|
//check for google search result
|
|
146
154
|
Expect(pResponse.text)
|
|
147
|
-
.to.contain('
|
|
155
|
+
.to.contain('google');
|
|
148
156
|
return fDone();
|
|
149
157
|
}
|
|
150
158
|
);
|
|
@@ -184,7 +192,7 @@ suite
|
|
|
184
192
|
//check for not found
|
|
185
193
|
Expect(pResponse.statusCode)
|
|
186
194
|
.to.equal(404);
|
|
187
|
-
|
|
195
|
+
|
|
188
196
|
return fDone();
|
|
189
197
|
}
|
|
190
198
|
);
|
|
@@ -196,6 +204,7 @@ suite
|
|
|
196
204
|
'Shutdown Orator web server',
|
|
197
205
|
function()
|
|
198
206
|
{
|
|
207
|
+
//TODO: this test assumes the order of test execution; is that safe?
|
|
199
208
|
_Orator.stopWebServer();
|
|
200
209
|
}
|
|
201
210
|
);
|
|
@@ -16,21 +16,49 @@ var _MockSettings = (
|
|
|
16
16
|
{
|
|
17
17
|
Product: 'MockOratorAlternate',
|
|
18
18
|
ProductVersion: '0.0.0',
|
|
19
|
-
APIServerPort:
|
|
19
|
+
APIServerPort: 8999,
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
suite
|
|
23
23
|
(
|
|
24
|
-
'Orator',
|
|
24
|
+
'Orator basic',
|
|
25
25
|
function()
|
|
26
26
|
{
|
|
27
27
|
var _Orator;
|
|
28
|
+
let capturedOriginalErr = null;
|
|
29
|
+
let capturedReq = null;
|
|
30
|
+
let capturedRes = null;
|
|
31
|
+
let capturedErr = null;
|
|
32
|
+
let capturedCallback = null;
|
|
28
33
|
|
|
29
34
|
setup
|
|
30
35
|
(
|
|
31
36
|
function()
|
|
32
37
|
{
|
|
33
38
|
_Orator = require('../source/Orator.js').new(_MockSettings);
|
|
39
|
+
_Orator.registerUnhandledErrorHandler((req, res, err, callback) =>
|
|
40
|
+
{
|
|
41
|
+
capturedReq = req;
|
|
42
|
+
capturedRes = res;
|
|
43
|
+
capturedErr = err;
|
|
44
|
+
capturedCallback = callback;
|
|
45
|
+
return err.statusCode > 0;
|
|
46
|
+
});
|
|
47
|
+
_Orator.registerErrorTransformer((err) =>
|
|
48
|
+
{
|
|
49
|
+
capturedOriginalErr = err;
|
|
50
|
+
return err;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
teardown(() => { capturedReq = undefined; capturedRes = undefined; capturedErr = undefined; capturedOriginalErr = undefined; });
|
|
56
|
+
|
|
57
|
+
suiteTeardown
|
|
58
|
+
(
|
|
59
|
+
function()
|
|
60
|
+
{
|
|
61
|
+
_Orator.stopWebServer();
|
|
34
62
|
}
|
|
35
63
|
);
|
|
36
64
|
|
|
@@ -95,8 +123,8 @@ suite
|
|
|
95
123
|
'/ThirdAPI',
|
|
96
124
|
function (pRequest, pResponse, fNext)
|
|
97
125
|
{
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
throw new Error('The server should give a nice stack trace');
|
|
127
|
+
fNext();
|
|
100
128
|
}
|
|
101
129
|
);
|
|
102
130
|
_Orator.webServer.get (
|
|
@@ -113,6 +141,23 @@ suite
|
|
|
113
141
|
return Promise.reject('error promise response');
|
|
114
142
|
}
|
|
115
143
|
);
|
|
144
|
+
_Orator.webServer.get (
|
|
145
|
+
'/SyncBug',
|
|
146
|
+
function (pRequest, pResponse, fNext)
|
|
147
|
+
{
|
|
148
|
+
const cat = null;
|
|
149
|
+
cat.dog();
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
_Orator.webServer.get (
|
|
153
|
+
'/AsyncBug',
|
|
154
|
+
async function (pRequest, pResponse)
|
|
155
|
+
{
|
|
156
|
+
await new Promise((resolve) => setTimeout(() => resolve()), 1);
|
|
157
|
+
const cat = null;
|
|
158
|
+
cat.dog();
|
|
159
|
+
}
|
|
160
|
+
);
|
|
116
161
|
// Expect this to fail
|
|
117
162
|
_Orator.addStaticRoute();
|
|
118
163
|
// And you can specify a path for bonus
|
|
@@ -125,19 +170,19 @@ suite
|
|
|
125
170
|
(
|
|
126
171
|
function ()
|
|
127
172
|
{
|
|
128
|
-
libSuperTest(
|
|
173
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
129
174
|
.get('PIN')
|
|
130
175
|
.end(
|
|
131
176
|
function (pError, pResponse)
|
|
132
177
|
{
|
|
133
178
|
Expect(pResponse.text)
|
|
134
179
|
.to.contain('PON');
|
|
135
|
-
libSuperTest(
|
|
180
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
136
181
|
.get('ThirdAPI')
|
|
137
182
|
.end(
|
|
138
183
|
function (pError, pResponse)
|
|
139
184
|
{
|
|
140
|
-
libSuperTest(
|
|
185
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
141
186
|
.get('Test.css')
|
|
142
187
|
.end(
|
|
143
188
|
function (pError, pResponse)
|
|
@@ -145,7 +190,7 @@ suite
|
|
|
145
190
|
_Orator.settings.Profiling.TraceLog = true;
|
|
146
191
|
Expect(pResponse.text)
|
|
147
192
|
.to.contain('50000px');
|
|
148
|
-
libSuperTest(
|
|
193
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
149
194
|
.get('content/')
|
|
150
195
|
.end(
|
|
151
196
|
function (pError, pResponse)
|
|
@@ -170,7 +215,7 @@ suite
|
|
|
170
215
|
'promise routes should work',
|
|
171
216
|
function(fDone)
|
|
172
217
|
{
|
|
173
|
-
libSuperTest(
|
|
218
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
174
219
|
.get('PromiseAPI')
|
|
175
220
|
.end(
|
|
176
221
|
function (pError, pResponse)
|
|
@@ -188,14 +233,70 @@ suite
|
|
|
188
233
|
'promise routes error handling',
|
|
189
234
|
function(fDone)
|
|
190
235
|
{
|
|
191
|
-
libSuperTest(
|
|
236
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
192
237
|
.get('PromiseAPIError')
|
|
193
238
|
.end(
|
|
194
239
|
function (pError, pResponse)
|
|
195
240
|
{
|
|
241
|
+
Expect(capturedErr).to.exist;
|
|
242
|
+
Expect(capturedReq).to.exist;
|
|
243
|
+
Expect(capturedRes).to.exist;
|
|
196
244
|
Expect(pResponse.text)
|
|
197
245
|
.to.contain('error promise response');
|
|
198
246
|
|
|
247
|
+
return fDone();
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
test
|
|
253
|
+
(
|
|
254
|
+
'unhandled error interception',
|
|
255
|
+
function(fDone)
|
|
256
|
+
{
|
|
257
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
258
|
+
.get('SyncBug')
|
|
259
|
+
.end(
|
|
260
|
+
function (pError, pResponse)
|
|
261
|
+
{
|
|
262
|
+
Expect(pError).to.not.exist;
|
|
263
|
+
Expect(capturedOriginalErr).to.exist;
|
|
264
|
+
Expect(capturedErr).to.exist;
|
|
265
|
+
Expect(capturedOriginalErr.statusCode).to.not.exist; // raw error
|
|
266
|
+
Expect(capturedErr.statusCode).to.equal(500); // wrapped to give reasonable http response
|
|
267
|
+
Expect(capturedReq).to.exist; // shows we called the custom error handler
|
|
268
|
+
Expect(capturedReq.RequestUUID).to.be.a('string'); // so we can log this from the handler
|
|
269
|
+
Expect(capturedRes).to.exist; // shows we called the custom error handler
|
|
270
|
+
Expect(capturedErr.message).to.contain('Cannot read properties of null (reading \'dog\')');
|
|
271
|
+
Expect(pResponse.text).to.contain('Cannot read property \'dog\'');
|
|
272
|
+
|
|
273
|
+
return fDone();
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
test
|
|
279
|
+
(
|
|
280
|
+
'unhandled error interception async',
|
|
281
|
+
function(fDone)
|
|
282
|
+
{
|
|
283
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
284
|
+
.get('AsyncBug')
|
|
285
|
+
.end(
|
|
286
|
+
function (pError, pResponse)
|
|
287
|
+
{
|
|
288
|
+
Expect(pError).to.not.exist;
|
|
289
|
+
Expect(capturedOriginalErr).to.exist;
|
|
290
|
+
Expect(capturedErr).to.exist;
|
|
291
|
+
Expect(capturedOriginalErr.statusCode).to.not.exist; // raw error
|
|
292
|
+
Expect(capturedErr.statusCode).to.equal(500); // wrapped to give reasonable http response
|
|
293
|
+
Expect(capturedReq).to.exist; // shows we called the custom error handler
|
|
294
|
+
Expect(capturedReq.RequestUUID).to.be.a('string'); // so we can log this from the handler
|
|
295
|
+
Expect(capturedRes).to.exist; // shows we called the custom error handler
|
|
296
|
+
Expect(capturedCallback).to.be.a('function');
|
|
297
|
+
Expect(capturedErr.message).to.contain('Cannot read property \'dog\'');
|
|
298
|
+
Expect(pResponse.text).to.contain('Cannot read property \'dog\'');
|
|
299
|
+
|
|
199
300
|
return fDone();
|
|
200
301
|
}
|
|
201
302
|
);
|
|
@@ -217,7 +318,7 @@ suite
|
|
|
217
318
|
{
|
|
218
319
|
Product: 'MockOratorInverted',
|
|
219
320
|
ProductVersion: '0.0.0',
|
|
220
|
-
APIServerPort:
|
|
321
|
+
APIServerPort: _MockSettings.APIServerPort - 10,
|
|
221
322
|
LogStackTraces: false
|
|
222
323
|
});
|
|
223
324
|
var _OratorInverted = require('../source/Orator.js').new(_MockSettingsInvertedParameters);
|
|
@@ -251,11 +352,12 @@ suite
|
|
|
251
352
|
}
|
|
252
353
|
);
|
|
253
354
|
_OratorInverted.startWebServer();
|
|
254
|
-
libSuperTest(
|
|
355
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort - 10}/`)
|
|
255
356
|
.get('PINGU')
|
|
256
357
|
.end(
|
|
257
358
|
function (pError, pResponse)
|
|
258
359
|
{
|
|
360
|
+
_OratorInverted.stopWebServer();
|
|
259
361
|
if (pError)
|
|
260
362
|
{
|
|
261
363
|
console.log('Error on Inverted Results: '+JSON.stringify(pError));
|
|
@@ -282,4 +384,4 @@ suite
|
|
|
282
384
|
}
|
|
283
385
|
);
|
|
284
386
|
}
|
|
285
|
-
);
|
|
387
|
+
);
|
|
@@ -17,7 +17,7 @@ var _MockSettings = (
|
|
|
17
17
|
{
|
|
18
18
|
Product: 'MockOratorAlternate',
|
|
19
19
|
ProductVersion: '0.0.0',
|
|
20
|
-
APIServerPort:
|
|
20
|
+
APIServerPort: 8099,
|
|
21
21
|
APIWorkers: 3,
|
|
22
22
|
APIWorkerRestart: false
|
|
23
23
|
});
|
|
@@ -135,19 +135,19 @@ suite
|
|
|
135
135
|
function(fDone)
|
|
136
136
|
{
|
|
137
137
|
|
|
138
|
-
libSuperTest('http://localhost:
|
|
138
|
+
libSuperTest('http://localhost:8099/')
|
|
139
139
|
.get('PIN')
|
|
140
140
|
.end(
|
|
141
141
|
function (pError, pResponse)
|
|
142
142
|
{
|
|
143
143
|
Expect(pResponse.text)
|
|
144
144
|
.to.contain('PON');
|
|
145
|
-
libSuperTest('http://localhost:
|
|
145
|
+
libSuperTest('http://localhost:8099/')
|
|
146
146
|
.get('ThirdAPI')
|
|
147
147
|
.end(
|
|
148
148
|
function (pError, pResponse)
|
|
149
149
|
{
|
|
150
|
-
libSuperTest('http://localhost:
|
|
150
|
+
libSuperTest('http://localhost:8099/')
|
|
151
151
|
.get('Test.css')
|
|
152
152
|
.end(
|
|
153
153
|
function (pError, pResponse)
|
|
@@ -155,7 +155,7 @@ suite
|
|
|
155
155
|
_Orator.settings.Profiling.TraceLog = true;
|
|
156
156
|
Expect(pResponse.text)
|
|
157
157
|
.to.contain('50000px');
|
|
158
|
-
libSuperTest('http://localhost:
|
|
158
|
+
libSuperTest('http://localhost:8099/')
|
|
159
159
|
.get('content/')
|
|
160
160
|
.end(
|
|
161
161
|
function (pError, pResponse)
|
|
@@ -191,7 +191,7 @@ suite
|
|
|
191
191
|
|
|
192
192
|
for(var i=0; i<DISTRIBUTION_LOAD_COUNT; i++)
|
|
193
193
|
{
|
|
194
|
-
libSuperTest('http://localhost:
|
|
194
|
+
libSuperTest('http://localhost:8099/')
|
|
195
195
|
.get('GetPID')
|
|
196
196
|
.end(
|
|
197
197
|
function (pError, pResponse)
|
|
@@ -230,4 +230,4 @@ suite
|
|
|
230
230
|
);
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
-
);
|
|
233
|
+
);
|
|
@@ -15,7 +15,7 @@ var libSuperTest = require('supertest');
|
|
|
15
15
|
var _MockSettings = (
|
|
16
16
|
{
|
|
17
17
|
Product: 'MockOratorRequestLogging',
|
|
18
|
-
APIServerPort:
|
|
18
|
+
APIServerPort: 8985,
|
|
19
19
|
Profiling: (
|
|
20
20
|
{
|
|
21
21
|
// Tracelog is just log-based request timing encapsulation.
|
|
@@ -40,6 +40,14 @@ suite
|
|
|
40
40
|
}
|
|
41
41
|
);
|
|
42
42
|
|
|
43
|
+
suiteTeardown
|
|
44
|
+
(
|
|
45
|
+
function()
|
|
46
|
+
{
|
|
47
|
+
_Orator.stopWebServer();
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
43
51
|
suite
|
|
44
52
|
(
|
|
45
53
|
'Request Logging Server Start',
|
|
@@ -51,22 +59,31 @@ suite
|
|
|
51
59
|
function(fDone)
|
|
52
60
|
{
|
|
53
61
|
_Orator.webServer.get (
|
|
54
|
-
'/PINGOLo',
|
|
55
|
-
function (pRequest, pResponse, fNext)
|
|
62
|
+
'/PINGOLo',
|
|
63
|
+
function (pRequest, pResponse, fNext)
|
|
56
64
|
{
|
|
57
65
|
pResponse.send('Loggo');
|
|
58
66
|
fNext();
|
|
59
67
|
}
|
|
60
68
|
);
|
|
61
69
|
_Orator.webServer.get (
|
|
62
|
-
'/PINataGOLo',
|
|
63
|
-
|
|
70
|
+
'/PINataGOLo',
|
|
71
|
+
function (pRequest, pResponse, fNext)
|
|
72
|
+
{
|
|
73
|
+
throw new Error("Something absolutely dire has occurred.");
|
|
74
|
+
pResponse.send('Loggso');
|
|
75
|
+
fNext();
|
|
76
|
+
}
|
|
77
|
+
);
|
|
78
|
+
_Orator.webServer.get (
|
|
79
|
+
'/PINataGOLo_promise',
|
|
80
|
+
async function (pRequest, pResponse)
|
|
64
81
|
{
|
|
65
82
|
return Promise.reject("Something absolutely dire has occurred.");
|
|
66
83
|
}
|
|
67
84
|
);
|
|
68
85
|
_Orator.startWebServer();
|
|
69
|
-
libSuperTest(
|
|
86
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
70
87
|
.get('PINGOLo')
|
|
71
88
|
.end(
|
|
72
89
|
function (pError, pResponse)
|
|
@@ -81,7 +98,7 @@ suite
|
|
|
81
98
|
Expect(pResponse.text)
|
|
82
99
|
.to.contain('Loggo');
|
|
83
100
|
}
|
|
84
|
-
libSuperTest(
|
|
101
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
85
102
|
.get('PINataGOLo')
|
|
86
103
|
.end(
|
|
87
104
|
function (pError, pResponse)
|
|
@@ -93,6 +110,8 @@ suite
|
|
|
93
110
|
}
|
|
94
111
|
else
|
|
95
112
|
{
|
|
113
|
+
Expect(pResponse.statusCode)
|
|
114
|
+
.to.equal(500);
|
|
96
115
|
Expect(pResponse.text)
|
|
97
116
|
.to.contain('dire');
|
|
98
117
|
}
|
|
@@ -107,11 +126,38 @@ suite
|
|
|
107
126
|
);
|
|
108
127
|
test
|
|
109
128
|
(
|
|
110
|
-
'
|
|
129
|
+
'uncaught exceptions should throw properly.',
|
|
111
130
|
function(fDone)
|
|
112
131
|
{
|
|
113
|
-
libSuperTest(
|
|
132
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
114
133
|
.get('PINataGOLo')
|
|
134
|
+
.end(
|
|
135
|
+
function (pError, pResponse)
|
|
136
|
+
{
|
|
137
|
+
if (pError)
|
|
138
|
+
{
|
|
139
|
+
console.log('Error on Logfile Results: '+JSON.stringify(pError));
|
|
140
|
+
Expect('Logged Request Error').to.equal('Nothing');
|
|
141
|
+
}
|
|
142
|
+
else
|
|
143
|
+
{
|
|
144
|
+
Expect(pResponse.statusCode)
|
|
145
|
+
.to.equal(500);
|
|
146
|
+
Expect(pResponse.text)
|
|
147
|
+
.to.contain('dire');
|
|
148
|
+
}
|
|
149
|
+
fDone();
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
test
|
|
155
|
+
(
|
|
156
|
+
'rejected promises should throw properly.',
|
|
157
|
+
function(fDone)
|
|
158
|
+
{
|
|
159
|
+
libSuperTest(`http://localhost:${_MockSettings.APIServerPort}/`)
|
|
160
|
+
.get('PINataGOLo_promise')
|
|
115
161
|
.end(
|
|
116
162
|
function (pError, pResponse)
|
|
117
163
|
{
|
|
@@ -133,4 +179,4 @@ suite
|
|
|
133
179
|
}
|
|
134
180
|
);
|
|
135
181
|
}
|
|
136
|
-
);
|
|
182
|
+
);
|
package/.vscode/launch.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Use IntelliSense to learn about possible attributes.
|
|
3
|
-
// Hover to view descriptions of existing attributes.
|
|
4
|
-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
-
"version": "0.2.0",
|
|
6
|
-
"configurations": [
|
|
7
|
-
{
|
|
8
|
-
"type": "node",
|
|
9
|
-
"request": "launch",
|
|
10
|
-
"name": "Mocha Tests",
|
|
11
|
-
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
|
|
12
|
-
"args": [
|
|
13
|
-
"-u",
|
|
14
|
-
"tdd",
|
|
15
|
-
"--bail",
|
|
16
|
-
"--timeout",
|
|
17
|
-
"999999",
|
|
18
|
-
"--colors",
|
|
19
|
-
"${workspaceFolder}/test/Orator_basic_tests.js",
|
|
20
|
-
"${workspaceFolder}/test/Orator_logging_tests.js",
|
|
21
|
-
"${workspaceFolder}/test/Orator-proxy_tests.js"
|
|
22
|
-
],
|
|
23
|
-
"internalConsoleOptions": "openOnSessionStart"
|
|
24
|
-
}
|
|
25
|
-
]
|
|
26
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the Orator Server
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
*
|
|
6
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
var Chai = require("chai");
|
|
10
|
-
var Expect = Chai.expect;
|
|
11
|
-
var Assert = Chai.assert;
|
|
12
|
-
|
|
13
|
-
var libSuperTest = require('supertest');
|
|
14
|
-
|
|
15
|
-
var _MockSettings = (
|
|
16
|
-
{
|
|
17
|
-
Product: 'MockOratorCHROMENOTRACE',
|
|
18
|
-
APIServerPort: 8083,
|
|
19
|
-
Profiling: (
|
|
20
|
-
{
|
|
21
|
-
// Tracelog is just log-based request timing encapsulation.
|
|
22
|
-
TraceLog: false,
|
|
23
|
-
|
|
24
|
-
// These profiling settings determine if we generate cpu or call graphs
|
|
25
|
-
Enabled: true,
|
|
26
|
-
Folder: '/tmp/',
|
|
27
|
-
// Currently supported profile types: CallGrinder or ChromeCPU
|
|
28
|
-
Type: 'ChromeCPU'
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
suite
|
|
34
|
-
(
|
|
35
|
-
'Orator',
|
|
36
|
-
function()
|
|
37
|
-
{
|
|
38
|
-
var _Orator;
|
|
39
|
-
|
|
40
|
-
setup
|
|
41
|
-
(
|
|
42
|
-
function()
|
|
43
|
-
{
|
|
44
|
-
_Orator = require('../source/Orator.js').new(_MockSettings);
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
suite
|
|
49
|
-
(
|
|
50
|
-
'Alternate (chromecpu) without Trace Server Start',
|
|
51
|
-
function()
|
|
52
|
-
{
|
|
53
|
-
test
|
|
54
|
-
(
|
|
55
|
-
'simple routes should work',
|
|
56
|
-
function(fDone)
|
|
57
|
-
{
|
|
58
|
-
_Orator.webServer.get (
|
|
59
|
-
'/PI',
|
|
60
|
-
function (pRequest, pResponse, fNext)
|
|
61
|
-
{
|
|
62
|
-
pResponse.send('PO');
|
|
63
|
-
fNext();
|
|
64
|
-
}
|
|
65
|
-
);
|
|
66
|
-
_Orator.startWebServer();
|
|
67
|
-
libSuperTest('http://localhost:8083/')
|
|
68
|
-
.get('PI')
|
|
69
|
-
.end(
|
|
70
|
-
function (pError, pResponse)
|
|
71
|
-
{
|
|
72
|
-
if (pError)
|
|
73
|
-
{
|
|
74
|
-
console.log('Error on Inverted Results: '+JSON.stringify(pError));
|
|
75
|
-
Expect('No Trace Request Error').to.equal('Nothing');
|
|
76
|
-
}
|
|
77
|
-
else
|
|
78
|
-
{
|
|
79
|
-
Expect(pResponse.text)
|
|
80
|
-
.to.contain('PO');
|
|
81
|
-
}
|
|
82
|
-
fDone();
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
);
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the Orator Server
|
|
3
|
-
*
|
|
4
|
-
* @license MIT
|
|
5
|
-
*
|
|
6
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
var Chai = require("chai");
|
|
10
|
-
var Expect = Chai.expect;
|
|
11
|
-
var Assert = Chai.assert;
|
|
12
|
-
|
|
13
|
-
var libSuperTest = require('supertest');
|
|
14
|
-
|
|
15
|
-
var _MockSettings = (
|
|
16
|
-
{
|
|
17
|
-
Product: 'MockOratorCHROME',
|
|
18
|
-
APIServerPort: 8081,
|
|
19
|
-
Profiling: (
|
|
20
|
-
{
|
|
21
|
-
// Tracelog is just log-based request timing encapsulation.
|
|
22
|
-
TraceLog: true,
|
|
23
|
-
|
|
24
|
-
// These profiling settings determine if we generate cpu or call graphs
|
|
25
|
-
Enabled: true,
|
|
26
|
-
Folder: '/tmp/',
|
|
27
|
-
// Currently supported profile types: CallGrinder or ChromeCPU
|
|
28
|
-
Type: 'ChromeCPU'
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
suite
|
|
34
|
-
(
|
|
35
|
-
'Orator',
|
|
36
|
-
function()
|
|
37
|
-
{
|
|
38
|
-
var _Orator;
|
|
39
|
-
|
|
40
|
-
setup
|
|
41
|
-
(
|
|
42
|
-
function()
|
|
43
|
-
{
|
|
44
|
-
_Orator = require('../source/Orator.js').new(_MockSettings);
|
|
45
|
-
}
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
suite
|
|
49
|
-
(
|
|
50
|
-
'Alternate (chromecpu) Server Start',
|
|
51
|
-
function()
|
|
52
|
-
{
|
|
53
|
-
test
|
|
54
|
-
(
|
|
55
|
-
'simple routes should work',
|
|
56
|
-
function(fDone)
|
|
57
|
-
{
|
|
58
|
-
_Orator.webServer.get (
|
|
59
|
-
'/PINGO',
|
|
60
|
-
function (pRequest, pResponse, fNext)
|
|
61
|
-
{
|
|
62
|
-
let tmpMemory = false;
|
|
63
|
-
for (var i = 0; i < 1000; i++)
|
|
64
|
-
{
|
|
65
|
-
tmpMemory = process.memoryUsage();
|
|
66
|
-
}
|
|
67
|
-
pResponse.send('PONGO');
|
|
68
|
-
fNext();
|
|
69
|
-
}
|
|
70
|
-
);
|
|
71
|
-
_Orator.startWebServer();
|
|
72
|
-
libSuperTest('http://localhost:8081/')
|
|
73
|
-
.get('PINGO')
|
|
74
|
-
.end(
|
|
75
|
-
function (pError, pResponse)
|
|
76
|
-
{
|
|
77
|
-
if (pError)
|
|
78
|
-
{
|
|
79
|
-
console.log('Error on Inverted Results: '+JSON.stringify(pError));
|
|
80
|
-
Expect('Chrome Trace Request Error').to.equal('Nothing');
|
|
81
|
-
}
|
|
82
|
-
else
|
|
83
|
-
{
|
|
84
|
-
Expect(pResponse.text)
|
|
85
|
-
.to.contain('PONGO');
|
|
86
|
-
}
|
|
87
|
-
fDone();
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
);
|