PageRenderTime 60ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

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