From c207e1e3de75a9c3a2c4a05fa1bc318d3e455ef9 Mon Sep 17 00:00:00 2001 From: Amy Chisholm Date: Fri, 30 Aug 2024 13:48:32 -0700 Subject: [PATCH] test: Convert grpc, lib, and utilization tests to `node:test` (#2532) --- test/unit/grpc/connection.test.js | 192 +++++++-------- test/unit/lib/logger.test.js | 51 ++-- test/unit/utilization/common.test.js | 112 ++++----- test/unit/utilization/docker-info.test.js | 284 +++++++++++----------- test/unit/utilization/main.test.js | 49 ++-- 5 files changed, 322 insertions(+), 366 deletions(-) diff --git a/test/unit/grpc/connection.test.js b/test/unit/grpc/connection.test.js index 5713803a6e..a71b5e34ff 100644 --- a/test/unit/grpc/connection.test.js +++ b/test/unit/grpc/connection.test.js @@ -4,7 +4,8 @@ */ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const sinon = require('sinon') const GrpcConnection = require('../../../lib/grpc/connection') const connectionStates = require('../../../lib/grpc/connection/states') @@ -52,20 +53,20 @@ const createMetricAggregatorForTests = () => { ) } -tap.test('GrpcConnection logic tests', (test) => { +test('GrpcConnection logic tests', async (t) => { const metrics = createMetricAggregatorForTests() - test.test('test metadata generation', (t) => { + await t.test('test metadata generation', () => { const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) // only sets the license and run id const metadataFirst = connection._getMetadata('fake-license', 'fake-run-id', {}, {}) - t.equal(metadataFirst.get('license_key').shift(), 'fake-license', 'license key set') - t.equal(metadataFirst.get('agent_run_token').shift(), 'fake-run-id', 'run id set') - t.equal(metadataFirst.get('flaky').length, 0, 'flaky not set') - t.equal(metadataFirst.get('delay').length, 0, 'delay not set') - t.equal(metadataFirst.get('flaky_code').length, 0, 'flaky_code not set') - t.equal(metadataFirst.get('success_delay_ms').length, 0, 'success_delay_ms not set') + assert.equal(metadataFirst.get('license_key').shift(), 'fake-license', 'license key set') + assert.equal(metadataFirst.get('agent_run_token').shift(), 'fake-run-id', 'run id set') + assert.equal(metadataFirst.get('flaky').length, 0, 'flaky not set') + assert.equal(metadataFirst.get('delay').length, 0, 'delay not set') + assert.equal(metadataFirst.get('flaky_code').length, 0, 'flaky_code not set') + assert.equal(metadataFirst.get('success_delay_ms').length, 0, 'success_delay_ms not set') // tests that env based params get set const metadataSecond = connection._getMetadata( @@ -80,12 +81,12 @@ tap.test('GrpcConnection logic tests', (test) => { } ) - t.equal(metadataSecond.get('license_key').shift(), 'fake-license', 'license key set') - t.equal(metadataSecond.get('agent_run_token').shift(), 'fake-run-id', 'run id set') - t.equal(metadataSecond.get('flaky').shift(), 10, 'flaky set') - t.equal(metadataSecond.get('delay').shift(), 20, 'delay set') - t.equal(metadataSecond.get('flaky_code').shift(), 7, 'flaky_code set') - t.equal(metadataSecond.get('success_delay_ms').shift(), 400, 'success_delay_ms set') + assert.equal(metadataSecond.get('license_key').shift(), 'fake-license', 'license key set') + assert.equal(metadataSecond.get('agent_run_token').shift(), 'fake-run-id', 'run id set') + assert.equal(metadataSecond.get('flaky').shift(), 10, 'flaky set') + assert.equal(metadataSecond.get('delay').shift(), 20, 'delay set') + assert.equal(metadataSecond.get('flaky_code').shift(), 7, 'flaky_code set') + assert.equal(metadataSecond.get('success_delay_ms').shift(), 400, 'success_delay_ms set') // tests that env based params get set const metadataThird = connection._getMetadata( @@ -100,24 +101,22 @@ tap.test('GrpcConnection logic tests', (test) => { } ) - t.equal(metadataThird.get('license_key').shift(), 'fake-license', 'license key set') - t.equal(metadataThird.get('agent_run_token').shift(), 'fake-run-id', 'run id set') - t.equal(metadataThird.get('flaky').length, 0, 'flaky not set') - t.equal(metadataThird.get('delay').length, 0, 'delay not set') - t.equal(metadataFirst.get('flaky_code').length, 0, 'flaky_code not set') - t.equal(metadataFirst.get('success_delay_ms').length, 0, 'success_delay_ms not set') - t.end() + assert.equal(metadataThird.get('license_key').shift(), 'fake-license', 'license key set') + assert.equal(metadataThird.get('agent_run_token').shift(), 'fake-run-id', 'run id set') + assert.equal(metadataThird.get('flaky').length, 0, 'flaky not set') + assert.equal(metadataThird.get('delay').length, 0, 'delay not set') + assert.equal(metadataFirst.get('flaky_code').length, 0, 'flaky_code not set') + assert.equal(metadataFirst.get('success_delay_ms').length, 0, 'success_delay_ms not set') }) - test.test('ensure fake enum is consistent', (t) => { + await t.test('ensure fake enum is consistent', () => { for (const [key, value] of Object.entries(connectionStates)) { /* eslint-disable-next-line eqeqeq */ - t.ok(key == connectionStates[value], 'found paired value for ' + key) + assert.ok(key == connectionStates[value], 'found paired value for ' + key) } - t.end() }) - test.test('should apply request headers map with lowercase keys', (t) => { + await t.test('should apply request headers map with lowercase keys', () => { const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) const requestHeadersMap = { @@ -128,58 +127,44 @@ tap.test('GrpcConnection logic tests', (test) => { // only sets the license and run id const metadata = connection._getMetadata('fake-license', 'fake-run-id', requestHeadersMap, {}) - t.same(metadata.get('key_1'), ['VALUE 1']) - t.same(metadata.get('key_2'), ['VALUE 2']) - - t.end() + assert.deepStrictEqual(metadata.get('key_1'), ['VALUE 1']) + assert.deepStrictEqual(metadata.get('key_2'), ['VALUE 2']) }) - - test.end() }) -tap.test('grpc connection error handling', (test) => { - test.test('should catch error when proto loader fails', (t) => { +test('grpc connection error handling', async (t) => { + await t.test('should catch error when proto loader fails', (t, end) => { const stub = sinon.stub(protoLoader, 'loadSync').returns({}) - - t.teardown(() => { - stub.restore() - }) - const connection = new GrpcConnection(fakeTraceObserverConfig) connection.on('disconnected', () => { - t.equal(connection._state, connectionStates.disconnected) - t.end() + assert.equal(connection._state, connectionStates.disconnected) + end() }) connection.connectSpans() + stub.restore() }) - test.test( + await t.test( 'should catch error when loadPackageDefinition returns invalid service definition', - (t) => { + (t, end) => { const stub = sinon.stub(grpcApi, 'loadPackageDefinition').returns({}) - t.teardown(() => { - stub.restore() - }) - const connection = new GrpcConnection(fakeTraceObserverConfig) connection.on('disconnected', () => { - t.equal(connection._state, connectionStates.disconnected) - - t.end() + assert.equal(connection._state, connectionStates.disconnected) + end() }) connection.connectSpans() + stub.restore() } ) - - test.end() }) -tap.test('grpc stream event handling', (test) => { - test.test('should immediately reconnect with OK status', (t) => { +test('grpc stream event handling', async (t) => { + await t.test('should immediately reconnect with OK status', (t, end) => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() @@ -188,8 +173,8 @@ tap.test('grpc stream event handling', (test) => { const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) connection._reconnect = (delay) => { - t.notOk(delay, 'should not have delay') - t.end() + assert.ok(!delay, 'should not have delay') + end() } const status = { @@ -203,14 +188,14 @@ tap.test('grpc stream event handling', (test) => { fakeStream.removeAllListeners() }) - test.test('should disconnect, no reconnect, with UNIMPLEMENTED status', (t) => { + await t.test('should disconnect, no reconnect, with UNIMPLEMENTED status', () => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) connection._reconnect = () => { - t.fail('should not call reconnect') + assert.fail('should not call reconnect') } let disconnectCalled = false @@ -228,12 +213,10 @@ tap.test('grpc stream event handling', (test) => { fakeStream.removeAllListeners() - t.ok(disconnectCalled) - - t.end() + assert.ok(disconnectCalled) }) - test.test('should delay reconnect when status not UNPLIMENTED or OK', (t) => { + await t.test('should delay reconnect when status not UNPLIMENTED or OK', (t, end) => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() @@ -241,8 +224,8 @@ tap.test('grpc stream event handling', (test) => { const connection = new GrpcConnection(fakeTraceObserverConfig, metrics, expectedDelayMs) connection._reconnect = (delay) => { - t.equal(delay, expectedDelayMs) - t.end() + assert.equal(delay, expectedDelayMs) + end() } const statusName = 'DEADLINE_EXCEEDED' @@ -258,32 +241,35 @@ tap.test('grpc stream event handling', (test) => { fakeStream.removeAllListeners() }) - test.test('should default delay 15 second reconnect when status not UNPLIMENTED or OK', (t) => { - const metrics = createMetricAggregatorForTests() - const fakeStream = new FakeStreamer() + await t.test( + 'should default delay 15 second reconnect when status not UNPLIMENTED or OK', + (t, end) => { + const metrics = createMetricAggregatorForTests() + const fakeStream = new FakeStreamer() - const expectedDelayMs = 15 * 1000 - const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) + const expectedDelayMs = 15 * 1000 + const connection = new GrpcConnection(fakeTraceObserverConfig, metrics) - connection._reconnect = (delay) => { - t.equal(delay, expectedDelayMs) - t.end() - } + connection._reconnect = (delay) => { + assert.equal(delay, expectedDelayMs) + end() + } - const statusName = 'DEADLINE_EXCEEDED' + const statusName = 'DEADLINE_EXCEEDED' - const status = { - code: grpcApi.status[statusName] - } + const status = { + code: grpcApi.status[statusName] + } - connection._setupSpanStreamObservers(fakeStream) + connection._setupSpanStreamObservers(fakeStream) - fakeStream.emitStatus(status) + fakeStream.emitStatus(status) - fakeStream.removeAllListeners() - }) + fakeStream.removeAllListeners() + } + ) - test.test('should not generate metric with OK status', (t) => { + await t.test('should not generate metric with OK status', () => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() @@ -307,12 +293,10 @@ tap.test('grpc stream event handling', (test) => { fakeStream.removeAllListeners() - t.notOk(calledMetrics, 'grpc status OK - no metric incremented') - - t.end() + assert.ok(!calledMetrics, 'grpc status OK - no metric incremented') }) - test.test('should increment UNIMPLEMENTED metric on UNIMPLEMENTED status', (t) => { + await t.test('should increment UNIMPLEMENTED metric on UNIMPLEMENTED status', () => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() @@ -334,14 +318,12 @@ tap.test('grpc stream event handling', (test) => { NAMES.INFINITE_TRACING.SPAN_RESPONSE_GRPC_UNIMPLEMENTED ) - t.equal(metric.callCount, 1, 'incremented metric') - - t.end() + assert.equal(metric.callCount, 1, 'incremented metric') }) - test.test( + await t.test( 'should increment SPAN_RESPONSE_GRPC_STATUS metric when status not UNPLIMENTED or OK', - (t) => { + () => { const metrics = createMetricAggregatorForTests() const fakeStream = new FakeStreamer() @@ -365,49 +347,41 @@ tap.test('grpc stream event handling', (test) => { util.format(NAMES.INFINITE_TRACING.SPAN_RESPONSE_GRPC_STATUS, statusName) ) - t.equal(metric.callCount, 1, 'incremented metric') - - t.end() + assert.equal(metric.callCount, 1, 'incremented metric') } ) - - test.end() }) -tap.test('_createClient', (t) => { - t.autoend() - - t.test( +test('_createClient', async (t) => { + await t.test( 'should create client with compression when config.infinite_tracing.compression is true', - (t) => { + () => { const metrics = createMetricAggregatorForTests() const config = { ...fakeTraceObserverConfig, compression: true } const connection = new GrpcConnection(config, metrics) connection._createClient() const metric = metrics.getOrCreateMetric(`${NAMES.INFINITE_TRACING.COMPRESSION}/enabled`) - t.equal(metric.callCount, 1, 'incremented compression enabled') + assert.equal(metric.callCount, 1, 'incremented compression enabled') const disabledMetric = metrics.getOrCreateMetric( `${NAMES.INFINITE_TRACING.COMPRESSION}/disabled` ) - t.not(disabledMetric.callCount) - t.end() + assert.notEqual(disabledMetric.callCount, null) } ) - t.test( + await t.test( 'should create client without compression when config.infinite_tracing.compression is false', - (t) => { + () => { const metrics = createMetricAggregatorForTests() const config = { ...fakeTraceObserverConfig, compression: false } const connection = new GrpcConnection(config, metrics) connection._createClient() const metric = metrics.getOrCreateMetric(`${NAMES.INFINITE_TRACING.COMPRESSION}/disabled`) - t.equal(metric.callCount, 1, 'incremented compression disabled') + assert.equal(metric.callCount, 1, 'incremented compression disabled') const enabledMetric = metrics.getOrCreateMetric( `${NAMES.INFINITE_TRACING.COMPRESSION}/disabled` ) - t.not(enabledMetric.callCount) - t.end() + assert.notEqual(enabledMetric.callCount, null) } ) }) diff --git a/test/unit/lib/logger.test.js b/test/unit/lib/logger.test.js index 5922f60f03..86d6605ece 100644 --- a/test/unit/lib/logger.test.js +++ b/test/unit/lib/logger.test.js @@ -5,14 +5,13 @@ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const sinon = require('sinon') const proxyquire = require('proxyquire').noPreserveCache() const EventEmitter = require('events').EventEmitter -tap.test('Bootstrapped Logger', (t) => { - t.autoend() - +test('Bootstrapped Logger', async (t) => { let fakeLoggerConfigure let fakeStreamPipe let fakeLogger @@ -46,7 +45,7 @@ tap.test('Bootstrapped Logger', (t) => { global.console.error = originalConsoleError }) - t.test('should instantiate a new logger (logging enabled + filepath)', (t) => { + await t.test('should instantiate a new logger (logging enabled + filepath)', () => { proxyquire('../../../lib/logger', { './util/logger': fakeLogger, './util/unwrapped-core': { fs: fakeFS }, @@ -61,7 +60,7 @@ tap.test('Bootstrapped Logger', (t) => { } }) - t.ok( + assert.ok( fakeLogger.calledOnceWithExactly({ name: 'newrelic_bootstrap', level: 'info', @@ -70,7 +69,7 @@ tap.test('Bootstrapped Logger', (t) => { 'should bootstrap sub-logger' ) - t.ok( + assert.ok( fakeLoggerConfigure.calledOnceWithExactly({ name: 'newrelic', level: 'debug', @@ -79,12 +78,12 @@ tap.test('Bootstrapped Logger', (t) => { 'should call logger.configure with config options' ) - t.ok( + assert.ok( fakeFS.createWriteStream.calledOnceWithExactly('/foo/bar/baz', { flags: 'a+', mode: 0o600 }), 'should create a new write stream to specific file' ) - t.ok( + assert.ok( fakeStreamPipe.calledOnceWithExactly(testEmitter), 'should use a new write stream for output' ) @@ -92,20 +91,18 @@ tap.test('Bootstrapped Logger', (t) => { const expectedError = new Error('stuff blew up') testEmitter.emit('error', expectedError) - t.ok( + assert.ok( testEmitterSpy.calledOnceWith('error'), 'should handle errors emitted from the write stream' ) - t.ok( + assert.ok( global.console.error.calledWith('New Relic failed to open log file /foo/bar/baz'), 'should log filepath when error occurs' ) - t.ok(global.console.error.calledWith(expectedError), 'should log error when it occurs') - - t.end() + assert.ok(global.console.error.calledWith(expectedError), 'should log error when it occurs') }) - t.test('should instantiate a new logger (logging enabled + stderr)', (t) => { + await t.test('should instantiate a new logger (logging enabled + stderr)', () => { proxyquire('../../../lib/logger', { './util/logger': fakeLogger, './util/unwrapped-core': { fs: fakeFS }, @@ -120,15 +117,13 @@ tap.test('Bootstrapped Logger', (t) => { } }) - t.ok( + assert.ok( fakeStreamPipe.calledOnceWithExactly(process.stderr), 'should use process.stderr for output' ) - - t.end() }) - t.test('should instantiate a new logger (logging enabled + stdout)', (t) => { + await t.test('should instantiate a new logger (logging enabled + stdout)', () => { proxyquire('../../../lib/logger', { './util/logger': fakeLogger, './util/unwrapped-core': { fs: fakeFS }, @@ -143,15 +138,13 @@ tap.test('Bootstrapped Logger', (t) => { } }) - t.ok( + assert.ok( fakeStreamPipe.calledOnceWithExactly(process.stdout), 'should use process.stdout for output' ) - - t.end() }) - t.test('should instantiate a new logger (logging disabled)', (t) => { + await t.test('should instantiate a new logger (logging disabled)', () => { proxyquire('../../../lib/logger', { './util/logger': fakeLogger, './util/unwrapped-core': { fs: fakeFS }, @@ -166,7 +159,7 @@ tap.test('Bootstrapped Logger', (t) => { } }) - t.ok( + assert.ok( fakeLoggerConfigure.calledOnceWithExactly({ name: 'newrelic', level: 'debug', @@ -175,12 +168,10 @@ tap.test('Bootstrapped Logger', (t) => { 'should call logger.configure with config options' ) - t.notOk(fakeStreamPipe.called, 'should not call pipe when logging is disabled') - - t.end() + assert.ok(!fakeStreamPipe.called, 'should not call pipe when logging is disabled') }) - t.test('should instantiate a new logger (no config)', (t) => { + await t.test('should instantiate a new logger (no config)', () => { proxyquire('../../../lib/logger', { './util/logger': fakeLogger, './util/unwrapped-core': { fs: fakeFS }, @@ -189,8 +180,6 @@ tap.test('Bootstrapped Logger', (t) => { } }) - t.notOk(fakeLoggerConfigure.called, 'should not call logger.configure') - - t.end() + assert.ok(!fakeLoggerConfigure.called, 'should not call logger.configure') }) }) diff --git a/test/unit/utilization/common.test.js b/test/unit/utilization/common.test.js index f212c8e704..937b1163a3 100644 --- a/test/unit/utilization/common.test.js +++ b/test/unit/utilization/common.test.js @@ -5,7 +5,8 @@ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const common = require('../../../lib/utilization/common') const helper = require('../../lib/agent_helper.js') const nock = require('nock') @@ -15,92 +16,80 @@ while (BIG.length < 300) { BIG += BIG } -tap.test('Utilization Common Components', function (t) { - t.autoend() - t.test('common.checkValueString', function (t) { - t.autoend() - t.test('should fail for strings of invalid size', function (t) { - t.notOk(common.checkValueString(null)) - t.notOk(common.checkValueString({})) - t.notOk(common.checkValueString('')) - - t.notOk(common.checkValueString(BIG)) - t.end() +test('Utilization Common Components', async function (t) { + await t.test('common.checkValueString', async function (t) { + await t.test('should fail for strings of invalid size', function () { + assert.ok(!common.checkValueString(null)) + assert.ok(!common.checkValueString({})) + assert.ok(!common.checkValueString('')) + + assert.ok(!common.checkValueString(BIG)) }) - t.test('should fail for strings with invalid characters', function (t) { - t.notOk(common.checkValueString('&')) - t.notOk(common.checkValueString('foo\0')) - t.end() + await t.test('should fail for strings with invalid characters', function () { + assert.ok(!common.checkValueString('&')) + assert.ok(!common.checkValueString('foo\0')) }) - t.test('should allow good values', function (t) { - t.ok(common.checkValueString('foobar')) - t.ok(common.checkValueString('f1B_./- \xff')) - t.end() + await t.test('should allow good values', function () { + assert.ok(common.checkValueString('foobar')) + assert.ok(common.checkValueString('f1B_./- \xff')) }) }) - t.test('common.getKeys', function (t) { - t.autoend() - t.test('should return null if any key is missing', function (t) { - t.equal(common.getKeys({}, ['foo']), null) - t.equal(common.getKeys({ foo: 'bar' }, ['foo', 'bar']), null) - t.equal(common.getKeys(null, ['foo']), null) - t.end() + await t.test('common.getKeys', async function (t) { + await t.test('should return null if any key is missing', function () { + assert.equal(common.getKeys({}, ['foo']), null) + assert.equal(common.getKeys({ foo: 'bar' }, ['foo', 'bar']), null) + assert.equal(common.getKeys(null, ['foo']), null) }) - t.test('should return null if any key is invalid', function (t) { - t.equal(common.getKeys({ foo: 'foo\0' }, ['foo']), null) - t.equal(common.getKeys({ foo: 'foo', bar: 'bar\0' }, ['foo', 'bar']), null) - t.end() + await t.test('should return null if any key is invalid', function () { + assert.equal(common.getKeys({ foo: 'foo\0' }, ['foo']), null) + assert.equal(common.getKeys({ foo: 'foo', bar: 'bar\0' }, ['foo', 'bar']), null) }) - t.test('should return null if any value is too large', function (t) { - t.equal(common.getKeys({ foo: BIG }, ['foo']), null) - t.end() + await t.test('should return null if any value is too large', function () { + assert.equal(common.getKeys({ foo: BIG }, ['foo']), null) }) - t.test('should pull only the desired values', function (t) { - t.same(common.getKeys({ foo: 'foo', bar: 'bar', baz: 'baz' }, ['foo', 'baz']), { + await t.test('should pull only the desired values', function () { + assert.deepEqual(common.getKeys({ foo: 'foo', bar: 'bar', baz: 'baz' }, ['foo', 'baz']), { foo: 'foo', baz: 'baz' }) - t.end() }) - t.test('should not fail with "clean" objects', function (t) { + await t.test('should not fail with "clean" objects', function () { const obj = Object.create(null) obj.foo = 'foo' - t.same(common.getKeys(obj, ['foo']), { foo: 'foo' }) - t.end() + assert.deepEqual(common.getKeys(obj, ['foo']), { foo: 'foo' }) }) }) - t.test('common.request', (t) => { - t.autoend() - let agent = null - + await t.test('common.request', async (t) => { t.before(() => { nock.disableNetConnect() nock('http://fakedomain').persist().get('/timeout').delay(150).reply(200, 'wohoo') }) - t.beforeEach(function () { - agent = helper.loadMockedAgent() + t.beforeEach(function (ctx) { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent() }) - t.afterEach(function () { - helper.unloadAgent(agent) - agent = null + t.afterEach(function (ctx) { + helper.unloadAgent(ctx.nr.agent) + ctx.nr.agent = null }) - t.teardown(() => { + t.after(() => { nock.cleanAll() nock.enableNetConnect() }) - t.test('should not timeout when request succeeds', (t) => { + await t.test('should not timeout when request succeeds', (ctx, end) => { + const agent = ctx.nr.agent let invocationCount = 0 common.request( { @@ -111,24 +100,25 @@ tap.test('Utilization Common Components', function (t) { }, agent, (err, data) => { - t.error(err) - t.equal(data, 'wohoo') + assert.ifError(err) + assert.equal(data, 'wohoo') invocationCount++ } ) // need to give enough time for second to have chance to run. - // sinon and http dont quite seem to work well enough to do this + // sinon and http don't quite seem to work well enough to do this // totally faked synchronously. setTimeout(verifyInvocations, 250) function verifyInvocations() { - t.equal(invocationCount, 1) - t.end() + assert.equal(invocationCount, 1) + end() } }) - t.test('should not invoke callback multiple times on timeout', (t) => { + await t.test('should not invoke callback multiple times on timeout', (ctx, end) => { + const agent = ctx.nr.agent let invocationCount = 0 common.request( { @@ -139,8 +129,8 @@ tap.test('Utilization Common Components', function (t) { }, agent, (err) => { - t.ok(err) - t.equal(err.code, 'ECONNRESET', 'error should be socket timeout') + assert.ok(err) + assert.equal(err.code, 'ECONNRESET', 'error should be socket timeout') invocationCount++ } ) @@ -151,8 +141,8 @@ tap.test('Utilization Common Components', function (t) { setTimeout(verifyInvocations, 200) function verifyInvocations() { - t.equal(invocationCount, 1) - t.end() + assert.equal(invocationCount, 1) + end() } }) }) diff --git a/test/unit/utilization/docker-info.test.js b/test/unit/utilization/docker-info.test.js index a3554b36a6..cad8ad0bc0 100644 --- a/test/unit/utilization/docker-info.test.js +++ b/test/unit/utilization/docker-info.test.js @@ -5,7 +5,8 @@ 'use strict' -const tap = require('tap') +const test = require('node:test') +const assert = require('node:assert') const fs = require('node:fs') const http = require('node:http') const os = require('node:os') @@ -13,48 +14,6 @@ const helper = require('../../lib/agent_helper') const standardResponse = require('./aws-ecs-api-response.json') const { getBootId } = require('../../../lib/utilization/docker-info') -tap.beforeEach(async (t) => { - t.context.orig = { - fs_access: fs.access, - os_platform: os.platform - } - fs.access = (file, mode, cb) => { - cb(Error('no proc file')) - } - os.platform = () => 'linux' - - t.context.agent = helper.loadMockedAgent() - t.context.agent.config.utilization = { - detect_aws: true, - detect_azure: true, - detect_gcp: true, - detect_docker: true, - detect_kubernetes: true, - detect_pcf: true - } - - t.context.logs = [] - t.context.logger = { - debug(msg) { - t.context.logs.push(msg) - } - } - - t.context.server = await getServer() -}) - -tap.afterEach((t) => { - fs.access = t.context.orig.fs_access - os.platform = t.context.orig.os_platform - - t.context.server.close() - - helper.unloadAgent(t.context.agent) - - delete process.env.ECS_CONTAINER_METADATA_URI - delete process.env.ECS_CONTAINER_METADATA_URI_V4 -}) - async function getServer() { const server = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'application/json' }) @@ -85,106 +44,149 @@ async function getServer() { return server } -tap.test('skips if not in ecs container', (t) => { - const { agent, logs, logger } = t.context - - function callback(err, data) { - t.error(err) - t.strictSame(logs, [ - 'Container boot id is not available in cgroups info', - 'Container is not in a recognized ECS container, omitting boot info' - ]) - t.equal(data, null) - t.equal( - agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, - 1 - ) - t.end() - } - - getBootId(agent, callback, logger) -}) +test('all tests', async (t) => { + t.beforeEach(async (ctx) => { + ctx.nr = {} + ctx.nr.orig = { + fs_access: fs.access, + os_platform: os.platform + } + fs.access = (file, mode, cb) => { + cb(Error('no proc file')) + } + os.platform = () => 'linux' + + ctx.nr.agent = helper.loadMockedAgent() + ctx.nr.agent.config.utilization = { + detect_aws: true, + detect_azure: true, + detect_gcp: true, + detect_docker: true, + detect_kubernetes: true, + detect_pcf: true + } -tap.test('records request error', (t) => { - const { agent, logs, logger, server } = t.context - const info = server.address() - process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:0` - - function callback(err, data) { - t.error(err) - t.strictSame(logs, [ - 'Container boot id is not available in cgroups info', - `Failed to query ECS endpoint, omitting boot info` - ]) - t.equal(data, null) - t.equal( - agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, - 1 - ) - t.end() - } - - getBootId(agent, callback, logger) -}) + ctx.nr.logs = [] + ctx.nr.logger = { + debug(msg) { + ctx.nr.logs.push(msg) + } + } -tap.test('records json parsing error', (t) => { - const { agent, logs, logger, server } = t.context - const info = server.address() - process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:${info.port}/json-error` - - function callback(err, data) { - t.error(err) - t.match(logs, [ - 'Container boot id is not available in cgroups info', - // Node 16 has a different format for JSON parsing errors: - /Failed to process ECS API response, omitting boot info: (Expected|Unexpected)/ - ]) - t.equal(data, null) - t.equal( - agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, - 1 - ) - t.end() - } - - getBootId(agent, callback, logger) -}) + ctx.nr.server = await getServer() + }) -tap.test('records error for no id in response', (t) => { - const { agent, logs, logger, server } = t.context - const info = server.address() - process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:${info.port}/no-id` - - function callback(err, data) { - t.error(err) - t.strictSame(logs, [ - 'Container boot id is not available in cgroups info', - 'Failed to find DockerId in response, omitting boot info' - ]) - t.equal(data, null) - t.equal( - agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, - 1 - ) - t.end() - } - - getBootId(agent, callback, logger) -}) + t.afterEach((ctx) => { + fs.access = ctx.nr.orig.fs_access + os.platform = ctx.nr.orig.os_platform + + ctx.nr.server.close() + + helper.unloadAgent(ctx.nr.agent) -tap.test('records found id', (t) => { - const { agent, logs, logger, server } = t.context - const info = server.address() - // Cover the non-V4 case: - process.env.ECS_CONTAINER_METADATA_URI = `http://${info.address}:${info.port}/success` - - function callback(err, data) { - t.error(err) - t.strictSame(logs, ['Container boot id is not available in cgroups info']) - t.equal(data, '1e1698469422439ea356071e581e8545-2769485393') - t.notOk(agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount) - t.end() - } - - getBootId(agent, callback, logger) + delete process.env.ECS_CONTAINER_METADATA_URI + delete process.env.ECS_CONTAINER_METADATA_URI_V4 + }) + + await t.test('skips if not in ecs container', (ctx, end) => { + const { agent, logs, logger } = ctx.nr + + function callback(err, data) { + assert.ifError(err) + assert.deepEqual(logs, [ + 'Container boot id is not available in cgroups info', + 'Container is not in a recognized ECS container, omitting boot info' + ]) + assert.equal(data, null) + assert.equal( + agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, + 1 + ) + end() + } + + getBootId(agent, callback, logger) + }) + + await t.test('records request error', (ctx, end) => { + const { agent, logs, logger, server } = ctx.nr + const info = server.address() + process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:0` + + function callback(err, data) { + assert.ifError(err) + assert.deepEqual(logs, [ + 'Container boot id is not available in cgroups info', + `Failed to query ECS endpoint, omitting boot info` + ]) + assert.equal(data, null) + assert.equal( + agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, + 1 + ) + end() + } + + getBootId(agent, callback, logger) + }) + + await t.test('records json parsing error', (ctx, end) => { + const { agent, logs, logger, server } = ctx.nr + const info = server.address() + process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:${info.port}/json-error` + + function callback(err, data) { + assert.ifError(err) + assert.deepEqual(logs[0], 'Container boot id is not available in cgroups info') + assert.equal(data, null) + assert.equal( + agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, + 1 + ) + end() + } + + getBootId(agent, callback, logger) + }) + + await t.test('records error for no id in response', (ctx, end) => { + const { agent, logs, logger, server } = ctx.nr + const info = server.address() + process.env.ECS_CONTAINER_METADATA_URI_V4 = `http://${info.address}:${info.port}/no-id` + + function callback(err, data) { + assert.ifError(err) + assert.deepEqual(logs, [ + 'Container boot id is not available in cgroups info', + 'Failed to find DockerId in response, omitting boot info' + ]) + assert.equal(data, null) + assert.equal( + agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount, + 1 + ) + end() + } + + getBootId(agent, callback, logger) + }) + + await t.test('records found id', (ctx, end) => { + const { agent, logs, logger, server } = ctx.nr + const info = server.address() + // Cover the non-V4 case: + process.env.ECS_CONTAINER_METADATA_URI = `http://${info.address}:${info.port}/success` + + function callback(err, data) { + assert.ifError(err) + assert.deepEqual(logs, ['Container boot id is not available in cgroups info']) + assert.equal(data, '1e1698469422439ea356071e581e8545-2769485393') + assert.ok( + !agent.metrics._metrics.unscoped['Supportability/utilization/boot_id/error']?.callCount + ) + end() + } + + getBootId(agent, callback, logger) + }) }) diff --git a/test/unit/utilization/main.test.js b/test/unit/utilization/main.test.js index 5872d60ffc..acca4122fe 100644 --- a/test/unit/utilization/main.test.js +++ b/test/unit/utilization/main.test.js @@ -4,17 +4,16 @@ */ 'use strict' -const { test } = require('tap') +const test = require('node:test') +const assert = require('node:assert') const helper = require('../../lib/agent_helper.js') const proxyquire = require('proxyquire') -test('getVendors', function (t) { - t.autoend() - let agent - - t.beforeEach(function () { - agent = helper.loadMockedAgent() - agent.config.utilization = { +test('getVendors', async function (t) { + t.beforeEach(function (ctx) { + ctx.nr = {} + ctx.nr.agent = helper.loadMockedAgent() + ctx.nr.agent.config.utilization = { detect_aws: true, detect_azure: true, detect_gcp: true, @@ -24,11 +23,12 @@ test('getVendors', function (t) { } }) - t.afterEach(function () { - helper.unloadAgent(agent) + t.afterEach(function (ctx) { + helper.unloadAgent(ctx.nr.agent) }) - t.test('calls all vendors', function (t) { + await t.test('calls all vendors', function (ctx, end) { + const { agent } = ctx.nr let awsCalled = false let azureCalled = false let gcpCalled = false @@ -66,18 +66,19 @@ test('getVendors', function (t) { }).getVendors getVendors(agent, function (err) { - t.error(err) - t.ok(awsCalled) - t.ok(azureCalled) - t.ok(gcpCalled) - t.ok(dockerCalled) - t.ok(kubernetesCalled) - t.ok(pcfCalled) - t.end() + assert.ifError(err) + assert.ok(awsCalled) + assert.ok(azureCalled) + assert.ok(gcpCalled) + assert.ok(dockerCalled) + assert.ok(kubernetesCalled) + assert.ok(pcfCalled) + end() }) }) - t.test('returns multiple vendors if available', function (t) { + await t.test('returns multiple vendors if available', function (ctx, end) { + const { agent } = ctx.nr const getVendors = proxyquire('../../../lib/utilization', { './aws-info': function (agentArg, cb) { cb(null, 'aws info') @@ -90,10 +91,10 @@ test('getVendors', function (t) { }).getVendors getVendors(agent, function (err, vendors) { - t.error(err) - t.equal(vendors.aws, 'aws info') - t.equal(vendors.docker, 'docker info') - t.end() + assert.ifError(err) + assert.equal(vendors.aws, 'aws info') + assert.equal(vendors.docker, 'docker info') + end() }) }) })