PageRenderTime 17ms CodeModel.GetById 20ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 1ms

/node_modules/newrelic/test/error.test.js

https://github.com/markba/bashhistory.io
JavaScript | 796 lines | 182 code | 61 blank | 553 comment | 3 complexity | 93160ec5284635574ff7f25d32e7b8a1 MD5 | raw file
  1'use strict';
  2
  3var path         = require('path')
  4  , chai         = require('chai')
  5  , expect       = chai.expect
  6  , should       = chai.should()
  7  , helper       = require(path.join(__dirname, 'lib', 'agent_helper'))
  8  , config       = require(path.join(__dirname, '..', 'lib', 'config.default'))
  9  , ErrorTracer  = require(path.join(__dirname, '..', 'lib', 'error'))
 10  , Transaction  = require(path.join(__dirname, '..', 'lib', 'transaction'))
 11  ;
 12
 13function createTransaction(agent, code) {
 14  var transaction = new Transaction(agent);
 15  transaction.name = 'WebTransaction/TestJS/path';
 16  transaction.statusCode = code;
 17
 18  return transaction;
 19}
 20
 21describe("ErrorTracer", function () {
 22  var tracer;
 23
 24  beforeEach(function () {
 25    tracer = new ErrorTracer(config.config);
 26  });
 27
 28  it("shouldn't gather errors if it's switched off by config", function () {
 29    var error = new Error('this error will never be seen');
 30    config.config.error_collector.enabled = false;
 31
 32    expect(tracer.errorCount).equal(0);
 33    expect(tracer.errors.length).equal(0);
 34
 35    tracer.add(null, error);
 36
 37    expect(tracer.errorCount).equal(1);
 38    expect(tracer.errors.length).equal(0);
 39
 40    config.config.error_collector.enabled = true;
 41  });
 42
 43  it("shouldn't gather errors if it's switched off by config", function () {
 44    var error = new Error('this error will never be seen');
 45    config.config.collect_errors = false;
 46
 47    expect(tracer.errorCount).equal(0);
 48    expect(tracer.errors.length).equal(0);
 49
 50    tracer.add(null, error);
 51
 52    expect(tracer.errorCount).equal(1);
 53    expect(tracer.errors.length).equal(0);
 54
 55    config.config.collect_errors = true;
 56  });
 57
 58  it("should retain a maximum of 20 errors to send", function () {
 59    for (var i = 0; i < 5; i++) tracer.add(null, new Error('filling the queue'));
 60    expect(tracer.errors.length).equal(5);
 61
 62    for (i = 0; i < 5; i++) tracer.add(null, new Error('more filling the queue'));
 63    expect(tracer.errors.length).equal(10);
 64
 65    // this will take the tracer 3 over the limit of 20
 66    for (i = 0; i < 13; i++) tracer.add(null, new Error('overfilling the queue'));
 67    expect(tracer.errorCount).equal(23);
 68    expect(tracer.errors.length).equal(20);
 69  });
 70
 71  describe("when finalizing transactions", function () {
 72    var agent;
 73
 74    beforeEach(function () {
 75      agent = helper.loadMockedAgent();
 76    });
 77
 78    afterEach(function () {
 79      helper.unloadAgent(agent);
 80    });
 81
 82    it("should capture errors for transactions ending in error", function () {
 83      tracer.onTransactionFinished(createTransaction(agent, 400), agent.metrics);
 84      tracer.onTransactionFinished(createTransaction(agent, 500), agent.metrics);
 85
 86      expect(tracer.errors.length).equal(2);
 87    });
 88
 89    it("should count errors on the error tracer", function () {
 90      tracer.onTransactionFinished(createTransaction(agent, 400), agent.metrics);
 91      tracer.onTransactionFinished(createTransaction(agent, 500), agent.metrics);
 92
 93      expect(tracer.errorCount).equal(2);
 94    });
 95
 96    it("should count named errors on the agent metrics", function () {
 97      tracer.onTransactionFinished(createTransaction(agent, 400), agent.metrics);
 98      tracer.onTransactionFinished(createTransaction(agent, 500), agent.metrics);
 99
100      var metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path');
101      expect(metric.callCount).equal(2);
102    });
103
104    it("should ignore 404 errors for transactions", function () {
105      tracer.onTransactionFinished(createTransaction(agent, 400), agent.metrics);
106      // 404 errors are ignored by default
107      tracer.onTransactionFinished(createTransaction(agent, 404), agent.metrics);
108      tracer.onTransactionFinished(createTransaction(agent, 404), agent.metrics);
109      tracer.onTransactionFinished(createTransaction(agent, 404), agent.metrics);
110      tracer.onTransactionFinished(createTransaction(agent, 404), agent.metrics);
111
112      expect(tracer.errorCount).equal(1);
113    });
114
115    it("should ignore 404 errors for transactions with exceptions attached", function () {
116      tracer.onTransactionFinished(createTransaction(agent, 400), agent.metrics);
117      // 404 errors are ignored by default
118      var special = createTransaction(agent, 404);
119      special.exceptions.push(new Error('ignored'));
120      tracer.onTransactionFinished(special, agent.metrics);
121
122      expect(tracer.errorCount).equal(1);
123    });
124  });
125
126  describe("with no exception and no transaction", function () {
127    var agent;
128
129    beforeEach(function () {
130      agent = helper.loadMockedAgent();
131      var tracer = agent.errors;
132
133      tracer.add(new Transaction(agent), null);
134    });
135
136    afterEach(function () {
137      helper.unloadAgent(agent);
138    });
139
140    it("should have no errors", function () {
141      agent.errors.add(null, null);
142      expect(agent.errors.errors.length).equal(0);
143    });
144  });
145
146  describe("with no error and a transaction with status code", function () {
147    var agent
148      , tracer
149      ;
150
151    beforeEach(function () {
152      agent = helper.loadMockedAgent();
153      tracer = agent.errors;
154
155      tracer.add(new Transaction (agent), null);
156    });
157
158    afterEach(function () {
159      helper.unloadAgent(agent);
160    });
161
162    it("should have no errors", function () {
163      expect(tracer.errors.length).equal(0);
164    });
165  });
166
167  describe("with no error and a transaction with a status code", function () {
168    var agent
169      , tracer
170      , errorJSON
171      ;
172
173    beforeEach(function () {
174      agent = helper.loadMockedAgent();
175      tracer = agent.errors;
176
177      var transaction = new Transaction (agent);
178      transaction.statusCode = 503; // PDX wut wut
179
180      tracer.add(transaction, null);
181      errorJSON = tracer.errors[0];
182    });
183
184    afterEach(function () {
185      helper.unloadAgent(agent);
186    });
187
188    it("should have one error", function () {
189      expect(tracer.errors.length).equal(1);
190    });
191
192    it("shouldn't care what time it was traced", function () {
193      expect(errorJSON[0]).equal(0);
194    });
195
196    it("should have the default scope", function () {
197      expect(errorJSON[1]).equal('WebTransaction/Uri/*');
198    });
199
200    it("should have an HTTP status code error message", function () {
201      expect(errorJSON[2]).equal('HttpError 503');
202    });
203
204    it("should default to a type of Error", function () {
205      expect(errorJSON[3]).equal('Error');
206    });
207
208    it("should not have a stack trace in the params", function () {
209      var params = errorJSON[4];
210      should.not.exist(params.stack_trace);
211    });
212  });
213
214  describe("with no error and a transaction with an URL and status code", function () {
215    var agent
216      , tracer
217      , errorJSON
218      , params
219      ;
220
221    beforeEach(function () {
222      agent = helper.loadMockedAgent();
223      agent.config.capture_params = true;
224      tracer = agent.errors;
225
226      var transaction = new Transaction(agent);
227      transaction.statusCode = 501;
228
229      transaction.url = '/test_action.json?test_param=a%20value&thing';
230
231      tracer.add(transaction, null);
232      errorJSON = tracer.errors[0];
233      params = errorJSON[4];
234    });
235
236    afterEach(function () {
237      helper.unloadAgent(agent);
238    });
239
240    it("should have one error", function () {
241      expect(tracer.errors.length).equal(1);
242    });
243
244    it("shouldn't care what time it was traced", function () {
245      expect(errorJSON[0]).equal(0);
246    });
247
248    it("should have the URL's scope", function () {
249      expect(errorJSON[1]).equal('WebTransaction/NormalizedUri/*');
250    });
251
252    it("should have an HTTP status code message", function () {
253      expect(errorJSON[2]).equal("HttpError 501");
254    });
255
256    it("should default to  a type of Error", function () {
257      expect(errorJSON[3]).equal('Error');
258    });
259
260    it("should not have a stack trace in the params", function () {
261      should.not.exist(params.stack_trace);
262    });
263
264    it("should have a request URL", function () {
265      expect(params.request_uri = '/test_action.json');
266    });
267
268    it("should parse out the first URL parameter", function () {
269      expect(params.request_params.test_param).equal('a value');
270    });
271
272    it("should parse out the other URL parameter", function () {
273      expect(params.request_params.thing).equal(true);
274    });
275  });
276
277  describe("with capture_params disabled", function () {
278    var agent = helper.loadMockedAgent();
279    agent.config.capture_params = false;
280    var tracer = agent.errors;
281
282    var transaction = new Transaction(agent);
283    transaction.statusCode = 501;
284
285    transaction.url = '/test_action.json?test_param=a%20value&thing';
286
287    tracer.add(transaction, null);
288    var errorJSON = tracer.errors[0];
289    var params = errorJSON[4];
290
291    should.not.exist(params.request_params);
292    helper.unloadAgent(agent);
293  });
294
295  describe("with capture_params enabled and ignored_params set", function () {
296    var agent = helper.loadMockedAgent();
297    agent.config.capture_params = true;
298    agent.config.ignored_params = ['thing'];
299    var tracer = agent.errors;
300
301    var transaction = new Transaction(agent);
302    transaction.statusCode = 501;
303
304    transaction.url = '/test_action.json?test_param=a%20value&thing';
305
306    tracer.add(transaction, null);
307    var errorJSON = tracer.errors[0];
308    var params = errorJSON[4];
309
310    expect(params.request_params).eql({test_param : 'a value'});
311    helper.unloadAgent(agent);
312  });
313
314  describe("with a thrown TypeError object and no transaction", function () {
315    var agent
316      , tracer
317      , errorJSON
318      ;
319
320    beforeEach(function () {
321      agent = helper.loadMockedAgent();
322      tracer = agent.errors;
323
324      var exception = new Error('Dare to be the same!');
325
326      tracer.add(null, exception);
327      errorJSON = tracer.errors[0];
328    });
329
330    afterEach(function () {
331      helper.unloadAgent(agent);
332    });
333
334    it("should have one error", function () {
335      expect(tracer.errors.length).equal(1);
336    });
337
338    it("shouldn't care what time it was traced", function () {
339      expect(errorJSON[0]).equal(0);
340    });
341
342    it("should have the default scope", function () {
343      expect(errorJSON[1]).equal('WebTransaction/Uri/*');
344    });
345
346    it("should fish the message out of the exception", function () {
347      expect(errorJSON[2]).equal("Dare to be the same!");
348    });
349
350    it("should have a type of TypeError", function () {
351      expect(errorJSON[3]).equal('Error');
352    });
353
354    it("should have a stack trace in the params", function () {
355      var params = errorJSON[4];
356      should.exist(params.stack_trace);
357      expect(params.stack_trace[0]).equal("Error: Dare to be the same!");
358    });
359  });
360
361  describe("with a thrown TypeError object and a transaction with no URL", function () {
362    var agent
363      , tracer
364      , errorJSON
365      ;
366
367    beforeEach(function () {
368      agent = helper.loadMockedAgent();
369      tracer = agent.errors;
370
371      var transaction = new Transaction(agent)
372        , exception   = new TypeError('Dare to be different!')
373        ;
374
375      tracer.add(transaction, exception);
376      errorJSON = tracer.errors[0];
377    });
378
379    afterEach(function () {
380      helper.unloadAgent(agent);
381    });
382
383    it("should have one error", function () {
384      expect(tracer.errors.length).equal(1);
385    });
386
387    it("shouldn't care what time it was traced", function () {
388      expect(errorJSON[0]).equal(0);
389    });
390
391    it("should have the default scope", function () {
392      expect(errorJSON[1]).equal('WebTransaction/Uri/*');
393    });
394
395    it("should fish the message out of the exception", function () {
396      expect(errorJSON[2]).equal("Dare to be different!");
397    });
398
399    it("should have a type of TypeError", function () {
400      expect(errorJSON[3]).equal('TypeError');
401    });
402
403    it("should have a stack trace in the params", function () {
404      var params = errorJSON[4];
405      should.exist(params.stack_trace);
406      expect(params.stack_trace[0]).equal("TypeError: Dare to be different!");
407    });
408  });
409
410  describe("with a thrown TypeError object and a transaction with an URL", function () {
411    var agent
412      , tracer
413      , errorJSON
414      , params
415      ;
416
417    beforeEach(function () {
418      agent = helper.loadMockedAgent();
419      agent.config.capture_params = true;
420      tracer = agent.errors;
421
422      var transaction = new Transaction(agent)
423        , exception   = new TypeError('wanted JSON, got XML')
424        ;
425
426      transaction.url = '/test_action.json?test_param=a%20value&thing';
427
428      tracer.add(transaction, exception);
429      errorJSON = tracer.errors[0];
430      params = errorJSON[4];
431    });
432
433    afterEach(function () {
434      helper.unloadAgent(agent);
435    });
436
437    it("should have one error", function () {
438      expect(tracer.errors.length).equal(1);
439    });
440
441    it("shouldn't care what time it was traced", function () {
442      expect(errorJSON[0]).equal(0);
443    });
444
445    it("should have the URL's scope", function () {
446      expect(errorJSON[1]).equal('WebTransaction/NormalizedUri/*');
447    });
448
449    it("should fish the message out of the exception", function () {
450      expect(errorJSON[2]).equal("wanted JSON, got XML");
451    });
452
453    it("should have a type of TypeError", function () {
454      expect(errorJSON[3]).equal('TypeError');
455    });
456
457    it("should have a stack trace in the params", function () {
458      should.exist(params.stack_trace);
459      expect(params.stack_trace[0]).equal("TypeError: wanted JSON, got XML");
460    });
461
462    it("should have a request URL", function () {
463      expect(params.request_uri = '/test_action.json');
464    });
465
466    it("should parse out the first URL parameter", function () {
467      expect(params.request_params.test_param).equal('a value');
468    });
469
470    it("should parse out the other URL parameter", function () {
471      expect(params.request_params.thing).equal(true);
472    });
473  });
474
475  describe("with a thrown string and a transaction with no URL", function () {
476    var agent
477      , tracer
478      , errorJSON
479      ;
480
481    beforeEach(function () {
482      agent = helper.loadMockedAgent();
483      tracer = agent.errors;
484
485      var transaction = new Transaction(agent)
486        , exception   = 'Dare to be different!'
487        ;
488
489      tracer.add(transaction, exception);
490      errorJSON = tracer.errors[0];
491    });
492
493    afterEach(function () {
494      helper.unloadAgent(agent);
495    });
496
497    it("should have one error", function () {
498      expect(tracer.errors.length).equal(1);
499    });
500
501    it("shouldn't care what time it was traced", function () {
502      expect(errorJSON[0]).equal(0);
503    });
504
505    it("should have the default scope", function () {
506      expect(errorJSON[1]).equal('WebTransaction/Uri/*');
507    });
508
509    it("should turn the string into the message", function () {
510      expect(errorJSON[2]).equal("Dare to be different!");
511    });
512
513    it("should default to a type of Error", function () {
514      expect(errorJSON[3]).equal('Error');
515    });
516
517    it("should have no stack trace", function () {
518      should.not.exist(errorJSON[4].stack_trace);
519    });
520  });
521
522  describe("with a thrown string and a transaction with an URL", function () {
523    var agent
524      , tracer
525      , errorJSON
526      , params
527      ;
528
529    beforeEach(function () {
530      agent = helper.loadMockedAgent();
531      agent.config.capture_params = true;
532      tracer = agent.errors;
533
534      var transaction = new Transaction(agent)
535        , exception   = 'wanted JSON, got XML'
536        ;
537
538      transaction.url = '/test_action.json?test_param=a%20value&thing';
539
540      tracer.add(transaction, exception);
541      errorJSON = tracer.errors[0];
542      params = errorJSON[4];
543    });
544
545    afterEach(function () {
546      helper.unloadAgent(agent);
547    });
548
549    it("should have one error", function () {
550      expect(tracer.errors.length).equal(1);
551    });
552
553    it("shouldn't care what time it was traced", function () {
554      expect(errorJSON[0]).equal(0);
555    });
556
557    it("should have the transaction's name", function () {
558      expect(errorJSON[1]).equal('WebTransaction/NormalizedUri/*');
559    });
560
561    it("should turn the string into the message", function () {
562      expect(errorJSON[2]).equal("wanted JSON, got XML");
563    });
564
565    it("should default to a type of Error", function () {
566      expect(errorJSON[3]).equal('Error');
567    });
568
569    it("should not have a stack trace in the params", function () {
570      should.not.exist(params.stack_trace);
571    });
572
573    it("should have a request URL", function () {
574      expect(params.request_uri = '/test_action.json');
575    });
576
577    it("should parse out the first URL parameter", function () {
578      expect(params.request_params.test_param).equal('a value');
579    });
580
581    it("should parse out the other URL parameter", function () {
582      expect(params.request_params.thing).equal(true);
583    });
584  });
585
586  describe("with an internal server error (500) and an exception", function () {
587    var agent
588      , name = 'WebTransaction/Uri/test-request/zxrkbl'
589      , error
590      ;
591
592    beforeEach(function () {
593      agent = helper.loadMockedAgent();
594      tracer = agent.errors;
595
596      var transaction = new Transaction(agent)
597        , exception   = new Error('500 test error')
598        ;
599
600      transaction.exceptions.push(exception);
601      transaction.url = '/test-request/zxrkbl';
602      transaction.name = 'WebTransaction/Uri/test-request/zxrkbl';
603      transaction.statusCode = 500;
604      transaction.end();
605
606      error = tracer.errors[0];
607    });
608
609    afterEach(function () {
610      helper.unloadAgent(agent);
611    });
612
613    it("should associate errors with the transaction's name", function () {
614      var errorName = error[1];
615
616      expect(errorName).equal(name);
617    });
618
619    it("should associate errors with a message", function () {
620      var message = error[2];
621
622      expect(message).match(/500 test error/);
623    });
624
625    it("should associate errors with a message class", function () {
626      var messageClass = error[3];
627
628      expect(messageClass).equal('Error');
629    });
630
631    it("should associate errors with parameters", function () {
632      var params = error[4];
633
634      should.exist(params);
635      expect(Object.keys(params).length).equal(2);
636      expect(params.request_uri).equal("/test-request/zxrkbl");
637
638      should.exist(params.stack_trace);
639      expect(params.stack_trace[0]).equal("Error: 500 test error");
640    });
641  });
642
643  describe("with a tracer unavailable (503) error", function () {
644    var agent
645      , name = 'WebTransaction/Uri/test-request/zxrkbl'
646      , error
647      ;
648
649    beforeEach(function () {
650      agent = helper.loadMockedAgent();
651      tracer = agent.errors;
652
653      var transaction = new Transaction(agent);
654      transaction.url = '/test-request/zxrkbl';
655      transaction.name = 'WebTransaction/Uri/test-request/zxrkbl';
656      transaction.statusCode = 503;
657      transaction.end();
658
659      error = tracer.errors[0];
660    });
661
662    afterEach(function () {
663      helper.unloadAgent(agent);
664    });
665
666    it("should associate errors with the transaction's name", function () {
667      var errorName = error[1];
668
669      expect(errorName).equal(name);
670    });
671
672    it("should associate errors with a message", function () {
673      var message = error[2];
674
675      expect(message).equal('HttpError 503');
676    });
677
678    it("should associate errors with an error type", function () {
679      var messageClass = error[3];
680
681      expect(messageClass).equal('Error');
682    });
683
684    it("should associate errors with parameters", function () {
685      var params = error[4];
686
687      expect(params).deep.equal({request_uri : "/test-request/zxrkbl"});
688    });
689  });
690
691  describe("when merging from failed collector delivery", function () {
692    it("shouldn't crash on null errors", function () {
693      expect(function () { tracer.merge(null); }).not.throws();
694    });
695
696    it("should never merge more than 20 errors", function () {
697      var sample = [0, 'WebTransaction/Uri/*', 'something bad happened', 'Error', {}];
698      var errors = [];
699      for (var i = 0; i < 30; i++) errors.push(sample);
700
701      tracer.merge(errors);
702
703      expect(tracer.errors.length).equal(20);
704    });
705  });
706
707  describe("when using the async listener", function () {
708    var mochaHandlers
709      , agent
710      , transaction
711      , active
712      , json
713      ;
714
715    before(function (done) {
716      agent = helper.loadMockedAgent();
717
718      /**
719       * Mocha is extremely zealous about trapping errors, and runs each test
720       * in a try / catch block. To get the exception to propagate out to the
721       * domain's uncaughtException handler, we need to put the test in an
722       * asynchronous context and break out of the mocha jail.
723       */
724      process.nextTick(function cb_nextTick() {
725        // disable mocha's error handler
726        mochaHandlers = helper.onlyDomains();
727
728        process.once('uncaughtException', function () {
729          json = agent.errors.errors[0];
730
731          return done();
732        });
733
734        var disruptor = agent.tracer.transactionProxy(function cb_transactionProxy() {
735          transaction = agent.getTransaction();
736          active = process.domain;
737
738          // trigger the error handler
739          throw new Error('sample error');
740        });
741
742        disruptor();
743      });
744    });
745
746    after(function () {
747      // ...but be sure to re-enable mocha's error handler
748      transaction.end();
749      helper.unloadAgent(agent);
750      process._events['uncaughtException'] = mochaHandlers;
751    });
752
753    it("should not have a domain active", function () {
754      should.not.exist(active);
755    });
756
757    it("should find a single error", function () {
758      expect(agent.errors.errors.length).equal(1);
759    });
760
761    describe("and an error is traced", function () {
762      it("should find the error", function () {
763        should.exist(json);
764      });
765
766      it("should have 5 elements in the trace", function () {
767        expect(json.length).equal(5);
768      });
769
770      it("should always have a 0 (ignored) timestamp", function () {
771        expect(json[0]).equal(0);
772      });
773
774      it("should have the default name", function () {
775        expect(json[1]).equal('WebTransaction/Uri/*');
776      });
777
778      it("should have the error's message", function () {
779        expect(json[2]).equal('sample error');
780      });
781
782      it("should have the error's constructor name (type)", function () {
783        expect(json[3]).equal('Error');
784      });
785
786      it("should default to passing the stack trace as a parameter", function () {
787        var params = json[4];
788
789        should.exist(params);
790        expect(Object.keys(params).length).equal(1);
791        should.exist(params.stack_trace);
792        expect(params.stack_trace[0]).equal("Error: sample error");
793      });
794    });
795  });
796});