From 3ad54136c9cc5755b82fee9333552010eb8596bf Mon Sep 17 00:00:00 2001 From: James Sumners Date: Fri, 6 Sep 2024 13:35:13 -0400 Subject: [PATCH] chore: Converted errors unit tests to node:test (#2540) Co-authored-by: Bob Evans --- lib/config/index.js | 2 +- test/unit/errors/error-collector.test.js | 2789 ++++++++--------- .../errors/error-event-aggregator.test.js | 88 +- test/unit/errors/error-group.test.js | 165 +- .../errors/error-trace-aggregator.test.js | 129 +- test/unit/errors/expected.test.js | 278 +- test/unit/errors/ignore.test.js | 202 +- test/unit/errors/server-config.test.js | 175 +- 8 files changed, 1866 insertions(+), 1962 deletions(-) diff --git a/lib/config/index.js b/lib/config/index.js index 62c77d1706..24d9f3d97a 100644 --- a/lib/config/index.js +++ b/lib/config/index.js @@ -839,7 +839,7 @@ Config.prototype.logUnknown = function logUnknown(json, key) { /** * Gets the user set host display name. If not provided, it returns the default value. * - * This function is written is this strange way because of the use of caching variables. + * This function is written in this strange way because of the use of caching variables. * I wanted to cache the DisplayHost, but if I attached the variable to the config object, * it sends the extra variable to New Relic, which is not desired. * diff --git a/test/unit/errors/error-collector.test.js b/test/unit/errors/error-collector.test.js index b35b92e1db..d6d87e984a 100644 --- a/test/unit/errors/error-collector.test.js +++ b/test/unit/errors/error-collector.test.js @@ -1,13 +1,14 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') -const test = tap.test +const test = require('node:test') +const assert = require('node:assert') +const { match } = require('../../lib/custom-assertions') const helper = require('../../lib/agent_helper') const Exception = require('../../../lib/errors').Exception const ErrorCollector = require('../../../lib/errors/error-collector') @@ -20,6 +21,7 @@ const Metrics = require('../../../lib/metrics') const API = require('../../../api') const DESTS = require('../../../lib/config/attribute-filter').DESTINATIONS const NAMES = require('../../../lib/metrics/names') +const http = require('http') function createTransaction(agent, code, isWeb) { if (typeof isWeb === 'undefined') { @@ -47,709 +49,664 @@ function createBackgroundTransaction(agent) { return createTransaction(agent, null, false) } -tap.test('Errors', (t) => { - t.autoend() - let agent = null +function getErrorTraces(errorCollector) { + return errorCollector.traceAggregator.errors +} - t.beforeEach(() => { - if (agent) { - helper.unloadAgent(agent) - } - agent = helper.loadMockedAgent({ - attributes: { - enabled: true - } - }) - }) +function getErrorEvents(errorCollector) { + return errorCollector.eventAggregator.getEvents() +} - t.afterEach(() => { - helper.unloadAgent(agent) - }) +function getFirstErrorIntrinsicAttributes(aggregator) { + return getFirstError(aggregator)[4].intrinsics +} + +function getFirstErrorCustomAttributes(aggregator) { + return getFirstError(aggregator)[4].userAttributes +} + +function getFirstError(aggregator) { + const errors = getErrorTraces(aggregator) + assert.equal(errors.length, 1) + return errors[0] +} + +function getFirstEventIntrinsicAttributes(aggregator) { + return getFirstEvent(aggregator)[0] +} + +function getFirstEventCustomAttributes(aggregator) { + return getFirstEvent(aggregator)[1] +} + +function getFirstEventAgentAttributes(aggregator) { + return getFirstEvent(aggregator)[2] +} + +function getFirstEvent(aggregator) { + const events = getErrorEvents(aggregator) + assert.equal(events.length, 1) + return events[0] +} + +test('Errors', async (t) => { + function beforeEach(ctx) { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent({ attributes: { enabled: true } }) + + ctx.nr.tx = new Transaction(ctx.nr.agent) + ctx.nr.tx.url = '/' + + ctx.nr.errors = ctx.nr.agent.errors + } + + function afterEach(ctx) { + helper.unloadAgent(ctx.nr.agent) + } - t.test('agent attribute format', (t) => { - t.autoend() + await t.test('agent attribute format', async (t) => { const PARAMS = 4 - let trans = null - let error = null - t.beforeEach(() => { - trans = new Transaction(agent) - trans.url = '/' - error = agent.errors - }) + t.beforeEach(beforeEach) + t.afterEach(afterEach) - t.test('record captured params', (t) => { - trans.trace.attributes.addAttribute(DESTS.TRANS_SCOPE, 'request.parameters.a', 'A') - error.add(trans, new Error()) - agent.errors.onTransactionFinished(trans) + await t.test('record captured params', (t) => { + const { agent, errors, tx } = t.nr + tx.trace.attributes.addAttribute(DESTS.TRANS_SCOPE, 'request.parameters.a', 'A') + errors.add(tx, Error()) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) let params = errorTraces[0][PARAMS] - t.same(params.agentAttributes, { 'request.parameters.a': 'A' }) + assert.equal(match(params.agentAttributes, { 'request.parameters.a': 'A' }), true) // Error events - const errorEvents = getErrorEvents(error) + const errorEvents = getErrorEvents(errors) params = errorEvents[0][2] - t.same(params, { 'request.parameters.a': 'A' }) - t.end() + assert.equal(match(params, { 'request.parameters.a': 'A' }), true) }) - t.test('records custom parameters', (t) => { - trans.trace.addCustomAttribute('a', 'A') - error.add(trans, new Error()) - agent.errors.onTransactionFinished(trans) + await t.test('record custom parameters', (t) => { + const { agent, errors, tx } = t.nr + tx.trace.addCustomAttribute('a', 'A') + errors.add(tx, Error()) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) let params = errorTraces[0][PARAMS] + assert.equal(match(params.userAttributes, { a: 'A' }), true) - t.same(params.userAttributes, { a: 'A' }) - - // error events - const errorEvents = getErrorEvents(error) + const errorEvents = getErrorEvents(errors) params = errorEvents[0][1] - - t.same(params, { a: 'A' }) - t.end() + assert.equal(match(params, { a: 'A' }), true) }) - t.test('merge custom parameters', (t) => { - trans.trace.addCustomAttribute('a', 'A') - error.add(trans, new Error(), { b: 'B' }) - agent.errors.onTransactionFinished(trans) + await t.test('merge custom parameters', (t) => { + const { agent, errors, tx } = t.nr + tx.trace.addCustomAttribute('a', 'A') + errors.add(tx, Error(), { b: 'B' }) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) let params = errorTraces[0][PARAMS] + assert.equal(match(params.userAttributes, { a: 'A', b: 'B' }), true) - t.same(params.userAttributes, { - a: 'A', - b: 'B' - }) - - // error events - const errorEvents = getErrorEvents(error) + const errorEvents = getErrorEvents(errors) params = errorEvents[0][1] - - t.same(params, { - a: 'A', - b: 'B' - }) - t.end() + assert.equal(match(params, { a: 'A', b: 'B' }), true) }) - t.test('overrides existing custom attributes with new custom attributes', (t) => { - trans.trace.custom.a = 'A' - error.add(trans, new Error(), { a: 'AA' }) - agent.errors.onTransactionFinished(trans) + await t.test('overrides existing custom attributes with new custom attributes', (t) => { + const { agent, errors, tx } = t.nr + tx.trace.custom.a = 'A' + errors.add(tx, Error(), { a: 'AA' }) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) let params = errorTraces[0][PARAMS] + assert.equal(match(params.userAttributes, { a: 'AA' }), true) - t.same(params.userAttributes, { - a: 'AA' - }) - - // error events - const errorEvents = getErrorEvents(error) + const errorEvents = getErrorEvents(errors) params = errorEvents[0][1] - - t.same(params, { - a: 'AA' - }) - t.end() + assert.equal(match(params, { a: 'AA' }), true) }) - t.test('does not add custom attributes in high security mode', (t) => { + await t.test('does not add custom attributes in high security mode', (t) => { + const { agent, errors, tx } = t.nr agent.config.high_security = true - error.add(trans, new Error(), { a: 'AA' }) - agent.errors.onTransactionFinished(trans) + errors.add(tx, Error(), { a: 'AA' }) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) let params = errorTraces[0][PARAMS] + assert.equal(match(params.userAttributes, {}), true) - t.same(params.userAttributes, {}) - - // error events - const errorEvents = getErrorEvents(error) + const errorEvents = getErrorEvents(errors) params = errorEvents[0][1] - - t.same(params, {}) - t.end() + assert.equal(match(params, {}), true) }) - t.test('redacts the error message in high security mode', (t) => { + await t.test('redacts the error message in high security mode', (t) => { + const { agent, errors, tx } = t.nr agent.config.high_security = true - error.add(trans, new Error('this should not be here'), { a: 'AA' }) - agent.errors.onTransactionFinished(trans) + errors.add(tx, Error('should be omitted'), { a: 'AA' }) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) - t.equal(errorTraces[0][2], '') - t.equal(errorTraces[0][4].stack_trace[0], 'Error: ') - t.end() + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces[0][2], '') + assert.equal(errorTraces[0][4].stack_trace[0], 'Error: ') }) - t.test('redacts the error message when strip_exception_messages.enabled', (t) => { + await t.test('redacts the error message when strip_exception_messages.enabled', (t) => { + const { agent, errors, tx } = t.nr agent.config.strip_exception_messages.enabled = true - error.add(trans, new Error('this should not be here'), { a: 'AA' }) - agent.errors.onTransactionFinished(trans) + errors.add(tx, Error('should be omitted'), { a: 'AA' }) + agent.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) - t.equal(errorTraces[0][2], '') - t.equal(errorTraces[0][4].stack_trace[0], 'Error: ') - t.end() + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces[0][2], '') + assert.equal(errorTraces[0][4].stack_trace[0], 'Error: ') }) }) - t.test('transaction id with distributed tracing enabled', (t) => { - t.autoend() - let errorJSON - let transaction - let error - - t.beforeEach(() => { - agent.config.distributed_tracing.enabled = true - error = new Error('this is an error') + await t.test('transaction id with distributed tracing enabled', async (t) => { + t.beforeEach((ctx) => { + beforeEach(ctx) + ctx.nr.agent.config.distributed_tracing.enabled = true }) + t.afterEach(afterEach) - t.test('should have a transaction id when there is a transaction', (t) => { - transaction = new Transaction(agent) + await t.test('should have a transaction id when there is a transaction', (t) => { + const { agent } = t.nr + const tx = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + agent.errors.add(tx, Error('boom')) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - transaction.end() - t.end() + + assert.equal(transactionId, tx.id) + tx.end() }) - t.test('should not have a transaction id when there is no transaction', (t) => { - agent.errors.add(null, error) + await t.test('should not have a transaction id when there is no transaction', (t) => { + const { agent } = t.nr - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] + agent.errors.add(null, Error('boom')) + const errorTraces = getErrorTraces(agent.errors) + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.notOk(transactionId) - t.end() + assert.equal(transactionId, undefined) }) }) - t.test('guid attribute with distributed tracing enabled', (t) => { - t.autoend() - let errorJSON - let transaction - let error - - t.beforeEach(() => { - agent.config.distributed_tracing.enabled = true - error = new Error('this is an error') + await t.test('guid attribute with distributed tracing enabled', async (t) => { + t.beforeEach((ctx) => { + beforeEach(ctx) + ctx.nr.agent.config.distributed_tracing.enabled = true }) + t.afterEach(afterEach) - t.test('should have a guid attribute when there is a transaction', (t) => { - transaction = new Transaction(agent) - const aggregator = agent.errors + await t.test('should have a guid attribute when there is a transaction', (t) => { + const { agent, errors } = t.nr + const tx = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + agent.errors.add(tx, Error('boom')) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.equal(attributes.guid, transaction.id) - transaction.end() - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + + assert.equal(transactionId, tx.id) + assert.equal(attributes.guid, tx.id) + tx.end() }) - t.test('should not have a guid attribute when there is no transaction', (t) => { - agent.errors.add(null, error) - const aggregator = agent.errors + await t.test('should not have a guid attribute when there is no transaction', (t) => { + const { agent, errors } = t.nr + agent.errors.add(null, Error('boom')) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.notOk(transactionId) - t.notOk(attributes.guid) - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + + assert.equal(transactionId, undefined) + assert.equal(attributes.guid, undefined) }) }) - t.test('transaction id with distributed tracing disabled', (t) => { - t.autoend() - let errorJSON - let transaction - let error - - t.beforeEach(() => { - agent.config.distributed_tracing.enabled = false - error = new Error('this is an error') + await t.test('transaction id with distributed tracing disabled', async (t) => { + t.beforeEach((ctx) => { + beforeEach(ctx) + ctx.nr.agent.config.distributed_tracing.enabled = false }) + t.afterEach(afterEach) - t.test('should have a transaction id when there is a transaction', (t) => { - transaction = new Transaction(agent) + await t.test('should have a transaction id when there is a transaction', (t) => { + const { agent } = t.nr + const tx = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + agent.errors.add(tx, Error('boom')) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - transaction.end() - t.end() + + assert.equal(transactionId, tx.id) + tx.end() }) - t.test('should not have a transaction id when there is no transaction', (t) => { - agent.errors.add(null, error) + await t.test('should not have a transaction id when there is no transaction', (t) => { + const { agent } = t.nr - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] + agent.errors.add(null, Error('boom')) + const errorTraces = getErrorTraces(agent.errors) + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.notOk(transactionId) - t.end() + assert.equal(transactionId, undefined) }) }) - t.test('guid attribute with distributed tracing disabled', (t) => { - t.autoend() - let errorJSON - let transaction - let error - - t.beforeEach(() => { - agent.config.distributed_tracing.enabled = false - error = new Error('this is an error') + await t.test('guid attribute with distributed tracing disabled', async (t) => { + t.beforeEach((ctx) => { + beforeEach(ctx) + ctx.nr.agent.config.distributed_tracing.enabled = false }) + t.afterEach(afterEach) - t.test('should have a guid attribute when there is a transaction', (t) => { - transaction = new Transaction(agent) - const aggregator = agent.errors + await t.test('should have a guid attribute when there is a transaction', (t) => { + const { agent, errors } = t.nr + const tx = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + agent.errors.add(tx, Error('boom')) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.equal(attributes.guid, transaction.id) - transaction.end() - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + + assert.equal(transactionId, tx.id) + assert.equal(attributes.guid, tx.id) + tx.end() }) - t.test('should not have a guid attribute when there is no transaction', (t) => { - agent.errors.add(null, error) - const aggregator = agent.errors + await t.test('should not have a guid attribute when there is no transaction', (t) => { + const { agent, errors } = t.nr + agent.errors.add(null, Error('boom')) const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - + const errorJSON = errorTraces[0] const transactionId = errorJSON[5] - t.notOk(transactionId) - t.notOk(attributes.guid) - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + + assert.equal(transactionId, undefined) + assert.equal(attributes.guid, undefined) }) }) - t.test('display name', (t) => { - t.autoend() + await t.test('display name', async (t) => { const PARAMS = 4 + t.beforeEach(beforeEach) + t.afterEach(afterEach) + + await t.test('should be in agent attributes if set by user', (t) => { + // This test skips the beforeEach because: + // 1. beforeEach creates a new agent + // 2. beforeEach creates a new transaction + // 3. transaction creates a new trace + // 4. trace invokes getDisplayHost(), thus caching the default value + // 5. test function is invoked + // 6. agent config is updated + // 7. new transaction is created + // 8. new transaction creates a new trace + // 9. new trace invokes getDisplayHost() + // 10. getDisplayHost() returns the original cached value because the agent has been reused + helper.unloadAgent(t.nr.agent) + const agent = helper.loadMockedAgent({ + attributes: { enabled: true }, + process_host: { + display_name: 'test-value' + } + }) + t.after(() => helper.unloadAgent(agent)) - let trans - let error - - t.test('should be in agent attributes if set by user', (t) => { - agent.config.process_host.display_name = 'test-value' - - trans = new Transaction(agent) - trans.url = '/' + const tx = new Transaction(agent) + tx.url = '/' - error = agent.errors - error.add(trans, new Error()) - error.onTransactionFinished(trans) + const errors = agent.errors + errors.add(tx, Error()) + errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) const params = errorTraces[0][PARAMS] - t.same(params.agentAttributes, { - 'host.displayName': 'test-value' - }) - t.end() + assert.equal(match(params.agentAttributes, { 'host.displayName': 'test-value' }), true) }) - t.test('should not be in agent attributes if not set by user', (t) => { - trans = new Transaction(agent) - trans.url = '/' + await t.test('should not be in agent attributes if not set by user', (t) => { + const { errors, tx } = t.nr - error = agent.errors - error.add(trans, new Error()) - error.onTransactionFinished(trans) + errors.add(tx, Error()) + errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(error) + const errorTraces = getErrorTraces(errors) const params = errorTraces[0][PARAMS] - t.same(params.agentAttributes, {}) - t.end() + assert.equal(match(params.agentAttributes, {}), true) }) }) - t.test('ErrorCollector', (t) => { - t.autoend() - let metrics = null - let collector = null - let harvester = null - let errorCollector = null + await t.test('ErrorCollector', async (t) => { + t.beforeEach((ctx) => { + beforeEach(ctx) - t.beforeEach(() => { - metrics = new Metrics(5, {}, {}) - collector = {} - harvester = { add() {} } + ctx.nr.metrics = new Metrics(5, {}, {}) + ctx.nr.collector = {} + ctx.nr.harvester = { + add() {} + } - errorCollector = new ErrorCollector( - agent.config, + ctx.nr.errorCollector = new ErrorCollector( + ctx.nr.agent.config, new ErrorTraceAggregator( - { - periodMs: 60, - transport: null, - limit: 20 - }, - collector, - harvester + { periodMs: 60, transport: null, limit: 20 }, + ctx.nr.collector, + ctx.nr.harvester ), new ErrorEventAggregator( + { periodMs: 60, transport: null, limit: 20 }, { - periodMs: 60, - transport: null, - limit: 20 - }, - { - collector, - metrics, - harvester + collector: ctx.nr.collector, + metrics: ctx.nr.metrics, + harvester: ctx.nr.harvester } ), - metrics + ctx.nr.metrics ) }) - t.afterEach(() => { - errorCollector = null - harvester = null - collector = null - metrics = null - }) + t.afterEach(afterEach) - t.test('should preserve the name field on errors', (t) => { + await t.test('should preserve the name field on errors', (t) => { + const { agent, errors } = t.nr const api = new API(agent) - - const testError = new Error('EVERYTHING IS BROKEN') + const testError = Error('EVERYTHING IS BROKEN') testError.name = 'GAMEBREAKER' api.noticeError(testError) - const errorTraces = getErrorTraces(agent.errors) + const errorTraces = getErrorTraces(errors) const error = errorTraces[0] - t.equal(error[error.length - 3], testError.name) - t.end() + assert.equal(error[error.length - 3], testError.name) }) - t.test('should not gather application errors if it is switched off by user config', (t) => { - const error = new Error('this error will never be seen') - agent.config.error_collector.enabled = false - t.teardown(() => { - agent.config.error_collector.enabled = true - }) - - const errorTraces = getErrorTraces(errorCollector) - t.equal(errorTraces.length, 0) - - errorCollector.add(null, error) + await t.test( + 'should not gather application errors if it is switched off by user config', + (t) => { + const { agent, errorCollector } = t.nr + agent.config.error_collector.enabled = false - t.equal(errorTraces.length, 0) + const errorTraces = getErrorTraces(errorCollector) + assert.equal(errorTraces.length, 0) - t.end() - }) + errorCollector.add(null, Error('boom')) + assert.equal(errorTraces.length, 0) + } + ) - t.test('should not gather user errors if it is switched off by user config', (t) => { - const error = new Error('this error will never be seen') + await t.test('should not gather user errors if it is switched off by user config', (t) => { + const { agent, errorCollector } = t.nr agent.config.error_collector.enabled = false - t.teardown(() => { - agent.config.error_collector.enabled = true - }) const errorTraces = getErrorTraces(errorCollector) - t.equal(errorTraces.length, 0) + assert.equal(errorTraces.length, 0) - errorCollector.addUserError(null, error) - - t.equal(errorTraces.length, 0) - - t.end() + errorCollector.addUserError(null, Error('boom')) + assert.equal(errorTraces.length, 0) }) - t.test('should not gather errors if it is switched off by server config', (t) => { - const error = new Error('this error will never be seen') + await t.test('should not gather errors if it is switched off by server config', (t) => { + const { agent, errorCollector } = t.nr agent.config.collect_errors = false - t.teardown(() => { - agent.config.collect_errors = true - }) const errorTraces = getErrorTraces(errorCollector) - t.equal(errorTraces.length, 0) + assert.equal(errorTraces.length, 0) - errorCollector.add(null, error) - - t.equal(errorTraces.length, 0) - - t.end() + errorCollector.add(null, Error('boom')) + assert.equal(errorTraces.length, 0) }) - t.test('should gather the same error in two transactions', (t) => { - const error = new Error('this happened once') + await t.test('should gather the same error in two transactions', (t) => { + const { agent, errors } = t.nr + const error = Error('this happened once') const first = new Transaction(agent) const second = new Transaction(agent) - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 0) + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 0) - agent.errors.add(first, error) - t.equal(first.exceptions.length, 1) + errors.add(first, error) + assert.equal(first.exceptions.length, 1) - agent.errors.add(second, error) - t.equal(second.exceptions.length, 1) + errors.add(second, error) + assert.equal(second.exceptions.length, 1) first.end() - t.equal(errorTraces.length, 1) + assert.equal(errorTraces.length, 1) second.end() - t.equal(errorTraces.length, 2) - t.end() + assert.equal(errorTraces.length, 2) }) - t.test('should not gather the same error twice in the same transaction', (t) => { - const error = new Error('this happened once') + await t.test('should not gather the same error twice in the same transaction', (t) => { + const { errorCollector } = t.nr + const error = Error('this happened once') const errorTraces = getErrorTraces(errorCollector) - t.equal(errorTraces.length, 0) + assert.equal(errorTraces.length, 0) errorCollector.add(null, error) errorCollector.add(null, error) - t.equal(errorTraces.length, 1) - t.end() + assert.equal(errorTraces.length, 1) }) - t.test('should not break on read only objects', (t) => { - const error = new Error('this happened once') + await t.test('should not break on read only objects', (t) => { + const { errorCollector } = t.nr + const error = Error('this happened once') Object.freeze(error) const errorTraces = getErrorTraces(errorCollector) - t.equal(errorTraces.length, 0) + assert.equal(errorTraces.length, 0) errorCollector.add(null, error) errorCollector.add(null, error) - - t.equal(errorTraces.length, 1) - t.end() + assert.equal(errorTraces.length, 1) }) - t.test('add()', (t) => { - t.doesNotThrow(() => { - const aggregator = agent.errors - const error = new Error() + await t.test('add()', (t) => { + const { errors } = t.nr + assert.doesNotThrow(() => { + const error = Error() Object.freeze(error) - aggregator.add(error) + errors.add(error) }, 'when handling immutable errors') - - t.end() }) - t.test('when finalizing transactions', (t) => { - t.autoend() - let finalizeCollector = null - - t.beforeEach(() => { - finalizeCollector = agent.errors + await t.test('when finalizing transactions', async (t) => { + // We must unload the singleton agent in this nested test prior to any + // of the subtests running. Otherwise, we will get an error about the agent + // already being created when `loadMockedAgent` is invoked. + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) }) - t.test('should capture errors for transactions ending in error', (t) => { - finalizeCollector.onTransactionFinished(createTransaction(agent, 400)) - finalizeCollector.onTransactionFinished(createTransaction(agent, 500)) + await t.test('should capture errors for transactions ending in error', (t) => { + const { agent, errors } = t.nr + errors.onTransactionFinished(createTransaction(agent, 400)) + errors.onTransactionFinished(createTransaction(agent, 500)) - const errorTraces = getErrorTraces(finalizeCollector) - t.equal(errorTraces.length, 2) - t.end() + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 2) }) - t.test('should generate transaction error metric', (t) => { - const transaction = createTransaction(agent, 200) - - finalizeCollector.add(transaction, new Error('error1')) - finalizeCollector.add(transaction, new Error('error2')) + await t.test('should generate transaction error metric', (t) => { + const { agent, errors } = t.nr + const tx = createTransaction(agent, 200) - finalizeCollector.onTransactionFinished(transaction) + errors.add(tx, Error('error1')) + errors.add(tx, Error('erorr2')) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.equal(metric.callCount, 2) - t.end() + assert.equal(metric.callCount, 2) }) - t.test('should generate transaction error metric when added from API', (t) => { + await t.test('should generate transaction error metric when added from API', (t) => { + const { agent, errors } = t.nr const api = new API(agent) - const transaction = createTransaction(agent, 200) + const tx = createTransaction(agent, 200) agent.tracer.getTransaction = () => { - return transaction + return tx } - - api.noticeError(new Error('error1')) - api.noticeError(new Error('error2')) - - finalizeCollector.onTransactionFinished(transaction) + api.noticeError(Error('error1')) + api.noticeError(Error('error2')) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.equal(metric.callCount, 2) - t.end() + assert.equal(metric.callCount, 2) }) - t.test('should not generate transaction error metric for ignored error', (t) => { + await t.test('should not generate transaction error metric for ignored error', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.ignore_classes = ['Error'] - const transaction = createTransaction(agent, 200) + const tx = createTransaction(agent, 200) - finalizeCollector.add(transaction, new Error('error1')) - finalizeCollector.add(transaction, new Error('error2')) - - finalizeCollector.onTransactionFinished(transaction) + errors.add(tx, Error('error1')) + errors.add(tx, Error('error2')) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.notOk(metric) - t.end() + assert.equal(metric, undefined) }) - t.test('should not generate transaction error metric for expected error', (t) => { + await t.test('should not generate transaction error metric for expected error', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] - const transaction = createTransaction(agent, 200) + const tx = createTransaction(agent, 200) - finalizeCollector.add(transaction, new Error('error1')) - finalizeCollector.add(transaction, new Error('error2')) - - finalizeCollector.onTransactionFinished(transaction) + errors.add(tx, Error('error1')) + errors.add(tx, Error('error2')) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.notOk(metric) - t.end() + assert.equal(metric, undefined) }) - t.test( + await t.test( 'should generate transaction error metric for unexpected error via noticeError', (t) => { + const { agent, errors } = t.nr const api = new API(agent) - const transaction = createTransaction(agent, 200) - - agent.tracer.getTransaction = () => { - return transaction - } + const tx = createTransaction(agent, 200) - api.noticeError(new Error('unexpected error')) - api.noticeError(new Error('another unexpected error')) + agent.tracer.getTransaction = () => tx - finalizeCollector.onTransactionFinished(transaction) + api.noticeError(Error('unexpected error')) + api.noticeError(Error('another unexpected error')) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.equal(metric.callCount, 2) - t.end() + assert.equal(metric.callCount, 2) } ) - t.test( + await t.test( 'should not generate transaction error metric for expected error via noticeError', (t) => { + const { agent, errors } = t.nr const api = new API(agent) - const transaction = createTransaction(agent, 200) - - agent.tracer.getTransaction = () => { - return transaction - } + const tx = createTransaction(agent, 200) - api.noticeError(new Error('expected error'), {}, true) - api.noticeError(new Error('another expected error'), {}, true) + agent.tracer.getTransaction = () => tx - finalizeCollector.onTransactionFinished(transaction) + api.noticeError(Error('expected error'), {}, true) + api.noticeError(Error('another expected error'), {}, true) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - - t.notOk(metric) - t.end() + assert.equal(metric, undefined) } ) - t.test('should ignore errors if related transaction is ignored', (t) => { - const transaction = createTransaction(agent, 500) - transaction.ignore = true + await t.test('should ignore errors if related transaction is ignored', (t) => { + const { agent, errors } = t.nr + const tx = createTransaction(agent, 500) + tx.ignore = true - // add errors by various means - finalizeCollector.add(transaction, new Error('no')) - const error = new Error('ignored') + // Add errors by various means + errors.add(tx, Error('no')) + const error = Error('ignored') const exception = new Exception({ error }) - transaction.addException(exception) - finalizeCollector.onTransactionFinished(transaction) + tx.addException(exception) + errors.onTransactionFinished(tx) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.notOk(metric) - t.end() + assert.equal(metric, undefined) }) - t.test('should ignore 404 errors for transactions', (t) => { - finalizeCollector.onTransactionFinished(createTransaction(agent, 400)) + await t.test('should ignore 404 errors for transactions', (t) => { + const { agent, errors } = t.nr + errors.onTransactionFinished(createTransaction(agent, 400)) // 404 errors are ignored by default - finalizeCollector.onTransactionFinished(createTransaction(agent, 404)) - finalizeCollector.onTransactionFinished(createTransaction(agent, 404)) - finalizeCollector.onTransactionFinished(createTransaction(agent, 404)) - finalizeCollector.onTransactionFinished(createTransaction(agent, 404)) + errors.onTransactionFinished(createTransaction(agent, 404)) + errors.onTransactionFinished(createTransaction(agent, 404)) + errors.onTransactionFinished(createTransaction(agent, 404)) + errors.onTransactionFinished(createTransaction(agent, 404)) - const errorTraces = getErrorTraces(finalizeCollector) - t.equal(errorTraces.length, 1) + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 1) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.equal(metric.callCount, 1) - t.end() + assert.equal(metric.callCount, 1) }) - t.test('should ignore 404 errors for transactions with exceptions attached', (t) => { + await t.test('should ignore 404 errors for transactions with exceptions attached', (t) => { + const { agent, errors } = t.nr const notIgnored = createTransaction(agent, 400) - const error = new Error('bad request') + const error = Error('bad request') const exception = new Exception({ error }) notIgnored.addException(exception) - finalizeCollector.onTransactionFinished(notIgnored) + errors.onTransactionFinished(notIgnored) // 404 errors are ignored by default, but making sure the config is set - finalizeCollector.config.error_collector.ignore_status_codes = [404] + errors.config.error_collector.ignore_status_codes = [404] const ignored = createTransaction(agent, 404) - agent.errors.add(ignored, new Error('ignored')) - finalizeCollector.onTransactionFinished(ignored) + agent.errors.add(ignored, Error('ignored')) + errors.onTransactionFinished(ignored) - const errorTraces = getErrorTraces(finalizeCollector) - t.equal(errorTraces.length, 1) + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 1) const metric = agent.metrics.getMetric('Errors/WebTransaction/TestJS/path') - t.equal(metric.callCount, 1) - t.end() + assert.equal(metric.callCount, 1) }) - t.test( + await t.test( 'should collect exceptions added with noticeError() API even if the status ' + 'code is in ignore_status_codes config', (t) => { + const { agent, errors } = t.nr const api = new API(agent) const tx = createTransaction(agent, 404) @@ -758,637 +715,559 @@ tap.test('Errors', (t) => { } // 404 errors are ignored by default, but making sure the config is set - finalizeCollector.config.error_collector.ignore_status_codes = [404] + errors.config.error_collector.ignore_status_codes = [404] // this should be ignored agent.errors.add(tx, new Error('should be ignored')) // this should go through api.noticeError(new Error('should go through')) - finalizeCollector.onTransactionFinished(tx) + errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(finalizeCollector) - t.equal(errorTraces.length, 1) - t.equal(errorTraces[0][2], 'should go through') - t.end() + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 1) + assert.equal(errorTraces[0][2], 'should go through') } ) }) - t.test('with no exception and no transaction', (t) => { - t.test('should have no errors', (t) => { - agent.errors.add(null, null) + await t.test('with no exception and no transaction', async (t) => { + helper.unloadAgent(t.nr.agent) + await t.test('should have no errors', (t) => { + const { errors } = t.nr + errors.add(null, null) - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 0) - t.end() + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 0) }) - t.end() }) - t.test('with no error and a transaction with status code', (t) => { - t.beforeEach(() => { - agent.errors.add(new Transaction(agent), null) + await t.test('with no error and a transaction without status code', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) + t.nr.errors.add(new Transaction(ctx.nr.agent), null) }) - t.test('should have no errors', (t) => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 0) - t.end() + await t.test('should have no errors', (t) => { + const { errors } = t.nr + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 0) }) - t.end() }) - t.test('with no error and a transaction with a status code', (t) => { - t.autoend() - let noErrorStatusTracer - let errorJSON - let transaction + await t.test('with no error and a transaction with a status code', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) - t.beforeEach(() => { - noErrorStatusTracer = agent.errors + ctx.nr.errors.add(new Transaction(ctx.nr.agent), null) - transaction = new Transaction(agent) - transaction.statusCode = 503 // PDX wut wut + ctx.nr.tx = new Transaction(ctx.nr.agent) + ctx.nr.tx.statusCode = 503 - noErrorStatusTracer.add(transaction, null) - noErrorStatusTracer.onTransactionFinished(transaction) + ctx.nr.errors.add(ctx.nr.tx, null) + ctx.nr.errors.onTransactionFinished(ctx.nr.tx) - const errorTraces = getErrorTraces(noErrorStatusTracer) - errorJSON = errorTraces[0] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(noErrorStatusTracer) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have no errors', (t) => { + const { errorTraces } = t.nr + assert.equal(errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[0], 0) }) - t.test('should have the default scope', (t) => { - t.equal(errorJSON[1], 'Unknown') - t.end() + await t.test('should have the default scope', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[1], 'Unknown') }) - t.test('should have an HTTP status code error message', (t) => { - t.equal(errorJSON[2], 'HttpError 503') - t.end() + await t.test('should have an HTTP status code error message', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[2], 'HttpError 503') }) - t.test('should default to a type of Error', (t) => { - t.equal(errorJSON[3], 'Error') - t.end() + await t.test('should default to a type of Error', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[3], 'Error') }) - t.test('should not have a stack trace in the params', (t) => { - const params = errorJSON[4] - t.notHas(params, 'stack_trace') - t.end() + await t.test('should not have a stack trace in the params', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[4].stack_trace, undefined) }) - t.test('should have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + await t.test('should have a transaction id', (t) => { + const { errorJSON, tx } = t.nr + assert.equal(errorJSON[5], tx.id) }) - t.test('should have 6 elements in errorJson', (t) => { - t.equal(errorJSON.length, 6) - t.end() + await t.test('should have 6 elements in errorJson', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON.length, 6) }) }) - t.test('with transaction agent attrs, status code, and no error', (t) => { - let errorJSON = null - let params = null - let transaction + await t.test('with transaction agent attrs, status code, and no error', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) - t.beforeEach(() => { - transaction = new Transaction(agent) - transaction.statusCode = 501 - transaction.url = '/' - transaction.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { + ctx.nr.tx.statusCode = 501 + ctx.nr.tx.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { test_param: 'a value', thing: true }) - agent.errors.add(transaction, null) - agent.errors.onTransactionFinished(transaction) + ctx.nr.errors.add(ctx.nr.tx, null) + ctx.nr.errors.onTransactionFinished(ctx.nr.tx) - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - params = errorJSON[4] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] + ctx.nr.params = ctx.nr.errorJSON[4] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + const { errors } = t.nr + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[0], 0) }) - t.test('should be scoped to the transaction', (t) => { - t.equal(errorJSON[1], 'WebTransaction/WebFrameworkUri/(not implemented)') - t.end() + await t.test('should be scoped to the transaction', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[1], 'WebTransaction/WebFrameworkUri/(not implemented)') }) - t.test('should have an HTTP status code message', (t) => { - t.equal(errorJSON[2], 'HttpError 501') - t.end() + await t.test('should have an HTTP status code message', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[2], 'HttpError 501') }) - t.test('should default to a type of Error', (t) => { - t.equal(errorJSON[3], 'Error') - t.end() + await t.test('should default to a type of Error', (t) => { + const { errorJSON } = t.nr + assert.equal(errorJSON[3], 'Error') }) - t.test('should not have a stack trace in the params', (t) => { - t.notHas(params, 'stack_trace') - t.end() + await t.test('should not have a stack trace in the params', (t) => { + const { params } = t.nr + assert.equal(params.stack_trace, undefined) }) - t.test('should have a transaction id', (t) => { + await t.test('should have a transaction id', (t) => { + const { errorJSON, tx } = t.nr const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + assert.equal(transactionId, tx.id) }) - t.test('should not have a request URL', (t) => { - t.notOk(params['request.uri']) - t.end() + await t.test('should not have a request URL', (t) => { + const { params } = t.nr + assert.equal(params['request.uri'], undefined) }) - t.test('should parse out the first agent parameter', (t) => { - t.equal(params.agentAttributes.test_param, 'a value') - t.end() + await t.test('should parse out the first agent parameter', (t) => { + const { params } = t.nr + assert.equal(params.agentAttributes.test_param, 'a value') }) - t.test('should parse out the other agent parameter', (t) => { - t.equal(params.agentAttributes.thing, true) - t.end() + await t.test('should parse out the other agent parameter', (t) => { + const { params } = t.nr + assert.equal(params.agentAttributes.thing, true) }) - t.end() }) - t.test('with attributes.enabled disabled', (t) => { - const transaction = new Transaction(agent) - transaction.statusCode = 501 + await t.test('with attributes.enabled disabled', (t) => { + const { agent, errors } = t.nr + const tx = new Transaction(agent) - transaction.url = '/test_action.json?test_param=a%20value&thing' + tx.statusCode = 501 + tx.url = '/test_action.json?test_param=a%20value&thing' - agent.errors.add(transaction, null) - agent.errors.onTransactionFinished(transaction) + errors.add(tx, null) + errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(agent.errors) + const errorTraces = getErrorTraces(errors) const errorJSON = errorTraces[0] const params = errorJSON[4] - - t.notHas(params, 'request_params') - t.end() + assert.equal(params.request_params, undefined) }) - t.test('with attributes.enabled and attributes.exclude set', (t) => { + await t.test('with attributes.enabled and attributes.exclude set', (t) => { + const { agent, errors } = t.nr + agent.config.attributes.exclude = ['thing'] agent.config.emit('attributes.exclude') - const transaction = new Transaction(agent) - transaction.statusCode = 501 - - transaction.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { + const tx = new Transaction(agent) + tx.statusCode = 501 + tx.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { test_param: 'a value', thing: 5 }) - agent.errors.add(transaction, null) - agent._transactionFinished(transaction) + errors.add(tx, null) + agent._transactionFinished(tx) - const errorTraces = getErrorTraces(agent.errors) + const errorTraces = getErrorTraces(errors) const errorJSON = errorTraces[0] const params = errorJSON[4] - - t.same(params.agentAttributes, { test_param: 'a value' }) - t.end() + assert.equal(match(params.agentAttributes, { test_param: 'a value' }), true) }) - t.test('with a thrown TypeError object and no transaction', (t) => { - t.autoend() - let typeErrorTracer - let errorJSON - - t.beforeEach(() => { - typeErrorTracer = agent.errors - - const exception = new Error('Dare to be the same!') + await t.test('with a thrown TypeError object and no transaction', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - typeErrorTracer.add(null, exception) + const exception = Error('Dare to be the same!') + ctx.nr.errors.add(null, exception) - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + assert.equal(t.nr.errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + assert.equal(t.nr.errorJSON[0], 0) }) - t.test('should have the default scope', (t) => { - t.equal(errorJSON[1], 'Unknown') - t.end() + await t.test('should have the default scope', (t) => { + assert.equal(t.nr.errorJSON[1], 'Unknown') }) - t.test('should fish the message out of the exception', (t) => { - t.equal(errorJSON[2], 'Dare to be the same!') - t.end() + await t.test('should fish the message out of the exception', (t) => { + assert.equal(t.nr.errorJSON[2], 'Dare to be the same!') }) - t.test('should have a type of TypeError', (t) => { - t.equal(errorJSON[3], 'Error') - t.end() + await t.test('should have a type of TypeError', (t) => { + assert.equal(t.nr.errorJSON[3], 'Error') }) - t.test('should have a stack trace in the params', (t) => { - const params = errorJSON[4] - t.hasProp(params, 'stack_trace') - t.equal(params.stack_trace[0], 'Error: Dare to be the same!') - t.end() + await t.test('should have a stack trace in the params', (t) => { + const params = t.nr.errorJSON[4] + assert.equal(Object.hasOwn(params, 'stack_trace'), true) + assert.equal(params.stack_trace[0], 'Error: Dare to be the same!') }) - t.test('should not have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.notOk(transactionId) - t.end() + await t.test('should not have a transaction id', (t) => { + const transactionId = t.nr.errorJSON[5] + assert.equal(transactionId, undefined) }) }) - t.test('with a thrown TypeError and a transaction with no params', (t) => { - t.autoend() - let typeErrorTracer - let errorJSON - let transaction - - t.beforeEach(() => { - typeErrorTracer = agent.errors + await t.test('with a thrown TypeError and a transaction with no params', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - transaction = new Transaction(agent) + ctx.nr.tx = new Transaction(ctx.nr.agent) const exception = new TypeError('Dare to be different!') + ctx.nr.errors.add(ctx.nr.tx, exception) + ctx.nr.errors.onTransactionFinished(ctx.nr.tx) - typeErrorTracer.add(transaction, exception) - typeErrorTracer.onTransactionFinished(transaction) - - const errorTraces = getErrorTraces(typeErrorTracer) - errorJSON = errorTraces[0] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(typeErrorTracer) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + assert.equal(t.nr.errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + assert.equal(t.nr.errorJSON[0], 0) }) - t.test('should have the default scope', (t) => { - t.equal(errorJSON[1], 'Unknown') - t.end() + await t.test('should have the default scope', (t) => { + assert.equal(t.nr.errorJSON[1], 'Unknown') }) - t.test('should fish the message out of the exception', (t) => { - t.equal(errorJSON[2], 'Dare to be different!') - t.end() + await t.test('should fish the message out of the exception', (t) => { + assert.equal(t.nr.errorJSON[2], 'Dare to be different!') }) - t.test('should have a type of TypeError', (t) => { - t.equal(errorJSON[3], 'TypeError') - t.end() + await t.test('should have a type of TypeError', (t) => { + assert.equal(t.nr.errorJSON[3], 'TypeError') }) - t.test('should have a stack trace in the params', (t) => { - const params = errorJSON[4] - t.hasProp(params, 'stack_trace') - t.equal(params.stack_trace[0], 'TypeError: Dare to be different!') - t.end() + await t.test('should have a stack trace in the params', (t) => { + const params = t.nr.errorJSON[4] + assert.equal(Object.hasOwn(params, 'stack_trace'), true) + assert.equal(params.stack_trace[0], 'TypeError: Dare to be different!') }) - t.test('should have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + await t.test('should have a transaction id', (t) => { + const transactionId = t.nr.errorJSON[5] + assert.equal(transactionId, t.nr.tx.id) }) }) - t.test('with a thrown `TypeError` and a transaction with agent attrs', (t) => { - t.autoend() - let errorJSON = null - let params = null - let transaction + await t.test('with a thrown TypeError and a transaction with agent attrs', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - t.beforeEach(() => { - transaction = new Transaction(agent) + const tx = new Transaction(ctx.nr.agent) const exception = new TypeError('wanted JSON, got XML') + ctx.nr.tx = tx - transaction.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { + tx.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { test_param: 'a value', thing: true }) - transaction.url = '/test_action.json' + tx.url = '/test_action.json' - agent.errors.add(transaction, exception) - agent.errors.onTransactionFinished(transaction) + ctx.nr.errors.add(tx, exception) + ctx.nr.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - params = errorJSON[4] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] + ctx.nr.params = ctx.nr.errorJSON[4] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + assert.equal(t.nr.errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + assert.equal(t.nr.errorJSON[0], 0) }) - t.test("should have the URL's scope", (t) => { - t.equal(errorJSON[1], 'WebTransaction/NormalizedUri/*') - t.end() + await t.test("should have the URL's scope", (t) => { + assert.equal(t.nr.errorJSON[1], 'WebTransaction/NormalizedUri/*') }) - t.test('should fish the message out of the exception', (t) => { - t.equal(errorJSON[2], 'wanted JSON, got XML') - t.end() + await t.test('should fish the message out of the exception', (t) => { + assert.equal(t.nr.errorJSON[2], 'wanted JSON, got XML') }) - t.test('should have a type of TypeError', (t) => { - t.equal(errorJSON[3], 'TypeError') - t.end() + await t.test('should have a type of TypeError', (t) => { + assert.equal(t.nr.errorJSON[3], 'TypeError') }) - t.test('should have a stack trace in the params', (t) => { - t.hasProp(params, 'stack_trace') - t.equal(params.stack_trace[0], 'TypeError: wanted JSON, got XML') - t.end() + await t.test('should have a stack trace in the params', (t) => { + const { params } = t.nr + assert.equal(Object.hasOwn(params, 'stack_trace'), true) + assert.equal(params.stack_trace[0], 'TypeError: wanted JSON, got XML') }) - t.test('should have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + await t.test('should have a transaction id', (t) => { + const transactionId = t.nr.errorJSON[5] + assert.equal(transactionId, t.nr.tx.id) }) - t.test('should not have a request URL', (t) => { - t.notOk(params['request.uri']) - t.end() + await t.test('should not have a request URL', (t) => { + assert.equal(t.nr.params['request.uri'], undefined) }) - t.test('should parse out the first agent parameter', (t) => { - t.equal(params.agentAttributes.test_param, 'a value') - t.end() + await t.test('should parse out the first agent parameter', (t) => { + assert.equal(t.nr.params.agentAttributes.test_param, 'a value') }) - t.test('should parse out the other agent parameter', (t) => { - t.equal(params.agentAttributes.thing, true) - t.end() + await t.test('should parse out the other agent parameter', (t) => { + assert.equal(t.nr.params.agentAttributes.thing, true) }) }) - t.test('with a thrown string and a transaction', (t) => { - t.autoend() - let thrownTracer - let errorJSON - let transaction + await t.test('with a thrown string and a transaction', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - t.beforeEach(() => { - thrownTracer = agent.errors - - transaction = new Transaction(agent) + const tx = new Transaction(ctx.nr.agent) const exception = 'Dare to be different!' + ctx.nr.tx = tx - thrownTracer.add(transaction, exception) - thrownTracer.onTransactionFinished(transaction) + ctx.nr.errors.add(tx, exception) + ctx.nr.errors.onTransactionFinished(tx) - const errorTraces = getErrorTraces(thrownTracer) - errorJSON = errorTraces[0] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(thrownTracer) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + assert.equal(t.nr.errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + assert.equal(t.nr.errorJSON[0], 0) }) - t.test('should have the default scope', (t) => { - t.equal(errorJSON[1], 'Unknown') - t.end() + await t.test('should have the default scope', (t) => { + assert.equal(t.nr.errorJSON[1], 'Unknown') }) - t.test('should turn the string into the message', (t) => { - t.equal(errorJSON[2], 'Dare to be different!') - t.end() + await t.test('should turn the string into the message', (t) => { + assert.equal(t.nr.errorJSON[2], 'Dare to be different!') }) - t.test('should default to a type of Error', (t) => { - t.equal(errorJSON[3], 'Error') - t.end() + await t.test('should default to a type of Error', (t) => { + assert.equal(t.nr.errorJSON[3], 'Error') }) - t.test('should have no stack trace', (t) => { - t.notHas(errorJSON[4], 'stack_trace') - t.end() + await t.test('should have no stack trace', (t) => { + assert.equal(t.nr.errorJSON[4].stack_trace, undefined) }) - t.test('should have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + await t.test('should have a transaction id', (t) => { + const transactionId = t.nr.errorJSON[5] + assert.equal(transactionId, t.nr.tx.id) }) }) - t.test('with a thrown string and a transaction with agent parameters', (t) => { - t.autoend() - let errorJSON = null - let params = null - let transaction + await t.test('with a thrown string and a transaction with agent parameters', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - t.beforeEach(() => { - transaction = new Transaction(agent) + const tx = new Transaction(ctx.nr.agent) const exception = 'wanted JSON, got XML' + ctx.nr.tx = tx - transaction.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { + tx.trace.attributes.addAttributes(DESTS.TRANS_SCOPE, { test_param: 'a value', thing: true }) + tx.url = '/test_action.json' - transaction.url = '/test_action.json' + ctx.nr.errors.add(tx, exception) + ctx.nr.errors.onTransactionFinished(tx) - agent.errors.add(transaction, exception) - agent.errors.onTransactionFinished(transaction) - - const errorTraces = getErrorTraces(agent.errors) - errorJSON = errorTraces[0] - params = errorJSON[4] + ctx.nr.errorTraces = getErrorTraces(ctx.nr.errors) + ctx.nr.errorJSON = ctx.nr.errorTraces[0] + ctx.nr.params = ctx.nr.errorJSON[4] }) - t.test('should have one error', (t) => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 1) - t.end() + await t.test('should have one error', (t) => { + assert.equal(t.nr.errorTraces.length, 1) }) - t.test('should not care what time it was traced', (t) => { - t.equal(errorJSON[0], 0) - t.end() + await t.test('should not care what time it was traced', (t) => { + assert.equal(t.nr.errorJSON[0], 0) }) - t.test("should have the transaction's name", (t) => { - t.equal(errorJSON[1], 'WebTransaction/NormalizedUri/*') - t.end() + await t.test("should have the transaction's name", (t) => { + assert.equal(t.nr.errorJSON[1], 'WebTransaction/NormalizedUri/*') }) - t.test('should turn the string into the message', (t) => { - t.equal(errorJSON[2], 'wanted JSON, got XML') - t.end() + await t.test('should turn the string into the message', (t) => { + assert.equal(t.nr.errorJSON[2], 'wanted JSON, got XML') }) - t.test('should default to a type of Error', (t) => { - t.equal(errorJSON[3], 'Error') - t.end() + await t.test('should default to a type of Error', (t) => { + assert.equal(t.nr.errorJSON[3], 'Error') }) - t.test('should not have a stack trace in the params', (t) => { - t.notHas(params, 'stack_trace') - t.end() + await t.test('should not have a stack trace in the params', (t) => { + assert.equal(t.nr.params.stack_trace, undefined) }) - t.test('should have a transaction id', (t) => { - const transactionId = errorJSON[5] - t.equal(transactionId, transaction.id) - t.end() + await t.test('should have a transaction id', (t) => { + const transactionId = t.nr.errorJSON[5] + assert.equal(transactionId, t.nr.tx.id) }) - t.test('should not have a request URL', (t) => { - t.notOk(params['request.uri']) - t.end() + await t.test('should not have a request URL', (t) => { + assert.equal(t.nr.params['request.uri'], undefined) }) - t.test('should parse out the first agent parameter', (t) => { - t.equal(params.agentAttributes.test_param, 'a value') - t.end() + await t.test('should parse out the first agent parameter', (t) => { + assert.equal(t.nr.params.agentAttributes.test_param, 'a value') }) - t.test('should parse out the other agent parameter', (t) => { - t.equal(params.agentAttributes.thing, true) - t.end() + await t.test('should parse out the other agent parameter', (t) => { + assert.equal(t.nr.params.agentAttributes.thing, true) }) }) - t.test('with an internal server error (500) and an exception', (t) => { - t.autoend() - const name = 'WebTransaction/Uri/test-request/zxrkbl' - let error + await t.test('with an internal server error (500) and an exception', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - t.beforeEach(() => { - errorCollector = agent.errors + const tx = new Transaction(ctx.nr.agent) + const exception = new Exception({ error: Error('500 test error') }) + ctx.nr.tx = tx - const transaction = new Transaction(agent) - const exception = new Exception({ error: new Error('500 test error') }) + tx.addException(exception) + tx.url = '/test-request/zxrkbl' + tx.name = 'WebTransaction/Uri/test-request/zxrkbl' + tx.statusCode = 500 + tx.end() - transaction.addException(exception) - transaction.url = '/test-request/zxrkbl' - transaction.name = 'WebTransaction/Uri/test-request/zxrkbl' - transaction.statusCode = 500 - transaction.end() - error = getErrorTraces(errorCollector)[0] + ctx.nr.error = getErrorTraces(ctx.nr.errors)[0] }) - t.test("should associate errors with the transaction's name", (t) => { - const errorName = error[1] - - t.equal(errorName, name) - t.end() + await t.test("should associate errors with the transaction's name", (t) => { + const errorName = t.nr.error[1] + assert.equal(errorName, 'WebTransaction/Uri/test-request/zxrkbl') }) - t.test('should associate errors with a message', (t) => { - const message = error[2] - - t.match(message, /500 test error/) - t.end() + await t.test('should associate errors with a message', (t) => { + const message = t.nr.error[2] + assert.match(message, /500 test error/) }) - t.test('should associate errors with a message class', (t) => { - const messageClass = error[3] - - t.equal(messageClass, 'Error') - t.end() + await t.test('should associate errors with a message class', (t) => { + const messageClass = t.nr.error[3] + assert.equal(messageClass, 'Error') }) - t.test('should associate errors with parameters', (t) => { - const params = error[4] - - t.ok(params && params.stack_trace) - t.equal(params.stack_trace[0], 'Error: 500 test error') - t.end() + await t.test('should associate errors with parameters', (t) => { + const params = t.nr.error[4] + assert.ok(params && params.stack_trace) + assert.equal(params.stack_trace[0], 'Error: 500 test error') }) }) - t.test('with a tracer unavailable (503) error', (t) => { - t.autoend() - const name = 'WebTransaction/Uri/test-request/zxrkbl' - let error + await t.test('with tracer unavailable (503) error', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) - t.beforeEach(() => { - errorCollector = agent.errors + const tx = new Transaction(ctx.nr.agent) + ctx.nr.tx = tx - const transaction = new Transaction(agent) - transaction.url = '/test-request/zxrkbl' - transaction.name = 'WebTransaction/Uri/test-request/zxrkbl' - transaction.statusCode = 503 - transaction.end() - error = getErrorTraces(errorCollector)[0] + tx.url = '/test-request/zxrkbl' + tx.name = 'WebTransaction/Uri/test-request/zxrkbl' + tx.statusCode = 503 + tx.end() + + ctx.nr.error = getErrorTraces(ctx.nr.errors)[0] }) - t.test("should associate errors with the transaction's name", (t) => { - const errorName = error[1] - t.equal(errorName, name) - t.end() + await t.test("should associate errors with the transaction's name", (t) => { + const errorName = t.nr.error[1] + assert.equal(errorName, 'WebTransaction/Uri/test-request/zxrkbl') }) - t.test('should associate errors with a message', (t) => { - const message = error[2] - t.equal(message, 'HttpError 503') - t.end() + await t.test('should associate errors with a message', (t) => { + const message = t.nr.error[2] + assert.equal(message, 'HttpError 503') }) - t.test('should associate errors with an error type', (t) => { - const messageClass = error[3] - t.equal(messageClass, 'Error') - t.end() + + await t.test('should associate errors with an error type', (t) => { + const messageClass = t.nr.error[3] + assert.equal(messageClass, 'Error') }) }) - t.test('should allow throwing null', (t) => { + await t.test('should allow throwing null', (t) => { + const { agent } = t.nr const api = new API(agent) try { @@ -1396,289 +1275,280 @@ tap.test('Errors', (t) => { throw null }) } catch (err) { - t.equal(err, null) + assert.equal(err, null) } - t.end() }) - t.test('should copy parameters from background transactions', async (t) => { + await t.test('should copy parameters from background transactions', (t, end) => { + const { agent, errors } = t.nr const api = new API(agent) - await api.startBackgroundTransaction('job', () => { + api.startBackgroundTransaction('job', () => { api.addCustomAttribute('jobType', 'timer') api.noticeError(new Error('record an error')) agent.getTransaction().end() - const errorTraces = getErrorTraces(agent.errors) + const errorTraces = getErrorTraces(errors) - t.equal(errorTraces.length, 1) - t.equal(errorTraces[0][2], 'record an error') + assert.equal(errorTraces.length, 1) + assert.equal(errorTraces[0][2], 'record an error') + end() }) }) - t.test('should generate expected error metric for expected errors', (t) => { + await t.test('should generate expected error metric for expected errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.EXPECTED) - t.equal(metric.callCount, 2) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.EXPECTED) + assert.equal(metric.callCount, 2) }) - t.test('should not generate expected error metric for unexpected errors', (t) => { + await t.test('should not generate expected error metric for unexpected errors', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) const metric = agent.metrics.getMetric(NAMES.ERRORS.EXPECTED) - t.notOk(metric) - t.end() + assert.equal(metric, undefined) }) - t.test('should not generate expected error metric for ignored errors', (t) => { + await t.test('should not generate expected error metric for ignored errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] agent.config.error_collector.ignore_classes = ['Error'] // takes precedence const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) const metric = agent.metrics.getMetric(NAMES.ERRORS.EXPECTED) - t.notOk(metric) - t.end() + assert.equal(metric, undefined) }) - t.test('should generate all error metric for unexpected errors', (t) => { + await t.test('should generate all error metric for unexpected errors', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.ALL) - t.equal(metric.callCount, 2) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.ALL) + assert.equal(metric.callCount, 2) }) - t.test('should not generate all error metric for expected errors', (t) => { + await t.test('should not generate all error metric for expected errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, new Error('error1')) + errors.add(transaction, new Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.ALL) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.ALL) + assert.equal(metric, undefined) }) - t.test('should not generate all error metric for ignored errors', (t) => { + await t.test('should not generate all error metric for ignored errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.ignore_classes = ['Error'] const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.ALL) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.ALL) + assert.equal(metric, undefined) }) - t.test('should generate web error metric for unexpected web errors', (t) => { + await t.test('should generate web error metric for unexpected web errors', (t) => { + const { agent, errors } = t.nr const transaction = createWebTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.WEB) - t.equal(metric.callCount, 2) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.WEB) + assert.equal(metric.callCount, 2) }) - t.test('should not generate web error metric for expected web errors', (t) => { + await t.test('should not generate web error metric for expected web errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.WEB) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.WEB) + assert.equal(metric, undefined) }) - t.test('should not generate web error metric for ignored web errors', (t) => { + await t.test('should not generate web error metric for ignored web errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.ignore_classes = ['Error'] const transaction = createTransaction(agent, 200) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.WEB) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.WEB) + assert.equal(metric, undefined) }) - t.test('should not generate web error metric for unexpected non-web errors', (t) => { + await t.test('should not generate web error metric for unexpected non-web errors', (t) => { + const { agent, errors } = t.nr const transaction = createBackgroundTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.WEB) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.WEB) + assert.equal(metric, undefined) }) - t.test('should generate other error metric for unexpected non-web errors', (t) => { + await t.test('should generate other error metric for unexpected non-web errors', (t) => { + const { agent, errors } = t.nr const transaction = createBackgroundTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.OTHER) - t.equal(metric.callCount, 2) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + assert.equal(metric.callCount, 2) }) - t.test('should not generate other error metric for expected non-web errors', (t) => { + await t.test('should not generate other error metric for expected non-web errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.expected_classes = ['Error'] const transaction = createBackgroundTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + assert.equal(metric, undefined) }) - t.test('should not generate other error metric for ignored non-web errors', (t) => { + await t.test('should not generate other error metric for ignored non-web errors', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.ignore_classes = ['Error'] const transaction = createBackgroundTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + assert.equal(metric, undefined) }) - t.test('should not generate other error metric for unexpected web errors', (t) => { + await t.test('should not generate other error metric for unexpected web errors', (t) => { + const { agent, errors } = t.nr const transaction = createWebTransaction(agent) - errorCollector.add(transaction, new Error('error1')) - errorCollector.add(transaction, new Error('error2')) + errors.add(transaction, Error('error1')) + errors.add(transaction, Error('error2')) - errorCollector.onTransactionFinished(transaction) + errors.onTransactionFinished(transaction) - const metric = metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(metric) - t.end() + const metric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + assert.equal(metric, undefined) }) - t.test('clearAll()', (t) => { - let aggregator - - t.beforeEach(() => { - aggregator = agent.errors - }) - - t.test('clears collected errors', (t) => { - aggregator.add(null, new Error('error1')) + await t.test('clearAll() clears collected errors', (t) => { + const { errors } = t.nr + errors.add(null, new Error('error1')) - t.equal(getErrorTraces(aggregator).length, 1) - t.equal(getErrorEvents(aggregator).length, 1) + assert.equal(getErrorTraces(errors).length, 1) + assert.equal(getErrorEvents(errors).length, 1) - aggregator.clearAll() + errors.clearAll() - t.equal(getErrorTraces(aggregator).length, 0) - t.equal(getErrorEvents(aggregator).length, 0) - t.end() - }) - t.end() + assert.equal(getErrorTraces(errors).length, 0) + assert.equal(getErrorEvents(errors).length, 0) }) }) - t.test('traced errors', (t) => { - t.autoend() - let aggregator + await t.test('traced errors', async (t) => { + t.beforeEach(beforeEach) + t.afterEach(afterEach) - t.beforeEach(() => { - aggregator = agent.errors - }) + await t.test('without transaction', async (t) => { + helper.unloadAgent(t.nr.agent) - t.test('without transaction', (t) => { - t.autoend() - t.test('should contain no intrinsic attributes', (t) => { - const error = new Error('some error') - aggregator.add(null, error) + await t.test('should contain no intrinsic attributes', (t) => { + const { errors } = t.nr + const error = Error('some error') + errors.add(null, error) - const errorTraces = getErrorTraces(aggregator) - t.equal(errorTraces.length, 1) + const errorTraces = getErrorTraces(errors) + assert.equal(errorTraces.length, 1) - const attributes = getFirstErrorIntrinsicAttributes(aggregator, t) - t.ok(typeof attributes === 'object') - t.end() + const attributes = getFirstErrorIntrinsicAttributes(errors) + assert.equal(typeof attributes === 'object', true) }) - t.test('should contain supplied custom attributes, with filter rules', (t) => { + await t.test('should contain supplied custom attributes, with filter rules', (t) => { + const { agent, errors } = t.nr agent.config.error_collector.attributes.exclude.push('c') agent.config.emit('error_collector.attributes.exclude') - const error = new Error('some error') + const error = Error('some error') const customAttributes = { a: 'b', c: 'ignored' } - aggregator.add(null, error, customAttributes) + errors.add(null, error, customAttributes) - const attributes = getFirstErrorCustomAttributes(aggregator, t) - t.equal(attributes.a, 'b') - t.notOk(attributes.c) - t.end() + const attributes = getFirstErrorCustomAttributes(errors) + assert.equal(attributes.a, 'b') + assert.equal(attributes.c, undefined) }) }) - t.test('on transaction finished', (t) => { - t.autoend() - t.test('should generate an event if the transaction is an HTTP error', (t) => { + await t.test('on transaction finished', async (t) => { + helper.unloadAgent(t.nr.agent) + + await t.test('should generate an event if the transaction is an HTTP error', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 500) - aggregator.add(transaction) + errors.add(transaction) transaction.end() - const collectedError = getErrorTraces(aggregator)[0] - t.ok(collectedError) - t.end() + const collectedError = getErrorTraces(errors)[0] + assert.ok(collectedError) }) - t.test('should contain CAT intrinsic parameters', (t) => { + await t.test('should contain CAT intrinsic parameters', (t) => { + const { agent, errors } = t.nr agent.config.cross_application_tracer.enabled = true agent.config.distributed_tracing.enabled = false @@ -1687,44 +1557,44 @@ tap.test('Errors', (t) => { transaction.referringTransactionGuid = '1234' transaction.incomingCatId = '2345' - const error = new Error('some error') - aggregator.add(transaction, error) + const error = Error('some error') + errors.add(transaction, error) transaction.end() - const attributes = getFirstErrorIntrinsicAttributes(aggregator, t) + const attributes = getFirstErrorIntrinsicAttributes(errors) - t.ok(typeof attributes === 'object') - t.ok(typeof attributes.path_hash === 'string') - t.equal(attributes.referring_transaction_guid, '1234') - t.equal(attributes.client_cross_process_id, '2345') - t.end() + assert.ok(typeof attributes === 'object') + assert.ok(typeof attributes.path_hash === 'string') + assert.equal(attributes.referring_transaction_guid, '1234') + assert.equal(attributes.client_cross_process_id, '2345') }) - t.test('should contain DT intrinsic parameters', (t) => { + await t.test('should contain DT intrinsic parameters', (t) => { + const { agent, errors } = t.nr agent.config.distributed_tracing.enabled = true agent.config.primary_application_id = 'test' agent.config.account_id = 1 const transaction = createTransaction(agent, 200) const error = new Error('some error') - aggregator.add(transaction, error) + errors.add(transaction, error) transaction.end() - const attributes = getFirstErrorIntrinsicAttributes(aggregator, t) + const attributes = getFirstErrorIntrinsicAttributes(errors) - t.ok(typeof attributes === 'object') - t.equal(attributes.traceId, transaction.traceId) - t.equal(attributes.guid, transaction.id) - t.equal(attributes.priority, transaction.priority) - t.equal(attributes.sampled, transaction.sampled) - t.notOk(attributes.parentId) - t.notOk(attributes.parentSpanId) - t.equal(transaction.sampled, true) - t.ok(transaction.priority > 1) - t.end() + assert.ok(typeof attributes === 'object') + assert.equal(attributes.traceId, transaction.traceId) + assert.equal(attributes.guid, transaction.id) + assert.equal(attributes.priority, transaction.priority) + assert.equal(attributes.sampled, transaction.sampled) + assert.equal(attributes.parentId, undefined) + assert.equal(attributes.parentSpanId, undefined) + assert.equal(transaction.sampled, true) + assert.ok(transaction.priority > 1) }) - t.test('should contain DT intrinsic parameters', (t) => { + await t.test('should contain DT intrinsic parameters', (t) => { + const { agent, errors } = t.nr agent.config.distributed_tracing.enabled = true agent.config.primary_application_id = 'test' agent.config.account_id = 1 @@ -1733,26 +1603,26 @@ tap.test('Errors', (t) => { transaction.isDistributedTrace = null transaction._acceptDistributedTracePayload(payload) - const error = new Error('some error') - aggregator.add(transaction, error) + const error = Error('some error') + errors.add(transaction, error) transaction.end() - const attributes = getFirstErrorIntrinsicAttributes(aggregator, t) - - t.ok(typeof attributes === 'object') - t.equal(attributes.traceId, transaction.traceId) - t.equal(attributes.guid, transaction.id) - t.equal(attributes.priority, transaction.priority) - t.equal(attributes.sampled, transaction.sampled) - t.equal(attributes['parent.type'], 'App') - t.equal(attributes['parent.app'], agent.config.primary_application_id) - t.equal(attributes['parent.account'], agent.config.account_id) - t.notOk(attributes.parentId) - t.notOk(attributes.parentSpanId) - t.end() - }) - - t.test('should contain Synthetics intrinsic parameters', (t) => { + const attributes = getFirstErrorIntrinsicAttributes(errors) + + assert.ok(typeof attributes === 'object') + assert.equal(attributes.traceId, transaction.traceId) + assert.equal(attributes.guid, transaction.id) + assert.equal(attributes.priority, transaction.priority) + assert.equal(attributes.sampled, transaction.sampled) + assert.equal(attributes['parent.type'], 'App') + assert.equal(attributes['parent.app'], agent.config.primary_application_id) + assert.equal(attributes['parent.account'], agent.config.account_id) + assert.equal(attributes.parentId, undefined) + assert.equal(attributes.parentSpanId, undefined) + }) + + await t.test('should contain Synthetics intrinsic parameters', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 200) transaction.syntheticsData = { @@ -1763,388 +1633,395 @@ tap.test('Errors', (t) => { monitorId: 'monId' } - const error = new Error('some error') - aggregator.add(transaction, error) + const error = Error('some error') + errors.add(transaction, error) transaction.end() - const attributes = getFirstErrorIntrinsicAttributes(aggregator, t) + const attributes = getFirstErrorIntrinsicAttributes(errors) - t.ok(typeof attributes === 'object') - t.equal(attributes.synthetics_resource_id, 'resId') - t.equal(attributes.synthetics_job_id, 'jobId') - t.equal(attributes.synthetics_monitor_id, 'monId') - t.end() + assert.ok(typeof attributes === 'object') + assert.equal(attributes.synthetics_resource_id, 'resId') + assert.equal(attributes.synthetics_job_id, 'jobId') + assert.equal(attributes.synthetics_monitor_id, 'monId') }) - t.test('should contain custom parameters', (t) => { + await t.test('should contain custom parameters', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 500) - const error = new Error('some error') + const error = Error('some error') const customParameters = { a: 'b' } - aggregator.add(transaction, error, customParameters) + errors.add(transaction, error, customParameters) transaction.end() - const attributes = getFirstErrorCustomAttributes(aggregator, t) - t.equal(attributes.a, 'b') - t.end() + const attributes = getFirstErrorCustomAttributes(errors) + assert.equal(attributes.a, 'b') }) - t.test('should merge supplied custom params with those on the trace', (t) => { + await t.test('should merge supplied custom params with those on the trace', (t) => { + const { agent, errors } = t.nr agent.config.attributes.enabled = true const transaction = createTransaction(agent, 500) transaction.trace.addCustomAttribute('a', 'b') - const error = new Error('some error') + const error = Error('some error') const customParameters = { c: 'd' } - aggregator.add(transaction, error, customParameters) + errors.add(transaction, error, customParameters) transaction.end() - const attributes = getFirstErrorCustomAttributes(aggregator, t) - t.equal(attributes.a, 'b') - t.equal(attributes.c, 'd') - t.end() + const attributes = getFirstErrorCustomAttributes(errors) + assert.equal(attributes.a, 'b') + assert.equal(attributes.c, 'd') }) - t.end() }) }) - t.test('error events', (t) => { - t.autoend() - let aggregator - - t.beforeEach(() => { - aggregator = agent.errors - }) + await t.test('error events', async (t) => { + t.beforeEach(beforeEach) + t.afterEach(afterEach) - t.test('should omit the error message when in high security mode', (t) => { + await t.test('should omit the error message when in high security mode', (t) => { + const { agent } = t.nr agent.config.high_security = true agent.errors.add(null, new Error('some error')) const events = getErrorEvents(agent.errors) - t.equal(events[0][0]['error.message'], '') + assert.equal(events[0][0]['error.message'], '') agent.config.high_security = false - t.end() }) - t.test('not spill over reservoir size', (t) => { - if (agent) { - helper.unloadAgent(agent) - } - agent = helper.loadMockedAgent({ error_collector: { max_event_samples_stored: 10 } }) + await t.test('not spill over reservoir size', (t) => { + helper.unloadAgent(t.nr.agent) + const agent = helper.loadMockedAgent({ error_collector: { max_event_samples_stored: 10 } }) + t.after(() => helper.unloadAgent(agent)) for (let i = 0; i < 20; i++) { - agent.errors.add(null, new Error('some error')) + agent.errors.add(null, Error('some error')) } const events = getErrorEvents(agent.errors) - t.equal(events.length, 10) - t.end() + assert.equal(events.length, 10) }) - t.test('without transaction', (t) => { - t.test('using add()', (t) => { - t.test('should contain intrinsic attributes', (t) => { - const error = new Error('some error') + await t.test('without transaction', async (t) => { + helper.unloadAgent(t.nr.agent) + + await t.test('using add()', async (t) => { + helper.unloadAgent(t.nr.agent) + + await t.test('should contain intrinsic attributes', (t) => { + const { errors } = t.nr + const error = Error('some error') const nowSeconds = Date.now() / 1000 - aggregator.add(null, error) - - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.ok(typeof attributes === 'object') - t.equal(attributes.type, 'TransactionError') - t.ok(typeof attributes['error.class'] === 'string') - t.ok(typeof attributes['error.message'] === 'string') - t.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) - t.equal(attributes.transactionName, 'Unknown') - t.end() + errors.add(null, error) + + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.ok(typeof attributes === 'object') + assert.equal(attributes.type, 'TransactionError') + assert.ok(typeof attributes['error.class'] === 'string') + assert.ok(typeof attributes['error.message'] === 'string') + assert.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) + assert.equal(attributes.transactionName, 'Unknown') }) - t.test('should not contain guid intrinsic attributes', (t) => { - const error = new Error('some error') - aggregator.add(null, error) + await t.test('should not contain guid intrinsic attributes', (t) => { + const { errors } = t.nr + const error = Error('some error') + errors.add(null, error) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.notOk(attributes.guid) - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.guid, undefined) }) - t.test('should set transactionName to Unknown', (t) => { - const error = new Error('some error') - aggregator.add(null, error) + await t.test('should set transactionName to Unknown', (t) => { + const { errors } = t.nr + const error = Error('some error') + errors.add(null, error) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.transactionName, 'Unknown') - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.transactionName, 'Unknown') }) - t.test('should contain supplied custom attributes, with filter rules', (t) => { + await t.test('should contain supplied custom attributes, with filter rules', (t) => { + const { agent, errors } = t.nr agent.config.attributes.enabled = true agent.config.attributes.exclude.push('c') agent.config.emit('attributes.exclude') - const error = new Error('some error') + const error = Error('some error') const customAttributes = { a: 'b', c: 'ignored' } - aggregator.add(null, error, customAttributes) + errors.add(null, error, customAttributes) - const attributes = getFirstEventCustomAttributes(aggregator, t) - t.equal(Object.keys(attributes).length, 1) - t.equal(attributes.a, 'b') - t.notOk(attributes.c) - t.end() + const attributes = getFirstEventCustomAttributes(errors) + assert.equal(Object.keys(attributes).length, 1) + assert.equal(attributes.a, 'b') + assert.equal(attributes.c, undefined) }) - t.test('should contain agent attributes', (t) => { + await t.test('should contain agent attributes', (t) => { + const { agent, errors } = t.nr agent.config.attributes.enabled = true - const error = new Error('some error') - aggregator.add(null, error, { a: 'a' }) + const error = Error('some error') + errors.add(null, error, { a: 'a' }) - const agentAttributes = getFirstEventAgentAttributes(aggregator, t) - const customAttributes = getFirstEventCustomAttributes(aggregator, t) + const agentAttributes = getFirstEventAgentAttributes(errors) + const customAttributes = getFirstEventCustomAttributes(errors) - t.equal(Object.keys(customAttributes).length, 1) - t.equal(Object.keys(agentAttributes).length, 0) - t.end() + assert.equal(Object.keys(customAttributes).length, 1) + assert.equal(Object.keys(agentAttributes).length, 0) }) - t.end() }) - t.test('using noticeError() API', (t) => { - let api - t.beforeEach(() => { - api = new API(agent) + await t.test('using noticeError() API', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) + ctx.nr.api = new API(ctx.nr.agent) }) - t.test('should contain intrinsic parameters', (t) => { - const error = new Error('some error') + await t.test('should contain intrinsic parameters', (t) => { + const { api, errors } = t.nr + const error = Error('some error') const nowSeconds = Date.now() / 1000 api.noticeError(error) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.ok(typeof attributes === 'object') - t.equal(attributes.type, 'TransactionError') - t.ok(typeof attributes['error.class'] === 'string') - t.ok(typeof attributes['error.message'] === 'string') - t.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) - t.equal(attributes.transactionName, 'Unknown') - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.ok(typeof attributes === 'object') + assert.equal(attributes.type, 'TransactionError') + assert.ok(typeof attributes['error.class'] === 'string') + assert.ok(typeof attributes['error.message'] === 'string') + assert.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) + assert.equal(attributes.transactionName, 'Unknown') }) - t.test('should set transactionName to Unknown', (t) => { - const error = new Error('some error') + await t.test('should set transactionName to Unknown', (t) => { + const { api, errors } = t.nr + const error = Error('some error') api.noticeError(error) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.transactionName, 'Unknown') - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.transactionName, 'Unknown') }) - t.test('should contain expected attributes, with filter rules', (t) => { + await t.test('should contain expected attributes, with filter rules', (t) => { + const { agent, api, errors } = t.nr agent.config.attributes.enabled = true agent.config.attributes.exclude = ['c'] agent.config.emit('attributes.exclude') - const error = new Error('some error') + const error = Error('some error') let customAttributes = { a: 'b', c: 'ignored' } api.noticeError(error, customAttributes) - const agentAttributes = getFirstEventAgentAttributes(aggregator, t) - customAttributes = getFirstEventCustomAttributes(aggregator, t) + const agentAttributes = getFirstEventAgentAttributes(errors) + customAttributes = getFirstEventCustomAttributes(errors) - t.equal(Object.keys(customAttributes).length, 1) - t.notOk(customAttributes.c) - t.equal(Object.keys(agentAttributes).length, 0) - t.end() + assert.equal(Object.keys(customAttributes).length, 1) + assert.equal(customAttributes.c, undefined) + assert.equal(Object.keys(agentAttributes).length, 0) }) - t.test('should preserve expected flag for noticeError', (t) => { - const error = new Error('some noticed error') + await t.test('should preserve expected flag for noticeError', (t) => { + const { api, errors } = t.nr + const error = Error('some noticed error') api.noticeError(error, null, true) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['error.expected'], true) - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['error.expected'], true) }) - t.test('unexpected noticeError should default to expected: false', (t) => { - const error = new Error('another noticed error') + + await t.test('unexpected noticeError should default to expected: false', (t) => { + const { api, errors } = t.nr + const error = Error('another noticed error') api.noticeError(error) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['error.expected'], false) - t.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['error.expected'], false) }) - t.test('noticeError expected:true should be definable without customAttributes', (t) => { - const error = new Error('yet another noticed expected error') - api.noticeError(error, true) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['error.expected'], true) - t.end() - }) - t.test('noticeError expected:false should be definable without customAttributes', (t) => { - const error = new Error('yet another noticed unexpected error') - api.noticeError(error, false) + await t.test( + 'noticeError expected:true should be definable without customAttributes', + (t) => { + const { api, errors } = t.nr + const error = Error('yet another noticed expected error') + api.noticeError(error, true) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['error.expected'], false) - t.end() - }) - t.test( + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['error.expected'], true) + } + ) + + await t.test( + 'noticeError expected:false should be definable without customAttributes', + (t) => { + const { api, errors } = t.nr + const error = Error('yet another noticed unexpected error') + api.noticeError(error, false) + + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['error.expected'], false) + } + ) + + await t.test( 'noticeError should not interfere with agentAttributes and customAttributes', (t) => { - const error = new Error('and even yet another noticed error') + const { api, errors } = t.nr + const error = Error('and even yet another noticed error') let customAttributes = { a: 'b', c: 'd' } api.noticeError(error, customAttributes, true) - const agentAttributes = getFirstEventAgentAttributes(aggregator, t) - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - customAttributes = getFirstEventCustomAttributes(aggregator, t) + const agentAttributes = getFirstEventAgentAttributes(errors) + const attributes = getFirstEventIntrinsicAttributes(errors) + customAttributes = getFirstEventCustomAttributes(errors) - t.equal(Object.keys(customAttributes).length, 2) - t.ok(customAttributes.c) - t.equal(attributes['error.expected'], true) - t.equal(Object.keys(agentAttributes).length, 0) - t.end() + assert.equal(Object.keys(customAttributes).length, 2) + assert.ok(customAttributes.c) + assert.equal(attributes['error.expected'], true) + assert.equal(Object.keys(agentAttributes).length, 0) } ) - t.end() }) - t.end() }) - t.test('on transaction finished', (t) => { - t.test('should generate an event if the transaction is an HTTP error', (t) => { + await t.test('on transaction finished', async (t) => { + helper.unloadAgent(t.nr.agent) + + await t.test('should generate an event if the transaction is an HTTP error', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 500) - aggregator.add(transaction) + errors.add(transaction) transaction.end() - const errorEvents = getErrorEvents(aggregator) + const errorEvents = getErrorEvents(errors) const collectedError = errorEvents[0] - t.ok(collectedError) - t.end() + assert.ok(collectedError) }) - t.test('should contain required intrinsic attributes', (t) => { + await t.test('should contain required intrinsic attributes', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 200) - const error = new Error('some error') + const error = Error('some error') const nowSeconds = Date.now() / 1000 - aggregator.add(transaction, error) + errors.add(transaction, error) transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - - t.ok(typeof attributes === 'object') - t.equal(attributes.type, 'TransactionError') - t.ok(typeof attributes['error.class'] === 'string') - t.ok(typeof attributes['error.message'] === 'string') - t.equal(attributes.guid, transaction.id) - t.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) - t.equal(attributes.transactionName, transaction.name) - t.end() - }) - - t.test('transaction-specific intrinsic attributes on a transaction', (t) => { - let transaction - let error - - t.beforeEach(() => { - transaction = createTransaction(agent, 500) - error = new Error('some error') - aggregator.add(transaction, error) + const attributes = getFirstEventIntrinsicAttributes(errors) + + assert.ok(typeof attributes === 'object') + assert.equal(attributes.type, 'TransactionError') + assert.ok(typeof attributes['error.class'] === 'string') + assert.ok(typeof attributes['error.message'] === 'string') + assert.equal(attributes.guid, transaction.id) + assert.ok(Math.abs(attributes.timestamp - nowSeconds) <= 1) + assert.equal(attributes.transactionName, transaction.name) + }) + + await t.test('transaction-specific intrinsic attributes on a transaction', async (t) => { + helper.unloadAgent(t.nr.agent) + t.beforeEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + beforeEach(ctx) + + ctx.nr.tx = createTransaction(ctx.nr.agent, 500) + ctx.nr.error = Error('some error') + ctx.nr.errors.add(ctx.nr.tx, ctx.nr.error) }) - t.test('includes transaction duration', (t) => { - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.duration, transaction.timer.getDurationInMillis() / 1000) - t.end() + await t.test('includes transaction duration', (t) => { + const { errors, tx } = t.nr + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.duration, tx.timer.getDurationInMillis() / 1000) }) - t.test('includes queueDuration if available', (t) => { - transaction.measure(NAMES.QUEUETIME, null, 100) - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.queueDuration, 0.1) - t.end() + await t.test('includes queueDuration if available', (t) => { + const { errors, tx } = t.nr + tx.measure(NAMES.QUEUETIME, null, 100) + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.queueDuration, 0.1) }) - t.test('includes externalDuration if available', (t) => { - transaction.measure(NAMES.EXTERNAL.ALL, null, 100) - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.externalDuration, 0.1) - t.end() + await t.test('includes externalDuration if available', (t) => { + const { errors, tx } = t.nr + tx.measure(NAMES.EXTERNAL.ALL, null, 100) + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.externalDuration, 0.1) }) - t.test('includes databaseDuration if available', (t) => { - transaction.measure(NAMES.DB.ALL, null, 100) - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.databaseDuration, 0.1) - t.end() + await t.test('includes databaseDuration if available', (t) => { + const { errors, tx } = t.nr + tx.measure(NAMES.DB.ALL, null, 100) + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.databaseDuration, 0.1) }) - t.test('includes externalCallCount if available', (t) => { - transaction.measure(NAMES.EXTERNAL.ALL, null, 100) - transaction.measure(NAMES.EXTERNAL.ALL, null, 100) - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.externalCallCount, 2) - t.end() + await t.test('includes externalCallCount if available', (t) => { + const { errors, tx } = t.nr + tx.measure(NAMES.EXTERNAL.ALL, null, 100) + tx.measure(NAMES.EXTERNAL.ALL, null, 100) + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.externalCallCount, 2) }) - t.test('includes databaseCallCount if available', (t) => { - transaction.measure(NAMES.DB.ALL, null, 100) - transaction.measure(NAMES.DB.ALL, null, 100) - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.databaseCallCount, 2) - t.end() + await t.test('includes databaseCallCount if available', (t) => { + const { errors, tx } = t.nr + tx.measure(NAMES.DB.ALL, null, 100) + tx.measure(NAMES.DB.ALL, null, 100) + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.databaseCallCount, 2) }) - t.test('includes internal synthetics attributes', (t) => { - transaction.syntheticsData = { + await t.test('includes internal synthetics attributes', (t) => { + const { errors, tx } = t.nr + tx.syntheticsData = { version: 1, accountId: 123, resourceId: 'resId', jobId: 'jobId', monitorId: 'monId' } - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['nr.syntheticsResourceId'], 'resId') - t.equal(attributes['nr.syntheticsJobId'], 'jobId') - t.equal(attributes['nr.syntheticsMonitorId'], 'monId') - t.end() + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['nr.syntheticsResourceId'], 'resId') + assert.equal(attributes['nr.syntheticsJobId'], 'jobId') + assert.equal(attributes['nr.syntheticsMonitorId'], 'monId') }) - t.test('includes internal transactionGuid attribute', (t) => { - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes['nr.transactionGuid'], transaction.id) - t.end() + await t.test('includes internal transactionGuid attribute', (t) => { + const { errors, tx } = t.nr + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes['nr.transactionGuid'], tx.id) }) - t.test('includes guid attribute', (t) => { - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.guid, transaction.id) - t.end() + await t.test('includes guid attribute', (t) => { + const { errors, tx } = t.nr + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.guid, tx.id) }) - t.test('includes traceId attribute', (t) => { - transaction.referringTransactionGuid = '1234' - transaction.end() - const attributes = getFirstEventIntrinsicAttributes(aggregator, t) - t.equal(attributes.traceId, transaction.traceId) - t.end() + await t.test('includes traceId attribute', (t) => { + const { errors, tx } = t.nr + tx.referringTransactionGuid = '1234' + tx.end() + const attributes = getFirstEventIntrinsicAttributes(errors) + assert.equal(attributes.traceId, tx.traceId) }) - t.test('includes http port if the transaction is a web transaction', (t) => { - const http = require('http') - - helper.unloadAgent(agent) - agent = helper.instrumentMockedAgent() + await t.test('includes http port if the transaction is a web transaction', (t, end) => { + helper.unloadAgent(t.nr.agent) + const agent = helper.instrumentMockedAgent() + t.after(() => helper.unloadAgent(agent)) const server = http.createServer(function createServerCb(req, res) { - t.ok(agent.getTransaction()) + assert.ok(agent.getTransaction()) // Return HTTP error, so that when the transaction ends, an error // event is generated. res.statusCode = 500 @@ -2158,291 +2035,273 @@ tap.test('Errors', (t) => { agent.on('transactionFinished', function (tx) { process.nextTick(() => { - const attributes = getFirstEventIntrinsicAttributes(agent.errors, t) - t.equal(attributes.port, tx.port) + const attributes = getFirstEventIntrinsicAttributes(agent.errors) + assert.equal(attributes.port, tx.port) server.close() - t.end() + end() }) }) }) - t.end() }) - t.test('should contain custom attributes, with filter rules', (t) => { + await t.test('should contain custom attributes, with filter rules', (t) => { + const { agent, errors } = t.nr agent.config.attributes.exclude.push('c') agent.config.emit('attributes.exclude') const transaction = createTransaction(agent, 500) - const error = new Error('some error') + const error = Error('some error') const customAttributes = { a: 'b', c: 'ignored' } - aggregator.add(transaction, error, customAttributes) + errors.add(transaction, error, customAttributes) transaction.end() - const attributes = getFirstEventCustomAttributes(aggregator, t) - t.equal(attributes.a, 'b') - t.notOk(attributes.c) - t.end() + const attributes = getFirstEventCustomAttributes(errors) + assert.equal(attributes.a, 'b') + assert.equal(attributes.c, undefined) }) - t.test('should merge new custom attrs with trace custom attrs', (t) => { + await t.test('should merge new custom attrs with trace custom attrs', (t) => { + const { agent, errors } = t.nr const transaction = createTransaction(agent, 500) transaction.trace.addCustomAttribute('a', 'b') - const error = new Error('some error') + const error = Error('some error') const customAttributes = { c: 'd' } - aggregator.add(transaction, error, customAttributes) + errors.add(transaction, error, customAttributes) transaction.end() - const attributes = getFirstEventCustomAttributes(aggregator, t) - t.equal(Object.keys(attributes).length, 2) - t.equal(attributes.a, 'b') - t.equal(attributes.c, 'd') - t.end() + const attributes = getFirstEventCustomAttributes(errors) + assert.equal(Object.keys(attributes).length, 2) + assert.equal(attributes.a, 'b') + assert.equal(attributes.c, 'd') }) - t.test('should contain agent attributes', (t) => { + await t.test('should contain agent attributes', (t) => { + const { agent, errors } = t.nr agent.config.attributes.enabled = true const transaction = createTransaction(agent, 500) transaction.trace.attributes.addAttribute(DESTS.TRANS_SCOPE, 'host.displayName', 'myHost') const error = new Error('some error') - aggregator.add(transaction, error, { a: 'a' }) + errors.add(transaction, error, { a: 'a' }) transaction.end() - const agentAttributes = getFirstEventAgentAttributes(aggregator, t) - const customAttributes = getFirstEventCustomAttributes(aggregator, t) + const agentAttributes = getFirstEventAgentAttributes(errors) + const customAttributes = getFirstEventCustomAttributes(errors) - t.equal(Object.keys(customAttributes).length, 1) - t.equal(customAttributes.a, 'a') - t.equal(Object.keys(agentAttributes).length, 1) - t.equal(agentAttributes['host.displayName'], 'myHost') - t.end() + assert.equal(Object.keys(customAttributes).length, 1) + assert.equal(customAttributes.a, 'a') + assert.equal(Object.keys(agentAttributes).length, 1) + assert.equal(agentAttributes['host.displayName'], 'myHost') }) - t.end() }) }) }) -function getErrorTraces(errorCollector) { - return errorCollector.traceAggregator.errors -} - -function getErrorEvents(errorCollector) { - return errorCollector.eventAggregator.getEvents() -} - -function getFirstErrorIntrinsicAttributes(aggregator, t) { - return getFirstError(aggregator, t)[4].intrinsics -} - -function getFirstErrorCustomAttributes(aggregator, t) { - return getFirstError(aggregator, t)[4].userAttributes -} - -function getFirstError(aggregator, t) { - const errors = getErrorTraces(aggregator) - t.equal(errors.length, 1) - return errors[0] -} - -function getFirstEventIntrinsicAttributes(aggregator, t) { - return getFirstEvent(aggregator, t)[0] -} - -function getFirstEventCustomAttributes(aggregator, t) { - return getFirstEvent(aggregator, t)[1] -} - -function getFirstEventAgentAttributes(aggregator, t) { - return getFirstEvent(aggregator, t)[2] -} +test('When using the async listener', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.instrumentMockedAgent() -function getFirstEvent(aggregator, t) { - const events = getErrorEvents(aggregator) - t.equal(events.length, 1) - return events[0] -} - -test('When using the async listener', (t) => { - t.autoend() - - let agent = null - let transaction = null - let active = null - let json = null - - t.beforeEach((t) => { - agent = helper.instrumentMockedAgent() - - helper.temporarilyOverrideTapUncaughtBehavior(tap, t) - }) - - t.afterEach(() => { - transaction.end() - - helper.unloadAgent(agent) - agent = null - transaction = null - active = null - json = null - }) - - t.test('should not have a domain active', (t) => { - executeThrowingTransaction(() => { - t.notOk(active) - t.end() + ctx.nr.uncaughtHandler = () => ctx.diagnostic('uncaught handler not defined') + ctx.nr.listeners = process.listeners('uncaughtException') + process.removeAllListeners('uncaughtException') + process.once('uncaughtException', () => { + ctx.nr.uncaughtHandler() }) }) - t.test('should find a single error', (t) => { - executeThrowingTransaction(() => { - const errorTraces = getErrorTraces(agent.errors) - t.equal(errorTraces.length, 1) - t.end() - }) + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) + for (const l of ctx.nr.listeners) { + process.on('uncaughtException', l) + } }) - t.test('should find traced error', (t) => { - executeThrowingTransaction(() => { - t.ok(json) - t.end() + await t.test('should not have a domain active', (t, end) => { + const { agent } = t.nr + let active + t.nr.uncaughtHandler = () => { + assert.equal(active, undefined) + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + active = process.domain + throw Error('sample error') + }) + disruptor() }) }) - t.test('should have 6 elements in the trace', (t) => { - executeThrowingTransaction(() => { - t.equal(json.length, 6) - t.end() + await t.test('should find a single error', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.equal(traces.length, 1) + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') + }) + disruptor() }) }) - t.test('should have the default name', (t) => { - executeThrowingTransaction(() => { - const { 1: name } = json - t.equal(name, 'Unknown') - t.end() + await t.test('should find traced error', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.notEqual(traces[0], undefined) + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') + }) + disruptor() }) }) - t.test("should have the error's message", (t) => { - executeThrowingTransaction(() => { - const { 2: message } = json - t.equal(message, 'sample error') - t.end() + await t.test('should have 6 elements in the trace', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.equal(traces[0].length, 6) + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') + }) + disruptor() }) }) - t.test("should have the error's constructor name (type)", (t) => { - executeThrowingTransaction(() => { - const { 3: name } = json - t.equal(name, 'Error') - t.end() + await t.test('should have the default name', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.equal(traces[0][1], 'Unknown') + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') + }) + disruptor() }) }) - t.test('should default to passing the stack trace as a parameter', (t) => { - executeThrowingTransaction(() => { - const { 4: params } = json - t.ok(params) - t.ok(params.stack_trace) - t.equal(params.stack_trace[0], 'Error: sample error') - t.end() + await t.test('should have the error message', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.equal(traces[0][2], 'sample error') + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') + }) + disruptor() }) }) - function executeThrowingTransaction(handledErrorCallback) { + await t.test('should have the error constructor name (type)', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + assert.equal(traces[0][3], 'Error') + end() + } process.nextTick(() => { - process.once('uncaughtException', () => { - const errorTraces = getErrorTraces(agent.errors) - json = errorTraces[0] - - return handledErrorCallback() + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') }) + disruptor() + }) + }) - const disruptor = agent.tracer.transactionProxy(function transactionProxyCb() { - transaction = agent.getTransaction() - active = process.domain - - // trigger the error handler - throw new Error('sample error') + await t.test('should default to passing the stack trace as a parameter', (t, end) => { + const { agent } = t.nr + t.nr.uncaughtHandler = () => { + const traces = getErrorTraces(agent.errors) + const params = traces[0][4] + assert.notEqual(params, undefined) + assert.notEqual(params.stack_trace, undefined) + assert.equal(params.stack_trace[0], 'Error: sample error') + end() + } + process.nextTick(() => { + const disruptor = agent.tracer.transactionProxy(() => { + throw Error('sample error') }) - disruptor() }) - } + }) }) -tap.test('_processErrors', (t) => { - t.beforeEach((t) => { - t.context.agent = helper.loadMockedAgent({ - attributes: { - enabled: true - } +test('_processErrors', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent({ + attributes: { enabled: true } }) - const transaction = new Transaction(t.context.agent) - transaction.url = '/' - t.context.transaction = transaction - t.context.errorCollector = t.context.agent.errors + const tx = new Transaction(ctx.nr.agent) + tx.url = '/' + ctx.nr.tx = tx + + ctx.nr.errorCollector = ctx.nr.agent.errors }) - t.afterEach((t) => { - helper.unloadAgent(t.context.agent) + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) }) - t.test('invalid errorType should return no iterableProperty', (t) => { - const { errorCollector, transaction } = t.context + await t.test('invalid errorType should return no iterableProperty', (t) => { + const { errorCollector, tx } = t.nr const errorType = 'invalid' - const result = errorCollector._getIterableProperty(transaction, errorType) + const result = errorCollector._getIterableProperty(tx, errorType) - t.equal(result, null) - t.end() + assert.equal(result, null) }) - t.test('if errorType is transaction, should return no iterableProperty', (t) => { - const { errorCollector, transaction } = t.context + await t.test('if errorType is transaction, should return no iterableProperty', (t) => { + const { errorCollector, tx } = t.nr const errorType = 'transaction' - const result = errorCollector._getIterableProperty(transaction, errorType) + const result = errorCollector._getIterableProperty(tx, errorType) - t.equal(result, null) - t.end() + assert.equal(result, null) }) - t.test('if type is user, return an array of objects', (t) => { - const { errorCollector, transaction } = t.context + await t.test('if type is user, return an array of objects', (t) => { + const { errorCollector, tx } = t.nr const errorType = 'user' - const result = errorCollector._getIterableProperty(transaction, errorType) + const result = errorCollector._getIterableProperty(tx, errorType) - t.same(result, []) - t.end() + assert.equal(match(result, []), true) }) - t.test('if type is transactionException, return an array of objects', (t) => { - const { errorCollector, transaction } = t.context + await t.test('if type is transactionException, return an array of objects', (t) => { + const { errorCollector, tx } = t.nr const errorType = 'transactionException' - const result = errorCollector._getIterableProperty(transaction, errorType) + const result = errorCollector._getIterableProperty(tx, errorType) - t.same(result, []) - t.end() + assert.equal(match(result, []), true) }) - t.test( + await t.test( 'if iterableProperty is null and errorType is not transaction, do not modify collectedErrors or expectedErrors', (t) => { - const { errorCollector, transaction } = t.context + const { errorCollector, tx } = t.nr const errorType = 'error' const collectedErrors = 0 const expectedErrors = 0 - const result = errorCollector._processErrors( - transaction, - collectedErrors, - expectedErrors, - errorType - ) + const result = errorCollector._processErrors(tx, collectedErrors, expectedErrors, errorType) - t.same(result, [collectedErrors, expectedErrors]) - t.end() + assert.equal(match(result, [collectedErrors, expectedErrors]), true) } ) - - t.end() }) diff --git a/test/unit/errors/error-event-aggregator.test.js b/test/unit/errors/error-event-aggregator.test.js index cb4c5990b0..1239dfed1a 100644 --- a/test/unit/errors/error-event-aggregator.test.js +++ b/test/unit/errors/error-event-aggregator.test.js @@ -1,79 +1,77 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const ErrorEventAggregator = require('../../../lib/errors/error-event-aggregator') const Metrics = require('../../../lib/metrics') -const sinon = require('sinon') +const { match } = require('../../lib/custom-assertions') const RUN_ID = 1337 const LIMIT = 5 -tap.test('Error Event Aggregator', (t) => { - t.autoend() - let errorEventAggregator - - t.beforeEach(() => { - errorEventAggregator = new ErrorEventAggregator( +test('Error Event Aggregator', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.errorEventAggregator = new ErrorEventAggregator( { config: { error_collector: { enabled: true, capture_events: true } }, runId: RUN_ID, limit: LIMIT, - enabled: (config) => config.error_collector.enabled && config.error_collector.capture_events + enabled(config) { + return config.error_collector.enabled && config.error_collector.capture_events + } }, { collector: {}, metrics: new Metrics(5, {}, {}), - harvester: { add: sinon.stub() } + harvester: { add() {} } } ) - sinon.stub(errorEventAggregator, 'stop') - }) - t.afterEach(() => { - errorEventAggregator = null + ctx.nr.stopped = 0 + ctx.nr.errorEventAggregator.stop = () => { + ctx.nr.stopped += 1 + } }) - t.test('should set the correct default method', (t) => { - const method = errorEventAggregator.method - - t.equal(method, 'error_event_data', 'default method should be error_event_data') - t.end() + await t.test('should set the correct default method', (t) => { + const { errorEventAggregator } = t.nr + assert.equal( + errorEventAggregator.method, + 'error_event_data', + 'default method should be error_event_data' + ) }) - t.test('toPayload() should return json format of data', (t) => { - const expectedMetrics = { - reservoir_size: LIMIT, - events_seen: 1 - } - + await t.test('toPayload() should return json format of data', (t) => { + const { errorEventAggregator } = t.nr + const expectedMetrics = { reservoir_size: LIMIT, events_seen: 1 } const rawErrorEvent = [{ 'type': 'TransactionError', 'error.class': 'class' }, {}, {}] errorEventAggregator.add(rawErrorEvent) const payload = errorEventAggregator._toPayloadSync() - t.equal(payload.length, 3, 'payload length should be 3') + assert.equal(payload.length, 3, 'payload length should be 3') const [runId, eventMetrics, errorEventData] = payload - - t.equal(runId, RUN_ID) - t.same(eventMetrics, expectedMetrics) - t.same(errorEventData, [rawErrorEvent]) - t.end() + assert.equal(runId, RUN_ID) + assert.equal(match(eventMetrics, expectedMetrics), true) + assert.equal(match(errorEventData, [rawErrorEvent]), true) }) - t.test('toPayload() should return nothing with no error event data', (t) => { + await t.test('toPayload() should return nothing with no error event data', (t) => { + const { errorEventAggregator } = t.nr const payload = errorEventAggregator._toPayloadSync() - - t.notOk(payload) - t.end() + assert.equal(payload, undefined) }) - ;[ + + const methodTests = [ { callCount: 1, msg: 'should stop aggregator', @@ -89,13 +87,15 @@ tap.test('Error Event Aggregator', (t) => { msg: 'should not stop aggregator', config: { error_collector: { enabled: true, capture_events: true } } } - ].forEach(({ config, msg, callCount }) => { - t.test(`${msg} if ${JSON.stringify(config)}`, (t) => { - const newConfig = { getAggregatorConfig: sinon.stub(), run_id: 1, ...config } - t.ok(errorEventAggregator.enabled) + ] + for (const methodTest of methodTests) { + const { callCount, config, msg } = methodTest + await t.test(`${msg} if ${JSON.stringify(config)}`, (t) => { + const { errorEventAggregator } = t.nr + const newConfig = { getAggregatorConfig() {}, run_id: 1, ...config } + assert.equal(errorEventAggregator.enabled, true) errorEventAggregator.reconfigure(newConfig) - t.equal(errorEventAggregator.stop.callCount, callCount, msg) - t.end() + assert.equal(t.nr.stopped, callCount, msg) }) - }) + } }) diff --git a/test/unit/errors/error-group.test.js b/test/unit/errors/error-group.test.js index a797454ed4..2ae8b32fce 100644 --- a/test/unit/errors/error-group.test.js +++ b/test/unit/errors/error-group.test.js @@ -1,118 +1,117 @@ /* - * Copyright 2023 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') +const { match } = require('../../lib/custom-assertions') + const helper = require('../../lib/agent_helper') const Transaction = require('../../../lib/transaction') -function getErrorTraces(errorCollector) { - return errorCollector.traceAggregator.errors -} - -function getErrorEvents(errorCollector) { - return errorCollector.eventAggregator.getEvents() -} - -tap.test('Error Group functionality', (t) => { - t.autoend() - let agent = null - - t.beforeEach(() => { - if (agent) { - helper.unloadAgent(agent) - } - agent = helper.loadMockedAgent({ - attributes: { - enabled: true - } - }) +test('Error Group functionality', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent({ attributes: { enabled: true } }) }) - t.afterEach(() => { - helper.unloadAgent(agent) + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) }) - t.test('should set error.group.name attribute when callback is set', (t) => { - const myCallback = function myCallback() { - return 'error-group-test-1' - } + await t.test('should set error.group.name attribute when callback is set', (t) => { + const { agent } = t.nr agent.errors.errorGroupCallback = myCallback - const error = new Error('whoops') - const transaction = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + const error = Error('whoops') + const tx = new Transaction(agent) + agent.errors.add(tx, error) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) const errorEvents = getErrorEvents(agent.errors) + assert.equal( + match(errorTraces[0][4].agentAttributes, { 'error.group.name': 'error-group-test-1' }), + true + ) + assert.equal(match(errorEvents[0][2], { 'error.group.name': 'error-group-test-1' }), true) - t.same(errorTraces[0][4].agentAttributes, { 'error.group.name': 'error-group-test-1' }) - t.same(errorEvents[0][2], { 'error.group.name': 'error-group-test-1' }) - - t.end() + function myCallback() { + return 'error-group-test-1' + } }) - t.test('should not set error.group.name attribute when callback throws', (t) => { - const myCallback = function myCallback() { - throw new Error('boom') - } + await t.test('should not set error.group.name attribute when callback throws', (t) => { + const { agent } = t.nr agent.errors.errorGroupCallback = myCallback - const error = new Error('whoops') - const transaction = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + const error = Error('whoops') + const tx = new Transaction(agent) + agent.errors.add(tx, error) + agent.errors.onTransactionFinished(tx) const errorTraces = getErrorTraces(agent.errors) const errorEvents = getErrorEvents(agent.errors) + assert.equal(match(errorTraces[0][4].agentAttributes, {}), true) + assert.equal(match(errorEvents[0][2], {}), true) - t.same(errorTraces[0][4].agentAttributes, {}) - t.same(errorEvents[0][2], {}) - - t.end() - }) - - t.test('should not set error.group.name attribute when callback returns empty string', (t) => { - const myCallback = function myCallback() { - return '' + function myCallback() { + throw Error('boom') } - agent.errors.errorGroupCallback = myCallback - - const error = new Error('whoops') - const transaction = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) + }) - const errorTraces = getErrorTraces(agent.errors) - const errorEvents = getErrorEvents(agent.errors) + await t.test( + 'should not set error.group.name attribute when callback returns empty string', + (t) => { + const { agent } = t.nr + agent.errors.errorGroupCallback = myCallback - t.same(errorTraces[0][4].agentAttributes, {}) - t.same(errorEvents[0][2], {}) + const error = Error('whoops') + const tx = new Transaction(agent) + agent.errors.add(tx, error) + agent.errors.onTransactionFinished(tx) - t.end() - }) + const errorTraces = getErrorTraces(agent.errors) + const errorEvents = getErrorEvents(agent.errors) + assert.equal(match(errorTraces[0][4].agentAttributes, {}), true) + assert.equal(match(errorEvents[0][2], {}), true) - t.test('should not set error.group.name attribute when callback returns not a string', (t) => { - const myCallback = function myCallback() { - return { 'error.group.name': 'blah' } + function myCallback() { + return '' + } } - agent.errors.errorGroupCallback = myCallback - - const error = new Error('whoops') - const transaction = new Transaction(agent) - agent.errors.add(transaction, error) - agent.errors.onTransactionFinished(transaction) - - const errorTraces = getErrorTraces(agent.errors) - const errorEvents = getErrorEvents(agent.errors) + ) + + await t.test( + 'should not set error.group.name attribute when callback returns not a string', + (t) => { + const { agent } = t.nr + agent.errors.errorGroupCallback = myCallback + + const error = Error('whoops') + const tx = new Transaction(agent) + agent.errors.add(tx, error) + agent.errors.onTransactionFinished(tx) + + const errorTraces = getErrorTraces(agent.errors) + const errorEvents = getErrorEvents(agent.errors) + assert.equal(match(errorTraces[0][4].agentAttributes, {}), true) + assert.equal(match(errorEvents[0][2], {}), true) + + function myCallback() { + return { 'error.group.name': 'blah' } + } + } + ) +}) - t.same(errorTraces[0][4].agentAttributes, {}) - t.same(errorEvents[0][2], {}) +function getErrorTraces(errorCollector) { + return errorCollector.traceAggregator.errors +} - t.end() - }) -}) +function getErrorEvents(errorCollector) { + return errorCollector.eventAggregator.getEvents() +} diff --git a/test/unit/errors/error-trace-aggregator.test.js b/test/unit/errors/error-trace-aggregator.test.js index 9a83380ce7..a22e830907 100644 --- a/test/unit/errors/error-trace-aggregator.test.js +++ b/test/unit/errors/error-trace-aggregator.test.js @@ -1,100 +1,101 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') +const { match } = require('../../lib/custom-assertions') const ErrorTraceAggregator = require('../../../lib/errors/error-trace-aggregator') -const sinon = require('sinon') const RUN_ID = 1337 const LIMIT = 5 -tap.test('Error Trace Aggregator', (t) => { - t.autoend() - let errorTraceAggregator - - t.beforeEach(() => { - errorTraceAggregator = new ErrorTraceAggregator( +test('Error Trace Aggregator', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.errorTraceAggregator = new ErrorTraceAggregator( { config: { collect_errors: true, error_collector: { enabled: true } }, runId: RUN_ID, limit: LIMIT, - enabled: (config) => config.error_collector.enabled && config.collect_errors + enabled(config) { + return config.error_collector.enabled && config.collect_errors + } }, {}, - { add: sinon.stub() } + { add() {} } ) - sinon.stub(errorTraceAggregator, 'stop') - }) - t.afterEach(() => { - errorTraceAggregator = null + ctx.nr.stopped = 0 + ctx.nr.errorTraceAggregator.stop = () => { + ctx.nr.stopped += 1 + } }) - t.test('should set the correct default method', (t) => { - const method = errorTraceAggregator.method - - t.equal(method, 'error_data', 'default method should be error_data') - t.end() + await t.test('should set the correct default method', (t) => { + const { errorTraceAggregator } = t.nr + assert.equal(errorTraceAggregator.method, 'error_data', 'default method should be error_data') }) - t.test('add() should add errors', (t) => { + await t.test('add() should add error', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) const firstError = errorTraceAggregator.errors[0] - t.equal(rawErrorTrace, firstError) - t.end() + assert.equal(rawErrorTrace, firstError) }) - t.test('_getMergeData() should return errors', (t) => { + await t.test('_getMergeData() should return errors', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) const data = errorTraceAggregator._getMergeData() - t.equal(data.length, 1, 'there should be one error') + assert.equal(data.length, 1, 'there should be one error') const firstError = data[0] - t.equal(rawErrorTrace, firstError, '_getMergeData should return the expected error trace') - t.end() + assert.equal(rawErrorTrace, firstError, '_getMergeData should return the expected error trace') }) - t.test('toPayloadSync() should return json format of data', (t) => { + await t.test('toPayloadSync() should return json format of data', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) const payload = errorTraceAggregator._toPayloadSync() - t.equal(payload.length, 2, 'sync payload should have runId and errorTraceData') + assert.equal(payload.length, 2, 'sync payload should have runId and errorTraceData') const [runId, errorTraceData] = payload - t.equal(runId, RUN_ID, 'run ID should match') + assert.equal(runId, RUN_ID, 'run ID should match') const expectedTraceData = [rawErrorTrace] - t.same(errorTraceData, expectedTraceData, 'errorTraceData should match') - t.end() + assert.equal(match(errorTraceData, expectedTraceData), true, 'errorTraceData should match') }) - t.test('toPayload() should return json format of data', (t) => { + await t.test('toPayload() should return json format of data', (t, end) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) errorTraceAggregator._toPayload((err, payload) => { - t.equal(payload.length, 2, 'payload should have two elements') + assert.equal(payload.length, 2, 'payload should have two elements') const [runId, errorTraceData] = payload - t.equal(runId, RUN_ID, 'run ID should match') + assert.equal(runId, RUN_ID, 'run ID should match') const expectedTraceData = [rawErrorTrace] - t.same(errorTraceData, expectedTraceData, 'errorTraceData should match') - t.end() + assert.equal(match(errorTraceData, expectedTraceData), true, 'errorTraceData should match') + end() }) }) - t.test('_merge() should merge passed-in data in order', (t) => { + await t.test('_merge() should merge passed-in data in order', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name1', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) @@ -105,16 +106,16 @@ tap.test('Error Trace Aggregator', (t) => { errorTraceAggregator._merge(mergeData) - t.equal(errorTraceAggregator.errors.length, 3, 'aggregator should have three errors') + assert.equal(errorTraceAggregator.errors.length, 3, 'aggregator should have three errors') const [error1, error2, error3] = errorTraceAggregator.errors - t.equal(error1[1], 'name1', 'error1 should have expected name') - t.equal(error2[1], 'name2', 'error2 should have expected name') - t.equal(error3[1], 'name3', 'error3 should have expected name') - t.end() + assert.equal(error1[1], 'name1', 'error1 should have expected name') + assert.equal(error2[1], 'name2', 'error2 should have expected name') + assert.equal(error3[1], 'name3', 'error3 should have expected name') }) - t.test('_merge() should not merge past limit', (t) => { + await t.test('_merge() should not merge past limit', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name1', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) @@ -128,26 +129,26 @@ tap.test('Error Trace Aggregator', (t) => { errorTraceAggregator._merge(mergeData) - t.equal( + assert.equal( errorTraceAggregator.errors.length, LIMIT, 'aggregator should have received five errors' ) const [error1, error2, error3, error4, error5] = errorTraceAggregator.errors - t.equal(error1[1], 'name1', 'error1 should have expected name') - t.equal(error2[1], 'name2', 'error2 should have expected name') - t.equal(error3[1], 'name3', 'error3 should have expected name') - t.equal(error4[1], 'name4', 'error4 should have expected name') - t.equal(error5[1], 'name5', 'error5 should have expected name') - t.end() + assert.equal(error1[1], 'name1', 'error1 should have expected name') + assert.equal(error2[1], 'name2', 'error2 should have expected name') + assert.equal(error3[1], 'name3', 'error3 should have expected name') + assert.equal(error4[1], 'name4', 'error4 should have expected name') + assert.equal(error5[1], 'name5', 'error5 should have expected name') }) - t.test('clear() should clear errors', (t) => { + await t.test('clear() should clear errors', (t) => { + const { errorTraceAggregator } = t.nr const rawErrorTrace = [0, 'name1', 'message', 'type', {}] errorTraceAggregator.add(rawErrorTrace) - t.equal( + assert.equal( errorTraceAggregator.errors.length, 1, 'before clear(), there should be one error in the aggregator' @@ -155,14 +156,14 @@ tap.test('Error Trace Aggregator', (t) => { errorTraceAggregator.clear() - t.equal( + assert.equal( errorTraceAggregator.errors.length, 0, 'after clear(), there should be nothing in the aggregator' ) - t.end() }) - ;[ + + const methodTests = [ { callCount: 1, msg: 'should stop aggregator', @@ -178,13 +179,15 @@ tap.test('Error Trace Aggregator', (t) => { msg: 'should not stop aggregator', config: { collect_errors: true, error_collector: { enabled: true } } } - ].forEach(({ config, msg, callCount }) => { - t.test(`${msg} if ${JSON.stringify(config)}`, (t) => { - const newConfig = { getAggregatorConfig: sinon.stub(), run_id: 1, ...config } - t.ok(errorTraceAggregator.enabled) + ] + for (const methodTest of methodTests) { + const { callCount, config, msg } = methodTest + await t.test(`${msg} if ${JSON.stringify(config)}`, (t) => { + const { errorTraceAggregator } = t.nr + const newConfig = { getAggregatorConfig() {}, run_id: 1, ...config } + assert.equal(errorTraceAggregator.enabled, true) errorTraceAggregator.reconfigure(newConfig) - t.equal(errorTraceAggregator.stop.callCount, callCount, msg) - t.end() + assert.equal(t.nr.stopped, callCount, msg) }) - }) + } }) diff --git a/test/unit/errors/expected.test.js b/test/unit/errors/expected.test.js index d349c7d72f..01e1c34102 100644 --- a/test/unit/errors/expected.test.js +++ b/test/unit/errors/expected.test.js @@ -1,91 +1,92 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const helper = require('../../lib/agent_helper') -const NAMES = require('../../../lib/metrics/names.js') -const Exception = require('../../../lib/errors').Exception +const { APDEX, ERRORS } = require('../../../lib/metrics/names') +const { Exception } = require('../../../lib/errors') const urltils = require('../../../lib/util/urltils') const errorHelper = require('../../../lib/errors/helper') const API = require('../../../api') -tap.test('Expected Errors, when expected configuration is present', (t) => { - t.autoend() - let agent - - t.beforeEach(() => { - agent = helper.loadMockedAgent() +test('Expected Errors, when expected configuration is present', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent() }) - t.afterEach(() => { - helper.unloadAgent(agent) - agent = null + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) }) - t.test('expected status code should not increment apdex frustrating', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('expected status code should not increment apdex frustrating', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.expected_status_codes = [500] tx.statusCode = 500 - const apdexStats = tx.metrics.getOrCreateApdexMetric(NAMES.APDEX) - tx._setApdex(NAMES.APDEX, 1, 1) + + const apdexStats = tx.metrics.getOrCreateApdexMetric(APDEX) + tx._setApdex(APDEX, 1, 1) const json = apdexStats.toJSON() tx.end() - // no errors in the frustrating column - t.equal(json[2], 0) - t.end() + assert.equal(json[2], 0, 'should be no errors in the frustrating column') + end() }) }) - t.test('expected messages', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('expected messages', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.capture_events = true agent.config.error_collector.expected_messages = { Error: ['expected'] } - let error = new Error('expected') + let error = Error('expected') let exception = new Exception({ error }) tx.addException(exception) - error = new Error('NOT expected') + error = Error('NOT expected') exception = new Exception({ error }) tx.addException(exception) tx.end() const errorUnexpected = agent.errors.eventAggregator.getEvents()[0] - t.equal( + assert.equal( errorUnexpected[0]['error.message'], 'NOT expected', 'should be able to test unexpected errors' ) - t.equal( + assert.equal( errorUnexpected[0]['error.expected'], false, 'unexpected errors should not have error.expected' ) const errorExpected = agent.errors.eventAggregator.getEvents()[1] - t.equal( + assert.equal( errorExpected[0]['error.message'], 'expected', 'should be able to test expected errors' ) - t.equal( + assert.equal( errorExpected[0]['error.expected'], true, 'expected errors should have error.expected' ) - t.end() + end() }) }) - t.test('expected classes', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('expected classes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.capture_events = true agent.config.error_collector.expected_classes = ['ReferenceError'] @@ -93,41 +94,43 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { let exception = new Exception({ error }) tx.addException(exception) - error = new Error('NOT expected') + error = Error('NOT expected') exception = new Exception({ error }) tx.addException(exception) tx.end() const errorUnexpected = agent.errors.eventAggregator.getEvents()[0] - t.equal( + assert.equal( errorUnexpected[0]['error.message'], 'NOT expected', 'should be able to test class-unexpected error' ) - t.notOk( + assert.equal( errorUnexpected[2]['error.expected'], + undefined, 'class-unexpected error should not have error.expected' ) const errorExpected = agent.errors.eventAggregator.getEvents()[1] - t.equal( + assert.equal( errorExpected[0]['error.message'], 'expected', 'should be able to test class-expected error' ) - t.equal( + assert.equal( errorExpected[0]['error.expected'], true, 'class-expected error should have error.expected' ) - t.end() + end() }) }) - t.test('expected messages by type', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('expected messages by type', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.capture_events = true agent.config.error_collector.expected_messages = { ReferenceError: ['expected if a ReferenceError'] @@ -137,51 +140,57 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { let exception = new Exception({ error }) tx.addException(exception) - error = new Error('expected if a ReferenceError') + error = Error('expected if a ReferenceError') exception = new Exception({ error }) tx.addException(exception) tx.end() const errorUnexpected = agent.errors.eventAggregator.getEvents()[0] - t.equal(errorUnexpected[0]['error.class'], 'Error') - t.notOk( + assert.equal(errorUnexpected[0]['error.class'], 'Error') + assert.equal( errorUnexpected[2]['error.expected'], + undefined, 'type-unexpected errors should not have error.expected' ) const errorExpected = agent.errors.eventAggregator.getEvents()[1] - t.equal(errorExpected[0]['error.class'], 'ReferenceError') - t.equal( + assert.equal(errorExpected[0]['error.class'], 'ReferenceError') + assert.equal( errorExpected[0]['error.expected'], true, 'type-expected errors should have error.expected' ) - t.end() + end() }) }) - t.test('expected errors raised via noticeError should not increment apdex frustrating', (t) => { - helper.runInTransaction(agent, function (tx) { - const api = new API(agent) - api.noticeError(new Error('we expected something to go wrong'), {}, true) - const apdexStats = tx.metrics.getOrCreateApdexMetric(NAMES.APDEX) - tx._setApdex(NAMES.APDEX, 1, 1) - const json = apdexStats.toJSON() - tx.end() - // no errors in the frustrating column - t.equal(json[2], 0) - t.end() - }) - }) - - t.test('should increment expected error metric call counts', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test( + 'expected errors raised via noticeError should not increment apdex frustrating', + (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { + const api = new API(agent) + api.noticeError(new Error('we expected something to go wrong'), {}, true) + const apdexStats = tx.metrics.getOrCreateApdexMetric(APDEX) + tx._setApdex(APDEX, 1, 1) + const json = apdexStats.toJSON() + tx.end() + + assert.equal(json[2], 0, 'shold be no errors in the frustrating column') + end() + }) + } + ) + + await t.test('should increment expected error metric call counts', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.capture_events = true agent.config.error_collector.expected_classes = ['Error'] - const error1 = new Error('expected') + const error1 = Error('expected') const error2 = new ReferenceError('NOT expected') const exception1 = new Exception({ error: error1 }) const exception2 = new Exception({ error: error2 }) @@ -190,26 +199,27 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { tx.addException(exception2) tx.end() - const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) + const transactionErrorMetric = agent.metrics.getMetric(ERRORS.PREFIX + tx.getFullName()) - const expectedErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.EXPECTED) + const expectedErrorMetric = agent.metrics.getMetric(ERRORS.EXPECTED) - t.equal( + assert.equal( transactionErrorMetric.callCount, 1, 'transactionErrorMetric.callCount should equal 1' ) - t.equal(expectedErrorMetric.callCount, 1, 'expectedErrorMetric.callCount should equal 1') - t.end() + assert.equal(expectedErrorMetric.callCount, 1, 'expectedErrorMetric.callCount should equal 1') + end() }) }) - t.test('should not increment error metric call counts, web transaction', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('should not increment error metric call counts, web transaction', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.capture_events = true agent.config.error_collector.expected_classes = ['Error'] - const error1 = new Error('expected') + const error1 = Error('expected') const error2 = new ReferenceError('NOT expected') const exception1 = new Exception({ error: error1 }) const exception2 = new Exception({ error: error2 }) @@ -218,27 +228,28 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { tx.addException(exception2) tx.end() - const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) + const transactionErrorMetric = agent.metrics.getMetric(ERRORS.PREFIX + tx.getFullName()) - const allErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.ALL) - const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) - const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + const allErrorMetric = agent.metrics.getMetric(ERRORS.ALL) + const webErrorMetric = agent.metrics.getMetric(ERRORS.WEB) + const otherErrorMetric = agent.metrics.getMetric(ERRORS.OTHER) - t.equal(transactionErrorMetric.callCount, 1, '') + assert.equal(transactionErrorMetric.callCount, 1, '') - t.equal(allErrorMetric.callCount, 1, 'allErrorMetric.callCount should equal 1') - t.equal(webErrorMetric.callCount, 1, 'webErrorMetric.callCount should equal 1') - t.notOk(otherErrorMetric, 'should not create other error metrics') - t.end() + assert.equal(allErrorMetric.callCount, 1, 'allErrorMetric.callCount should equal 1') + assert.equal(webErrorMetric.callCount, 1, 'webErrorMetric.callCount should equal 1') + assert.equal(otherErrorMetric, undefined, 'should not create other error metrics') + end() }) }) - t.test('should not generate any error metrics during expected status code', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('should not generate any error metrics during expected status code', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.expected_status_codes = [500] tx.statusCode = 500 - const error1 = new Error('expected') + const error1 = Error('expected') const error2 = new ReferenceError('NOT expected') const exception1 = new Exception({ error: error1 }) const exception2 = new Exception({ error: error2 }) @@ -247,28 +258,29 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { tx.addException(exception2) tx.end() - const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) + const transactionErrorMetric = agent.metrics.getMetric(ERRORS.PREFIX + tx.getFullName()) - const allErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.ALL) - const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) - const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + const allErrorMetric = agent.metrics.getMetric(ERRORS.ALL) + const webErrorMetric = agent.metrics.getMetric(ERRORS.WEB) + const otherErrorMetric = agent.metrics.getMetric(ERRORS.OTHER) - t.notOk(transactionErrorMetric, 'should not create transactionErrorMetrics') + assert.equal(transactionErrorMetric, undefined, 'should not create transactionErrorMetrics') - t.notOk(allErrorMetric, 'should not create NAMES.ERRORS.ALL metrics') - t.notOk(webErrorMetric, 'should not create NAMES.ERRORS.WEB metrics') - t.notOk(otherErrorMetric, 'should not create NAMES.ERRORS.OTHER metrics') - t.end() + assert.equal(allErrorMetric, undefined, 'should not create ERRORS.ALL metrics') + assert.equal(webErrorMetric, undefined, 'should not create ERRORS.WEB metrics') + assert.equal(otherErrorMetric, undefined, 'should not create ERRORS.OTHER metrics') + end() }) }) - t.test('should not increment error metric call counts, bg transaction', (t) => { + await t.test('should not increment error metric call counts, bg transaction', (t, end) => { + const { agent } = t.nr helper.runInTransaction(agent, function (tx) { tx.type = 'BACKGROUND' agent.config.error_collector.capture_events = true agent.config.error_collector.expected_classes = ['Error'] - const error1 = new Error('expected') + const error1 = Error('expected') const error2 = new ReferenceError('NOT expected') const exception1 = new Exception({ error: error1 }) const exception2 = new Exception({ error: error2 }) @@ -277,44 +289,46 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { tx.addException(exception2) tx.end() - const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) + const transactionErrorMetric = agent.metrics.getMetric(ERRORS.PREFIX + tx.getFullName()) - const allErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.ALL) - const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) - const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + const allErrorMetric = agent.metrics.getMetric(ERRORS.ALL) + const webErrorMetric = agent.metrics.getMetric(ERRORS.WEB) + const otherErrorMetric = agent.metrics.getMetric(ERRORS.OTHER) - t.equal( + assert.equal( transactionErrorMetric.callCount, 1, 'should increment transactionErrorMetric.callCount' ) - t.equal(allErrorMetric.callCount, 1, 'should increment allErrorMetric.callCount') - t.notOk(webErrorMetric, 'should not increment webErrorMetric') - t.equal(otherErrorMetric.callCount, 1, 'should increment otherErrorMetric.callCount') - t.end() + assert.equal(allErrorMetric.callCount, 1, 'should increment allErrorMetric.callCount') + assert.equal(webErrorMetric, undefined, 'should not increment webErrorMetric') + assert.equal(otherErrorMetric.callCount, 1, 'should increment otherErrorMetric.callCount') + end() }) }) - t.test('should not increment error metric call counts, bg transaction', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('should not increment error metric call counts, bg transaction', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { agent.config.error_collector.expected_messages = { Error: ['except this error'] } const error = new Error('except this error') const exception = new Exception({ error }) const result = errorHelper.isExpectedException(tx, exception, agent.config, urltils) - t.equal(result, true) - t.end() + assert.equal(result, true) + end() }) }) - t.test('status code + "all expected" errors should not affect apdex', (t) => { + await t.test('status code + "all expected" errors should not affect apdex', (t, end) => { + const { agent } = t.nr // when we have an error-like status code, and all the collected errors // are expected, we can safely assume that the error-like status code // came from an expected error - helper.runInTransaction(agent, function (tx) { + helper.runInTransaction(agent, (tx) => { tx.statusCode = 500 - const apdexStats = tx.metrics.getOrCreateApdexMetric(NAMES.APDEX) + const apdexStats = tx.metrics.getOrCreateApdexMetric(APDEX) const errorCollector = agent.config.error_collector errorCollector.expected_messages = { Error: ['apdex is frustrating'] @@ -323,7 +337,7 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { ReferenceError: ['apdex is frustrating'] } - let error = new Error('apdex is frustrating') + let error = Error('apdex is frustrating') let exception = new Exception({ error }) tx.addException(exception) @@ -331,46 +345,48 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { exception = new Exception({ error }) tx.addException(exception) - t.equal(tx.hasOnlyExpectedErrors(), true) + assert.equal(tx.hasOnlyExpectedErrors(), true) - tx._setApdex(NAMES.APDEX, 1, 1) + tx._setApdex(APDEX, 1, 1) const json = apdexStats.toJSON() tx.end() // no errors in the frustrating column - t.equal(json[2], 0) - t.end() + assert.equal(json[2], 0) + end() }) }) - t.test('status code + no expected errors should frustrate apdex', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('status code + no expected errors should frustrate apdex', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { tx.statusCode = 500 - const apdexStats = tx.metrics.getOrCreateApdexMetric(NAMES.APDEX) - t.equal(tx.hasOnlyExpectedErrors(), false) + const apdexStats = tx.metrics.getOrCreateApdexMetric(APDEX) + assert.equal(tx.hasOnlyExpectedErrors(), false) - tx._setApdex(NAMES.APDEX, 1, 1) + tx._setApdex(APDEX, 1, 1) const json = apdexStats.toJSON() tx.end() - // should put an error in the frustrating column - t.equal(json[2], 1) - t.end() + + assert.equal(json[2], 1, 'should put an error in the frustrating column') + end() }) }) - t.test('status code + "not all expected" errors should frustrate apdex', (t) => { + await t.test('status code + "not all expected" errors should frustrate apdex', (t, end) => { + const { agent } = t.nr // when we have an error-like status code, and some of the collected // errors are expected, but others are not, we have no idea which error - // resulted in the error-like status code. Therefore we still bump + // resulted in the error-like status code. Therefore, we still bump // apdex to frustrating. - helper.runInTransaction(agent, function (tx) { + helper.runInTransaction(agent, (tx) => { tx.statusCode = 500 - const apdexStats = tx.metrics.getOrCreateApdexMetric(NAMES.APDEX) + const apdexStats = tx.metrics.getOrCreateApdexMetric(APDEX) agent.config.error_collector.expected_messages = { Error: ['apdex is frustrating'] } - let error = new Error('apdex is frustrating') + let error = Error('apdex is frustrating') let exception = new Exception({ error }) tx.addException(exception) @@ -378,12 +394,12 @@ tap.test('Expected Errors, when expected configuration is present', (t) => { exception = new Exception({ error }) tx.addException(exception) - tx._setApdex(NAMES.APDEX, 1, 1) + tx._setApdex(APDEX, 1, 1) const json = apdexStats.toJSON() tx.end() - // should have an error in the frustrating column - t.equal(json[2], 1) - t.end() + + assert.equal(json[2], 1, 'should have an error in the frustrating column') + end() }) }) }) diff --git a/test/unit/errors/ignore.test.js b/test/unit/errors/ignore.test.js index a02ce8b530..c4f4a223cd 100644 --- a/test/unit/errors/ignore.test.js +++ b/test/unit/errors/ignore.test.js @@ -1,42 +1,41 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const helper = require('../../lib/agent_helper') -const NAMES = require('../../../lib/metrics/names.js') +const NAMES = require('../../../lib/metrics/names') -tap.test('Ignored Errors', (t) => { - t.autoend() - - let agent = null - - t.beforeEach(() => { - agent = helper.loadMockedAgent() +test('Ignored Errors', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent() }) - t.afterEach(() => { - helper.unloadAgent(agent) + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) }) - t.test('Ignore Classes should result in no error reported', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore Classes should result in no error reported', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_classes = ['Error'] - const error1 = new Error('ignored') + const error1 = Error('ignored') const error2 = new ReferenceError('NOT ignored') errorAggr.add(tx, error1) errorAggr.add(tx, error2) tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 1) + assert.equal(errorAggr.traceAggregator.errors.length, 1) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -44,32 +43,33 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.equal(transactionErrorMetric.callCount, 1) + assert.equal(transactionErrorMetric.callCount, 1) - t.equal(allErrorMetric.callCount, 1) - t.equal(webErrorMetric.callCount, 1) + assert.equal(allErrorMetric.callCount, 1) + assert.equal(webErrorMetric.callCount, 1) - t.notOk(otherErrorMetric) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) - t.test('Ignore Classes should trump expected classes', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore Classes should trump expected classes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_classes = ['Error'] agent.config.error_collector.expected_classes = ['Error'] - const error1 = new Error('ignored') + const error1 = Error('ignored') const error2 = new ReferenceError('NOT ignored') errorAggr.add(tx, error1) errorAggr.add(tx, error2) tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 1) + assert.equal(errorAggr.traceAggregator.errors.length, 1) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -77,24 +77,25 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.equal(transactionErrorMetric.callCount, 1) + assert.equal(transactionErrorMetric.callCount, 1) - t.equal(allErrorMetric.callCount, 1) - t.equal(webErrorMetric.callCount, 1) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric.callCount, 1) + assert.equal(webErrorMetric.callCount, 1) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) - t.test('Ignore messages should result in no error reported', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore messages should result in no error reported', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_messages = { Error: ['ignored'] } - const error1 = new Error('ignored') - const error2 = new Error('not ignored') + const error1 = Error('ignored') + const error2 = Error('not ignored') const error3 = new ReferenceError('not ignored') errorAggr.add(tx, error1) @@ -103,7 +104,7 @@ tap.test('Ignored Errors', (t) => { tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 2) + assert.equal(errorAggr.traceAggregator.errors.length, 2) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -111,25 +112,26 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.equal(transactionErrorMetric.callCount, 2) + assert.equal(transactionErrorMetric.callCount, 2) - t.equal(allErrorMetric.callCount, 2) - t.equal(webErrorMetric.callCount, 2) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric.callCount, 2) + assert.equal(webErrorMetric.callCount, 2) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) - t.test('Ignore messages should trump expected_messages', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore messages should trump expected_messages', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_messages = { Error: ['ignore'] } agent.config.error_collector.expected_messages = { Error: ['ignore'] } - const error1 = new Error('ignore') - const error2 = new Error('not ignore') + const error1 = Error('ignore') + const error2 = Error('not ignore') const error3 = new ReferenceError('not ignore') errorAggr.add(tx, error1) @@ -138,7 +140,7 @@ tap.test('Ignored Errors', (t) => { tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 2) + assert.equal(errorAggr.traceAggregator.errors.length, 2) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -146,25 +148,26 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.equal(transactionErrorMetric.callCount, 2) + assert.equal(transactionErrorMetric.callCount, 2) - t.equal(allErrorMetric.callCount, 2) - t.equal(webErrorMetric.callCount, 2) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric.callCount, 2) + assert.equal(webErrorMetric.callCount, 2) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) - t.test('Ignore status code should result in 0 errors reported', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore status code should result in 0 errors reported', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_status_codes = [500] tx.statusCode = 500 - const error1 = new Error('ignore') - const error2 = new Error('ignore me too') + const error1 = Error('ignore') + const error2 = Error('ignore me too') const error3 = new ReferenceError('i will also be ignored') errorAggr.add(tx, error1) @@ -173,7 +176,7 @@ tap.test('Ignored Errors', (t) => { tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 0) + assert.equal(errorAggr.traceAggregator.errors.length, 0) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -181,62 +184,69 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(transactionErrorMetric) + assert.equal(transactionErrorMetric, undefined) - t.notOk(allErrorMetric) - t.notOk(webErrorMetric) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric, undefined) + assert.equal(webErrorMetric, undefined) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) - t.test('Ignore status code should ignore when status set after collecting errors', (t) => { - helper.runInTransaction(agent, function (tx) { - const errorAggr = agent.errors - agent.config.error_collector.capture_events = true - agent.config.error_collector.ignore_status_codes = [500] + await t.test( + 'Ignore status code should ignore when status set after collecting errors', + (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { + const errorAggr = agent.errors + agent.config.error_collector.capture_events = true + agent.config.error_collector.ignore_status_codes = [500] - const error1 = new Error('ignore') - const error2 = new Error('ignore me too') - const error3 = new ReferenceError('i will also be ignored') + const error1 = Error('ignore') + const error2 = Error('ignore me too') + const error3 = new ReferenceError('i will also be ignored') - errorAggr.add(tx, error1) - errorAggr.add(tx, error2) - errorAggr.add(tx, error3) + errorAggr.add(tx, error1) + errorAggr.add(tx, error2) + errorAggr.add(tx, error3) - // important: set code after collecting errors for test case - tx.statusCode = 500 - tx.end() + // important: set code after collecting errors for test case + tx.statusCode = 500 + tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 0) + assert.equal(errorAggr.traceAggregator.errors.length, 0) - const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) + const transactionErrorMetric = agent.metrics.getMetric( + NAMES.ERRORS.PREFIX + tx.getFullName() + ) - const allErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.ALL) - const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) - const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) + const allErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.ALL) + const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) + const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(transactionErrorMetric) + assert.equal(transactionErrorMetric, undefined) - t.notOk(allErrorMetric) - t.notOk(webErrorMetric) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric, undefined) + assert.equal(webErrorMetric, undefined) + assert.equal(otherErrorMetric, undefined) - t.end() - }) - }) + end() + }) + } + ) - t.test('Ignore status code should trump expected status code', (t) => { - helper.runInTransaction(agent, function (tx) { + await t.test('Ignore status code should trump expected status code', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, (tx) => { const errorAggr = agent.errors agent.config.error_collector.capture_events = true agent.config.error_collector.ignore_status_codes = [500] agent.config.error_collector.expected_status_codes = [500] tx.statusCode = 500 - const error1 = new Error('ignore') - const error2 = new Error('also ignore') + const error1 = Error('ignore') + const error2 = Error('also ignore') const error3 = new ReferenceError('i will also be ignored') errorAggr.add(tx, error1) @@ -245,7 +255,7 @@ tap.test('Ignored Errors', (t) => { tx.end() - t.equal(errorAggr.traceAggregator.errors.length, 0) + assert.equal(errorAggr.traceAggregator.errors.length, 0) const transactionErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.PREFIX + tx.getFullName()) @@ -253,13 +263,13 @@ tap.test('Ignored Errors', (t) => { const webErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.WEB) const otherErrorMetric = agent.metrics.getMetric(NAMES.ERRORS.OTHER) - t.notOk(transactionErrorMetric) + assert.equal(transactionErrorMetric, undefined) - t.notOk(allErrorMetric) - t.notOk(webErrorMetric) - t.notOk(otherErrorMetric) + assert.equal(allErrorMetric, undefined) + assert.equal(webErrorMetric, undefined) + assert.equal(otherErrorMetric, undefined) - t.end() + end() }) }) }) diff --git a/test/unit/errors/server-config.test.js b/test/unit/errors/server-config.test.js index 1d268ba07b..4b8fcbde29 100644 --- a/test/unit/errors/server-config.test.js +++ b/test/unit/errors/server-config.test.js @@ -1,143 +1,153 @@ /* - * Copyright 2020 New Relic Corporation. All rights reserved. + * Copyright 2024 New Relic Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const helper = require('../../lib/agent_helper') +const { match } = require('../../lib/custom-assertions') -tap.test('Merging Server Config Values', (t) => { - t.autoend() - let agent - - t.beforeEach(() => { - agent = helper.loadMockedAgent() +test('Merging Server Config Values', async (t) => { + t.beforeEach((ctx) => { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent() }) - t.afterEach(() => { - helper.unloadAgent(agent) - agent = null + t.afterEach((ctx) => { + helper.unloadAgent(ctx.nr.agent) }) - t.test('_fromServer should update ignore_status_codes', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update ignore_status_codes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.ignore_status_codes = [404] const params = { 'error_collector.ignore_status_codes': ['501-505'] } agent.config._fromServer(params, 'error_collector.ignore_status_codes') const expected = [404, 501, 502, 503, 504, 505] - t.same(agent.config.error_collector.ignore_status_codes, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_status_codes, expected), true) + end() }) }) - t.test('_fromServer should update expected_status_codes', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update expected_status_codes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.expected_status_codes = [404] const params = { 'error_collector.expected_status_codes': ['501-505'] } agent.config._fromServer(params, 'error_collector.expected_status_codes') const expected = [404, 501, 502, 503, 504, 505] - t.same(agent.config.error_collector.expected_status_codes, expected) - t.end() + assert.equal(match(agent.config.error_collector.expected_status_codes, expected), true) + end() }) }) - t.test('_fromServer should update expected_classes', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update expected_classes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.expected_classes = ['Foo'] const params = { 'error_collector.expected_classes': ['Bar'] } agent.config._fromServer(params, 'error_collector.expected_classes') const expected = ['Foo', 'Bar'] - t.same(agent.config.error_collector.expected_classes, expected) - t.end() + assert.equal(match(agent.config.error_collector.expected_classes, expected), true) + end() }) }) - t.test('_fromServer should update ignore_classes', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update ignore_classes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.ignore_classes = ['Foo'] const params = { 'error_collector.ignore_classes': ['Bar'] } agent.config._fromServer(params, 'error_collector.ignore_classes') const expected = ['Foo', 'Bar'] - t.same(agent.config.error_collector.ignore_classes, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_classes, expected), true) + end() }) }) - t.test('_fromServer should skip over malformed ignore_classes', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should skip over malformed ignore_classes', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.ignore_classes = ['Foo'] const params = { 'error_collector.ignore_classes': ['Bar'] } agent.config._fromServer(params, 'error_collector.ignore_classes') const nonsense = { 'error_collector.ignore_classes': [{ this: 'isNotAClass' }] } agent.config._fromServer(nonsense, 'error_collector.ignore_classes') const expected = ['Foo', 'Bar'] - t.same(agent.config.error_collector.ignore_classes, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_classes, expected), true) + end() }) }) - t.test('_fromServer should update expected_messages', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update expected_messages', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.expected_messages = { Foo: ['bar'] } const params = { 'error_collector.expected_messages': { Zip: ['zap'] } } agent.config._fromServer(params, 'error_collector.expected_messages') const expected = { Foo: ['bar'], Zip: ['zap'] } - t.same(agent.config.error_collector.expected_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.expected_messages, expected), true) + end() }) }) - t.test('_fromServer should update ignore_messages', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should update ignore_messages', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.ignore_messages = { Foo: ['bar'] } const params = { 'error_collector.ignore_messages': { Zip: ['zap'] } } agent.config._fromServer(params, 'error_collector.ignore_messages') const expected = { Foo: ['bar'], Zip: ['zap'] } - t.same(agent.config.error_collector.ignore_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) + end() }) }) - t.test('_fromServer should merge if keys match', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should merge if keys match', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { agent.config.error_collector.ignore_messages = { Foo: ['bar'] } const params = { 'error_collector.ignore_messages': { Foo: ['zap'] } } agent.config._fromServer(params, 'error_collector.ignore_messages') const expected = { Foo: ['bar', 'zap'] } - t.same(agent.config.error_collector.ignore_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) + end() }) }) - t.test('_fromServer misconfigure should not explode', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer misconfigure should not explode', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // whoops, a misconfiguration agent.config.error_collector.ignore_messages = { Foo: 'bar' } const params = { 'error_collector.ignore_messages': { Foo: ['zap'] } } agent.config._fromServer(params, 'error_collector.ignore_messages') const expected = { Foo: ['zap'] } // expect this to replace - t.same(agent.config.error_collector.ignore_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) + end() }) }) - t.test('_fromServer local misconfigure should not explode', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer local misconfigure should not explode', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // whoops, a misconfiguration agent.config.error_collector.ignore_messages = { Foo: 'bar' } const params = { 'error_collector.ignore_messages': { Foo: ['zap'] } } agent.config._fromServer(params, 'error_collector.ignore_messages') const expected = { Foo: ['zap'] } // expect this to replace - t.same(agent.config.error_collector.ignore_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) + end() }) }) - t.test('_fromServer ignore_message misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer ignore_message misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // whoops, a misconfiguration const badServerValues = [ null, @@ -153,14 +163,15 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.ignore_messages = expected const params = { 'error_collector.ignore_messages': value } agent.config._fromServer(params, 'error_collector.ignore_messages') - t.same(agent.config.error_collector.ignore_messages, expected) + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer expect_message misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer expect_message misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // whoops, a misconfiguration const badServerValues = [ null, @@ -176,13 +187,15 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.expect_messages = expected const params = { 'error_collector.expect_messages': value } agent.config._fromServer(params, 'error_collector.expect_messages') - t.same(agent.config.error_collector.expect_messages, expected) + assert.equal(match(agent.config.error_collector.expect_messages, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer ignore_classes misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + + await t.test('_fromServer ignore_classes misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // classes should be an array of strings const badServerValues = [ null, @@ -198,14 +211,15 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.ignore_classes = expected const params = { 'error_collector.ignore_classes': value } agent.config._fromServer(params, 'error_collector.ignore_classes') - t.same(agent.config.error_collector.ignore_classes, expected) + assert.equal(match(agent.config.error_collector.ignore_classes, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer expect_classes misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer expect_classes misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // classes should be an array of strings const badServerValues = [ null, @@ -221,14 +235,15 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.expect_classes = expected const params = { 'error_collector.expect_classes': value } agent.config._fromServer(params, 'error_collector.expect_classes') - t.same(agent.config.error_collector.expect_classes, expected) + assert.equal(match(agent.config.error_collector.expect_classes, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer ignore_status_codes misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer ignore_status_codes misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // classes should be an array of strings and numbers const badServerValues = [ null, @@ -245,14 +260,15 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.ignore_status_codes = toSet const params = { 'error_collector.ignore_status_codes': value } agent.config._fromServer(params, 'error_collector.ignore_status_codes') - t.same(agent.config.error_collector.ignore_status_codes, expected) + assert.equal(match(agent.config.error_collector.ignore_status_codes, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer expect_status_codes misconfiguration should be ignored', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer expect_status_codes misconfiguration should be ignored', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // classes should be an array of strings and numbers const badServerValues = [ null, @@ -269,21 +285,22 @@ tap.test('Merging Server Config Values', (t) => { agent.config.error_collector.expected_status_codes = toSet const params = { 'error_collector.expected_status_codes': value } agent.config._fromServer(params, 'error_collector.expected_status_codes') - t.same(agent.config.error_collector.expected_status_codes, expected) + assert.equal(match(agent.config.error_collector.expected_status_codes, expected), true) }) - t.end() + end() }) }) - t.test('_fromServer should de-duplicate arrays nested in object', (t) => { - helper.runInTransaction(agent, function () { + await t.test('_fromServer should de-duplicate arrays nested in object', (t, end) => { + const { agent } = t.nr + helper.runInTransaction(agent, () => { // whoops, a misconfiguration agent.config.error_collector.ignore_messages = { Foo: ['zap', 'bar'] } const params = { 'error_collector.ignore_messages': { Foo: ['bar'] } } agent.config._fromServer(params, 'error_collector.ignore_messages') const expected = { Foo: ['zap', 'bar'] } // expect this to replace - t.same(agent.config.error_collector.ignore_messages, expected) - t.end() + assert.equal(match(agent.config.error_collector.ignore_messages, expected), true) + end() }) }) })