Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Converted collector unit tests to node:test #2510

Merged
merged 12 commits into from
Sep 4, 2024
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
Loading