Skip to content

Commit

Permalink
chore: Converted collector unit tests to node:test (newrelic#2510)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsumners-nr authored Sep 4, 2024
1 parent 47b8398 commit 762511b
Show file tree
Hide file tree
Showing 12 changed files with 2,119 additions and 2,872 deletions.
26 changes: 23 additions & 3 deletions lib/collector/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,29 @@ const BACKOFFS = [

// Expected collector response codes
const SUCCESS = new Set([200, 202])
const RESTART = new Set([401, 409])
const FAILURE_SAVE_DATA = new Set([408, 429, 500, 503])
const FAILURE_DISCARD_DATA = new Set([400, 403, 404, 405, 407, 411, 413, 414, 415, 417, 431])
const RESTART = new Set([
401, // Authentication failed.
409 // NR says to reconnect for some reason.
])
const FAILURE_SAVE_DATA = new Set([
408, // Data took too long to reach NR.
429, // Too many requests being received by NR, rate limited.
500, // NR server went boom.
503 // NR server is not available.
])
const FAILURE_DISCARD_DATA = new Set([
400, // Format of the request is incorrect.
403, // Not entitled to perform the action.
404, // Sending to wrong destination.
405, // Using the wrong HTTP method (e.g. PUT instead of POST).
407, // Proxy authentication misconfigured.
411, // No Content-Length header provided, or value is incorrect.
413, // Payload is too large.
414, // URI exceeds allowed length.
415, // Content-type or Content-encoding values are incorrect.
417, // NR cannot meet the expectation of the request.
431 // Request headers exceed size limit.
])

const AGENT_RUN_BEHAVIOR = CollectorResponse.AGENT_RUN_BEHAVIOR

Expand Down
57 changes: 57 additions & 0 deletions test/lib/assert-metrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/

'use strict'

module.exports = {
assertMetricValues
}

const assert = require('node:assert')

/**
* @param {Transaction} transaction Nodejs agent transaction
* @param {Array} expected Array of metric data where metric data is in this form:
* [
* {
* “name”:”name of metric”,
* “scope”:”scope of metric”,
* },
* [count,
* total time,
* exclusive time,
* min time,
* max time,
* sum of squares]
* ]
* @param {boolean} exact When true, found and expected metric lengths should match
*/
function assertMetricValues(transaction, expected, exact) {
const metrics = transaction.metrics

for (let i = 0; i < expected.length; ++i) {
let expectedMetric = Object.assign({}, expected[i])
let name = null
let scope = null

if (typeof expectedMetric === 'string') {
name = expectedMetric
expectedMetric = {}
} else {
name = expectedMetric[0].name
scope = expectedMetric[0].scope
}

const metric = metrics.getMetric(name, scope)
assert.ok(metric, 'should have expected metric name')

assert.deepStrictEqual(metric.toJSON(), expectedMetric[1], 'metric values should match')
}

if (exact) {
const metricsJSON = metrics.toJSON()
assert.equal(metricsJSON.length, expected.length, 'metrics length should match')
}
}
53 changes: 46 additions & 7 deletions test/lib/test-collector.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ class Collector {
#handlers = new Map()
#server
#address
#runId

constructor() {
constructor({ runId = 42 } = {}) {
this.#runId = runId
this.#server = https.createServer({
key: fakeCert.privateKey,
cert: fakeCert.certificate
Expand All @@ -37,6 +39,27 @@ class Collector {
this.end(JSON.stringify(payload))
}

req.body = function () {
let resolve
let reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})

let data = ''
this.on('data', (d) => {
data += d
})
this.on('end', () => {
resolve(data)
})
this.on('error', (error) => {
reject(error)
})
return promise
}

handler.isDone = true
handler(req, res)
})
Expand Down Expand Up @@ -104,6 +127,19 @@ class Collector {
}
}

/**
* the most basic `connect` handler. Useful when you do not need to
* customize the handler.
*
* @returns {function}
*/
get connectHandler() {
const runId = this.#runId
return function (req, res) {
res.json({ payload: { return_value: { agent_run_id: runId } } })
}
}

/**
* The most basic `preconnect` handler. Useful when you do not need to
* customize the handler.
Expand Down Expand Up @@ -135,7 +171,9 @@ class Collector {
* requests.
* @param {function} handler A typical `(req, res) => {}` handler. For
* convenience, `res` is extended with a `json({ payload, code = 200 })`
* method for easily sending JSON responses.
* method for easily sending JSON responses. Also, `req` is extended with
* a `body()` method that returns a promise which resolves to the string
* data supplied via POST-like requests.
*/
addHandler(endpoint, handler) {
const qs = querystring.decode(endpoint.slice(endpoint.indexOf('?') + 1))
Expand Down Expand Up @@ -181,11 +219,12 @@ class Collector {
// Add handlers for the required agent startup connections. These should
// be overwritten by tests that exercise the startup phase, but adding these
// stubs makes it easier to test other connection events.
this.addHandler(helper.generateCollectorPath('preconnect', 42), this.preconnectHandler)
this.addHandler(helper.generateCollectorPath('connect', 42), (req, res) => {
res.json({ payload: { return_value: { agent_run_id: 42 } } })
})
this.addHandler(helper.generateCollectorPath('agent_settings', 42), this.agentSettingsHandler)
this.addHandler(helper.generateCollectorPath('preconnect', this.#runId), this.preconnectHandler)
this.addHandler(helper.generateCollectorPath('connect', this.#runId), this.connectHandler)
this.addHandler(
helper.generateCollectorPath('agent_settings', this.#runId),
this.agentSettingsHandler
)

return address
}
Expand Down
Loading

0 comments on commit 762511b

Please sign in to comment.