PageRenderTime 44ms CodeModel.GetById 10ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/hayes/framework
JavaScript | 297 lines | 214 code | 72 blank | 11 comment | 4 complexity | 16441e4226b2bea6205c7318e7296e14 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  , dominion     = require(path.join(__dirname, '..', 'lib', 'dominion'))
 10  , ErrorTracer  = require(path.join(__dirname, '..', 'lib', 'error'))
 11  , Transaction  = require(path.join(__dirname, '..', 'lib', 'transaction'))
 12  ;
 13
 14function createTransaction(code) {
 15  return { statusCode : code, exceptions : [] };
 16}
 17
 18describe("ErrorTracer", function () {
 19  var service;
 20
 21  beforeEach(function () {
 22    service = new ErrorTracer(config.config);
 23  });
 24
 25  it("shouldn't gather errors if it's switched off", function () {
 26    var error = new Error('this error will never be seen');
 27    service.config.error_collector.enabled = false;
 28
 29    expect(service.errorCount).equal(0);
 30    expect(service.errors.length).equal(0);
 31
 32    service.add(error);
 33
 34    expect(service.errorCount).equal(1);
 35    expect(service.errors.length).equal(0);
 36
 37    service.config.error_collector.enabled = true;
 38  });
 39
 40  it("should retain a maximum of 20 errors to send", function () {
 41    for (var i = 0; i < 5; i++) service.add(null, new Error('filling the queue'));
 42    expect(service.errors.length).equal(5);
 43
 44    for (i = 0; i < 5; i++) service.add(null, new Error('more filling the queue'));
 45    expect(service.errors.length).equal(10);
 46
 47    // this will take the tracer 3 over the limit of 20
 48    for (i = 0; i < 13; i++) service.add(null, new Error('overfilling the queue'));
 49    expect(service.errorCount).equal(23);
 50    expect(service.errors.length).equal(20);
 51  });
 52
 53  it("should handle errors properly for transactions", function () {
 54    service.onTransactionFinished(createTransaction(400));
 55    service.onTransactionFinished(createTransaction(500));
 56
 57    expect(service.errors.length).equal(2);
 58    expect(service.errorCount).equal(2);
 59  });
 60
 61  it("should ignore 404 errors for transactions", function () {
 62    service.onTransactionFinished(createTransaction(400));
 63    // 404 errors are ignored by default
 64    service.onTransactionFinished(createTransaction(404));
 65    service.onTransactionFinished(createTransaction(404));
 66    service.onTransactionFinished(createTransaction(404));
 67    service.onTransactionFinished(createTransaction(404));
 68
 69    expect(service.errorCount).equal(1);
 70  });
 71
 72  describe("with an internal server error (500) and an exception", function () {
 73    var agent
 74      , scope
 75      , error
 76      ;
 77
 78    beforeEach(function () {
 79      agent = helper.loadMockedAgent();
 80      service = agent.errors;
 81
 82      var transaction = new Transaction(agent)
 83        , exception   = new Error('500 test error')
 84        ;
 85
 86      transaction.exceptions.push(exception);
 87      scope = transaction.measureWeb('/test-request/zxrkbl', 500, 5, 5);
 88      transaction.end();
 89
 90      error = service.errors[0];
 91    });
 92
 93    afterEach(function () {
 94      helper.unloadAgent(agent);
 95    });
 96
 97    it("should properly reset when finished", function () {
 98      expect(service.errorCount).equal(1);
 99
100      service.clear();
101      expect(service.errorCount).equal(0);
102    });
103
104    it("should associate errors with the transaction's scope", function () {
105      var errorScope = error[1];
106
107      expect(errorScope).equal(scope);
108    });
109
110    it("should associate errors with a message", function () {
111      var message = error[2];
112
113      expect(message).match(/500 test error/);
114    });
115
116    it("should associate errors with a message class", function () {
117      var messageClass = error[3];
118
119      expect(messageClass).equal('Error');
120    });
121
122    it("should associate errors with parameters", function () {
123      var params = error[4];
124
125      expect(params).eql({request_uri : "/test-request/zxrkbl"});
126    });
127  });
128
129  describe("with a service unavailable (503) error", function () {
130    var agent
131      , scope
132      , error
133      ;
134
135    beforeEach(function () {
136      agent = helper.loadMockedAgent();
137      service = agent.errors;
138
139      var transaction = new Transaction(agent);
140      scope = transaction.measureWeb('/test-request/zxrkbl', 503, 5, 5);
141      transaction.end();
142
143      error = service.errors[0];
144    });
145
146    afterEach(function () {
147      helper.unloadAgent(agent);
148    });
149
150    it("should properly reset when finished", function () {
151      expect(service.errorCount).equal(1);
152
153      service.clear();
154      expect(service.errorCount).equal(0);
155    });
156
157    it("should associate errors with the transaction's scope", function () {
158      var errorScope = error[1];
159
160      expect(errorScope).equal(scope);
161    });
162
163    it("should associate errors with a message", function () {
164      var message = error[2];
165
166      expect(message).equal('HttpError 503');
167    });
168
169    it("should associate errors with a message class", function () {
170      var messageClass = error[3];
171
172      expect(messageClass).equal('HttpError 503');
173    });
174
175    it("should associate errors with parameters", function () {
176      var params = error[4];
177
178      expect(params).deep.equal({request_uri : "/test-request/zxrkbl"});
179    });
180  });
181
182  describe("when monitoring function application for errors", function () {
183    var transaction;
184
185    beforeEach(function () {
186      var agent = helper.loadMockedAgent();
187      transaction = new Transaction(agent);
188    });
189
190    it("should rethrow the exception", function () {
191      var testFunction = function () {
192        var uninitialized;
193        uninitialized.explosion.happens.here = "fabulous";
194      };
195
196      expect(function () {
197        service.monitor(testFunction, transaction);
198      }).throws(TypeError);
199    });
200
201    it("should return the correct value", function () {
202      var safeFunction = function (val) {
203        return val * val;
204      };
205
206      expect(service.monitor(safeFunction.bind(null, 3), transaction)).equal(9);
207    });
208  });
209
210  if (dominion.available) {
211    describe("when domains are available", function () {
212      var mochaHandlers
213        , agent
214        , domain
215        , active
216        , json
217        ;
218
219      before(function (done) {
220        agent = helper.loadMockedAgent();
221
222        /**
223         * Mocha is extremely zealous about trapping errors, and runs each test
224         * in a try / catch block. To get the exception to propagate out to the
225         * domain's uncaughtException handler, we need to put the test in an
226         * asynchronous context and break out of the mocha jail.
227         */
228        process.nextTick(function () {
229          // disable mocha's error handler
230          mochaHandlers = helper.onlyDomains();
231
232          process.once('uncaughtException', function () {
233            json = agent.errors.errors[0];
234
235            return done();
236          });
237
238          var disruptor = agent.tracer.transactionProxy(function () {
239            domain = agent.getTransaction().trace.domain;
240            active = process.domain;
241
242            // trigger the domain
243            throw new Error('sample error');
244          });
245
246          disruptor();
247        });
248      });
249
250      after(function () {
251        // ...but be sure to re-enable mocha's error handler
252        process._events['uncaughtException'] = mochaHandlers;
253      });
254
255      it("should put transactions in domains", function () {
256        should.exist(domain);
257        should.exist(active);
258        expect(domain).equal(active);
259      });
260
261      it("should find a single error", function () {
262        expect(agent.errors.errors.length).equal(1);
263      });
264
265      describe("when handed an error from a domain", function () {
266        it("should find the error", function () {
267          should.exist(json);
268        });
269
270        it("should have 5 elements in the trace", function () {
271          expect(json.length).equal(5);
272        });
273
274        it("should always have a 0 (ignored) timestamp", function () {
275          expect(json[0]).equal(0);
276        });
277
278        it("should have the default ('Unknown') scope", function () {
279          expect(json[1]).equal('Unknown');
280        });
281
282        it("should have the error's message", function () {
283          expect(json[2]).match(/^Error: sample error/);
284        });
285
286        it("should have the error's constructor name (class)", function () {
287          expect(json[3]).equal('Error');
288        });
289
290        it("should default to empty parameters", function () {
291          expect(json[4]).deep.equal({});
292        });
293      });
294    });
295
296  }
297});