From 9e7086d0eb4de54eeaab8a547cec2bc6ec7fb596 Mon Sep 17 00:00:00 2001 From: Bob Evans Date: Mon, 22 Jul 2024 17:51:25 -0400 Subject: [PATCH 1/3] feat!: Updated `mongodb` instrumentation to drop support for versions 2 and 3. --- docker-compose.yml | 14 +- lib/instrumentation/mongodb.js | 9 +- lib/instrumentation/mongodb/v2-mongo.js | 118 -------- lib/instrumentation/mongodb/v3-mongo.js | 85 ------ test/lib/params.js | 5 - test/versioned/mongodb/collection-common.js | 164 +++++------ .../versioned/mongodb/collection-index.tap.js | 11 +- test/versioned/mongodb/common.js | 101 +------ test/versioned/mongodb/db-common.js | 4 - test/versioned/mongodb/legacy/bulk.tap.js | 60 ---- test/versioned/mongodb/legacy/cursor.tap.js | 112 ------- test/versioned/mongodb/legacy/db.tap.js | 256 ---------------- test/versioned/mongodb/legacy/find.tap.js | 70 ----- test/versioned/mongodb/legacy/index.tap.js | 97 ------- test/versioned/mongodb/legacy/misc.tap.js | 274 ------------------ test/versioned/mongodb/legacy/update.tap.js | 178 ------------ test/versioned/mongodb/package.json | 26 +- 17 files changed, 93 insertions(+), 1491 deletions(-) delete mode 100644 lib/instrumentation/mongodb/v2-mongo.js delete mode 100644 lib/instrumentation/mongodb/v3-mongo.js delete mode 100644 test/versioned/mongodb/legacy/bulk.tap.js delete mode 100644 test/versioned/mongodb/legacy/cursor.tap.js delete mode 100644 test/versioned/mongodb/legacy/db.tap.js delete mode 100644 test/versioned/mongodb/legacy/find.tap.js delete mode 100644 test/versioned/mongodb/legacy/index.tap.js delete mode 100644 test/versioned/mongodb/legacy/misc.tap.js delete mode 100644 test/versioned/mongodb/legacy/update.tap.js diff --git a/docker-compose.yml b/docker-compose.yml index 18036638ea..849bb27f5f 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,23 +60,11 @@ services: ports: - "11211:11211" - mongodb_3: - container_name: nr_node_mongodb - platform: ${DOCKER_PLATFORM:-linux/amd64} - image: library/mongo:3 - ports: - - "27017:27017" - healthcheck: - test: ["CMD", "mongo", "--quiet"] - interval: 1s - timeout: 10s - retries: 30 - mongodb_5: container_name: nr_node_mongodb_5 image: library/mongo:5 ports: - - "27018:27017" + - "27017:27017" healthcheck: test: ["CMD", "mongo", "--quiet"] interval: 1s diff --git a/lib/instrumentation/mongodb.js b/lib/instrumentation/mongodb.js index e8c201a289..0cafb38e1d 100644 --- a/lib/instrumentation/mongodb.js +++ b/lib/instrumentation/mongodb.js @@ -6,8 +6,6 @@ 'use strict' const semver = require('semver') -const instrument = require('./mongodb/v2-mongo') -const instrumentV3 = require('./mongodb/v3-mongo') const instrumentV4 = require('./mongodb/v4-mongo') // XXX: When this instrumentation is modularized, update this thread @@ -39,9 +37,10 @@ function initialize(agent, mongodb, moduleName, shim) { const mongoVersion = shim.pkgVersion if (semver.satisfies(mongoVersion, '>=4.0.0')) { instrumentV4(shim, mongodb) - } else if (semver.satisfies(mongoVersion, '>=3.0.6')) { - instrumentV3(shim, mongodb) } else { - instrument(shim, mongodb) + shim.logger.warn( + 'New Relic Node.js agent no longer supports mongodb < 4, current version %s. Please downgrade to v11 for support, if needed', + mongoVersion + ) } } diff --git a/lib/instrumentation/mongodb/v2-mongo.js b/lib/instrumentation/mongodb/v2-mongo.js deleted file mode 100644 index 5ee1231460..0000000000 --- a/lib/instrumentation/mongodb/v2-mongo.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const { captureAttributesOnStarted, makeQueryDescFunc } = require('./common') -const { OperationSpec } = require('../../shim/specs') - -/** - * parser used to grab the collection and operation - * from a running query - * - * @param {object} operation - */ -function queryParser(operation) { - let collection = this.collectionName || 'unknown' - if (this.ns) { - collection = this.ns.split(/\./)[1] || collection - } - - return { operation, collection } -} -/** - * Registers relevant instrumentation for mongo <= 3.0.6 - * and >= 2. This relies on the built-in "APM" hook points - * to instrument their provided objects as well as sets - * up a listener for when commands start to properly - * add necessary attributes to segments - * - * @param {Shim} shim - * @param {object} mongodb resolved package - */ -module.exports = function instrument(shim, mongodb) { - shim.setParser(queryParser) - - const recordDesc = { - Gridstore: { - isQuery: false, - makeDescFunc: function makeGridDesc(shim, fn, opName) { - return new OperationSpec({ name: 'GridFS-' + opName, callback: shim.LAST }) - } - }, - OrderedBulkOperation: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - UnorderedBulkOperation: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - CommandCursor: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - AggregationCursor: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - Cursor: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - Collection: { isQuery: true, makeDescFunc: makeQueryDescFunc }, - Db: { - isQuery: false, - makeDescFunc: function makeDbDesc(shim, fn, method) { - return new OperationSpec({ callback: shim.LAST, name: method }) - } - } - } - - // instrument using the apm api - const instrumenter = mongodb.instrument(Object.create(null), instrumentModules) - captureAttributesOnStarted(shim, instrumenter) - - /** - * Every module groups instrumentations by their - * promise, callback, return permutations - * Iterate over permutations and properly - * wrap depending on the `recordDesc` above - * See: https://github.com/mongodb/node-mongodb-native/blob/v3.0.5/lib/collection.js#L384 - * - * @param _ - * @param modules - */ - function instrumentModules(_, modules) { - modules.forEach((module) => { - const { obj, instrumentations, name } = module - instrumentations.forEach((meta) => { - applyInstrumentation(name, obj, meta) - }) - }) - } - - /** - * Iterate over methods on object and lookup in `recordDesc` to decide - * if it needs to be wrapped as an operation or query - * - * @param {string} objectName name of class getting instrumented - * @param {object} object reference to the class getting instrumented - * @param {Define} meta describes the methods and if they are callbacks - * promises, and return values - */ - function applyInstrumentation(objectName, object, meta) { - const { methods, options } = meta - if (options.callback) { - methods.forEach((method) => { - const { isQuery, makeDescFunc } = recordDesc[objectName] - const proto = object.prototype - if (isQuery) { - shim.recordQuery(proto, method, makeDescFunc) - } else if (isQuery === false) { - // could be unset - shim.recordOperation(proto, method, makeDescFunc) - } else { - shim.logger.trace('No wrapping method found for %s', objectName) - } - }) - } - - // the cursor object implements Readable stream and internally calls nextObject on - // each read, in which case we do not want to record each nextObject() call - if (/Cursor$/.test(objectName)) { - shim.recordOperation( - object.prototype, - 'pipe', - new OperationSpec({ opaque: true, name: 'pipe' }) - ) - } - } -} diff --git a/lib/instrumentation/mongodb/v3-mongo.js b/lib/instrumentation/mongodb/v3-mongo.js deleted file mode 100644 index 14507b8722..0000000000 --- a/lib/instrumentation/mongodb/v3-mongo.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2021 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const { RecorderSpec } = require('../../shim/specs') -const { - captureAttributesOnStarted, - instrumentBulkOperation, - instrumentCollection, - instrumentCursor, - instrumentDb -} = require('./common') - -/** - * parser used to grab the collection and operation - * on every mongo operation - * - * @param {object} operation mongodb operation - * @returns {object} { operation, collection } parsed operation and collection - */ -function queryParser(operation) { - let collection = this.collectionName || 'unknown' - // in v3.3.0 aggregate commands added the collection - // to target - if (this.operation && this.operation.target) { - collection = this.operation.target - } else if (this.ns) { - collection = this.ns.split(/\./)[1] || collection - } else if (this.s && this.s.collection && this.s.collection.collectionName) { - collection = this.s.collection.collectionName - } - return { operation, collection } -} - -/** - * Records the `mongo.MongoClient.connect` operations. It also adds the first arg of connect(url) - * to a Symbol on the MongoClient to be used later to extract the host/port in cases where the topology - * is a cluster of domain sockets - * - * @param {Shim} shim instance of shim - * @param {object} mongodb resolved package - */ -function instrumentClient(shim, mongodb) { - shim.recordOperation(mongodb.MongoClient, 'connect', function wrappedConnect(shim) { - return new RecorderSpec({ callback: shim.LAST, name: 'connect' }) - }) -} - -/** - * Registers relevant instrumentation for mongo >= 3.0.6 - * In 3.0.6 they refactored their "APM" module which removed - * a lot of niceities around instrumentation classes. - * see: https://github.com/mongodb/node-mongodb-native/pull/1675/files - * This reverts back to instrumenting pre-canned methods on classes - * as well as sets up a listener for when commands start to properly - * add necessary attributes to segments - * - * @param {Shim} shim instance of shim - * @param {object} mongodb resolved package - */ -module.exports = function instrument(shim, mongodb) { - shim.setParser(queryParser) - instrumentClient(shim, mongodb) - const instrumenter = mongodb.instrument(Object.create(null), () => {}) - // in v3 of mongo endSessions fires after every command and it updates the active segment - // attributes with the admin database name which stomps on the database name where the original - // command runs on - captureAttributesOnStarted(shim, instrumenter, { skipCommands: ['endSessions'] }) - instrumentCursor(shim, mongodb.Cursor) - instrumentCursor(shim, shim.require('./lib/aggregation_cursor')) - instrumentCursor(shim, shim.require('./lib/command_cursor')) - instrumentBulkOperation(shim, shim.require('./lib/bulk/common')) - instrumentCollection(shim, mongodb.Collection) - instrumentDb(shim, mongodb.Db) - - // calling instrument sets up listeners for a few events - // we should restore this on unload to avoid leaking - // event emitters - shim.agent.once('unload', function uninstrumentMongo() { - instrumenter.uninstrument() - }) -} diff --git a/test/lib/params.js b/test/lib/params.js index 60f82472e4..22dffd2d3d 100644 --- a/test/lib/params.js +++ b/test/lib/params.js @@ -15,11 +15,6 @@ module.exports = { mongodb_host: process.env.NR_NODE_TEST_MONGODB_HOST || 'localhost', mongodb_port: process.env.NR_NODE_TEST_MONGODB_PORT || 27017, - // mongodb 4.2.0 does not allow mongo server v2. - // There is now a separate container that maps 27018 to mongo:5 - mongodb_v4_host: process.env.NR_NODE_TEST_MONGODB_V4_HOST || 'localhost', - mongodb_v4_port: process.env.NR_NODE_TEST_MONGODB_V4_PORT || 27018, - mysql_host: process.env.NR_NODE_TEST_MYSQL_HOST || 'localhost', mysql_port: process.env.NR_NODE_TEST_MYSQL_PORT || 3306, diff --git a/test/versioned/mongodb/collection-common.js b/test/versioned/mongodb/collection-common.js index 73417bd600..6f18c96e5b 100644 --- a/test/versioned/mongodb/collection-common.js +++ b/test/versioned/mongodb/collection-common.js @@ -8,8 +8,6 @@ const common = require('./common') const tap = require('tap') const helper = require('../../lib/agent_helper') -const semver = require('semver') -const { version: pkgVersion } = require('mongodb/package') let METRIC_HOST_NAME = null let METRIC_HOST_PORT = null @@ -184,104 +182,100 @@ function collectionTest(name, run) { }) }) - // this seems to break in 3.x up to 3.6.0 - // I think it is because of this https://jira.mongodb.org/browse/NODE-2452 - if (semver.satisfies(pkgVersion, '>=3.6.0')) { - t.test('replica set string remote connection', function (t) { - t.autoend() - t.beforeEach(async function () { - agent = helper.instrumentMockedAgent() - - const mongodb = require('mongodb') - - await dropTestCollections(mongodb) - METRIC_HOST_NAME = common.getHostName(agent) - METRIC_HOST_PORT = common.getPort() - const res = await common.connect(mongodb, null, true) - client = res.client - db = res.db - collection = db.collection(COLLECTIONS.collection1) - await populate(collection) - }) + t.test('replica set string remote connection', function (t) { + t.autoend() + t.beforeEach(async function () { + agent = helper.instrumentMockedAgent() - t.afterEach(async function () { - await common.close(client, db) - helper.unloadAgent(agent) - agent = null - }) + const mongodb = require('mongodb') - t.test('should generate the correct metrics and segments', function (t) { - helper.runInTransaction(agent, function (transaction) { - transaction.name = common.TRANSACTION_NAME - run( - t, - collection, - function (err, segments, metrics, { childrenLength = 1, strict = true } = {}) { - if ( - !t.error(err, 'running test should not error') || - !t.ok(agent.getTransaction(), 'should maintain tx state') - ) { - return t.end() - } - t.equal(agent.getTransaction().id, transaction.id, 'should not change transactions') - const segment = agent.tracer.getSegment() - let current = transaction.trace.root - - // this logic is just for the collection.aggregate. - // aggregate no longer returns a callback with cursor - // it just returns a cursor. so the segments on the - // transaction are not nested but both on the trace - // root. instead of traversing the children, just - // iterate over the expected segments and compare - // against the corresponding child on trace root - // we also added a strict flag for aggregate because depending on the version - // there is an extra segment for the callback of our test which we do not care - // to assert - if (childrenLength === 2) { - t.equal(current.children.length, childrenLength, 'should have one child') + await dropTestCollections(mongodb) + METRIC_HOST_NAME = common.getHostName(agent) + METRIC_HOST_PORT = common.getPort() + const res = await common.connect(mongodb, null, true) + client = res.client + db = res.db + collection = db.collection(COLLECTIONS.collection1) + await populate(collection) + }) + + t.afterEach(async function () { + await common.close(client, db) + helper.unloadAgent(agent) + agent = null + }) - segments.forEach((expectedSegment, i) => { - const child = current.children[i] - - t.equal(child.name, expectedSegment, `child should be named ${expectedSegment}`) - if (common.MONGO_SEGMENT_RE.test(child.name)) { - checkSegmentParams(t, child) - t.equal(child.ignore, false, 'should not ignore segment') - } - - if (strict) { - t.equal(child.children.length, 0, 'should have no more children') - } - }) - } else { - for (let i = 0, l = segments.length; i < l; ++i) { - t.equal(current.children.length, childrenLength, 'should have one child') - current = current.children[0] - t.equal(current.name, segments[i], 'child should be named ' + segments[i]) - if (common.MONGO_SEGMENT_RE.test(current.name)) { - checkSegmentParams(t, current) - t.equal(current.ignore, false, 'should not ignore segment') - } + t.test('should generate the correct metrics and segments', function (t) { + helper.runInTransaction(agent, function (transaction) { + transaction.name = common.TRANSACTION_NAME + run( + t, + collection, + function (err, segments, metrics, { childrenLength = 1, strict = true } = {}) { + if ( + !t.error(err, 'running test should not error') || + !t.ok(agent.getTransaction(), 'should maintain tx state') + ) { + return t.end() + } + t.equal(agent.getTransaction().id, transaction.id, 'should not change transactions') + const segment = agent.tracer.getSegment() + let current = transaction.trace.root + + // this logic is just for the collection.aggregate. + // aggregate no longer returns a callback with cursor + // it just returns a cursor. so the segments on the + // transaction are not nested but both on the trace + // root. instead of traversing the children, just + // iterate over the expected segments and compare + // against the corresponding child on trace root + // we also added a strict flag for aggregate because depending on the version + // there is an extra segment for the callback of our test which we do not care + // to assert + if (childrenLength === 2) { + t.equal(current.children.length, childrenLength, 'should have one child') + + segments.forEach((expectedSegment, i) => { + const child = current.children[i] + + t.equal(child.name, expectedSegment, `child should be named ${expectedSegment}`) + if (common.MONGO_SEGMENT_RE.test(child.name)) { + checkSegmentParams(t, child) + t.equal(child.ignore, false, 'should not ignore segment') } if (strict) { - t.equal(current.children.length, 0, 'should have no more children') + t.equal(child.children.length, 0, 'should have no more children') + } + }) + } else { + for (let i = 0, l = segments.length; i < l; ++i) { + t.equal(current.children.length, childrenLength, 'should have one child') + current = current.children[0] + t.equal(current.name, segments[i], 'child should be named ' + segments[i]) + if (common.MONGO_SEGMENT_RE.test(current.name)) { + checkSegmentParams(t, current) + t.equal(current.ignore, false, 'should not ignore segment') } } if (strict) { - t.ok(current === segment, 'should test to the current segment') + t.equal(current.children.length, 0, 'should have no more children') } + } - transaction.end() - common.checkMetrics(t, agent, METRIC_HOST_NAME, METRIC_HOST_PORT, metrics || []) - t.end() + if (strict) { + t.ok(current === segment, 'should test to the current segment') } - ) - }) + + transaction.end() + common.checkMetrics(t, agent, METRIC_HOST_NAME, METRIC_HOST_PORT, metrics || []) + t.end() + } + ) }) }) - } + }) }) } diff --git a/test/versioned/mongodb/collection-index.tap.js b/test/versioned/mongodb/collection-index.tap.js index 6014a9cc66..0576063696 100644 --- a/test/versioned/mongodb/collection-index.tap.js +++ b/test/versioned/mongodb/collection-index.tap.js @@ -6,8 +6,7 @@ 'use strict' const common = require('./collection-common') -const semver = require('semver') -const { COLLECTIONS, DB_NAME, pkgVersion, STATEMENT_PREFIX } = require('./common') +const { STATEMENT_PREFIX } = require('./common') common.test('createIndex', async function createIndexTest(t, collection, verify) { const data = await collection.createIndex('i') @@ -36,14 +35,6 @@ common.test('indexes', async function indexesTest(t, collection, verify) { name: '_id_' } - // this will fail if running a mongodb server > 4.3.1 - // https://jira.mongodb.org/browse/SERVER-41696 - // we only connect to a server > 4.3.1 when using the mongodb - // driver of 4.2.0+ - if (semver.satisfies(pkgVersion, '<4.2.0')) { - expectedResult.ns = `${DB_NAME}.${COLLECTIONS.collection1}` - } - t.same(result, expectedResult, 'should have expected results') verify(null, [`${STATEMENT_PREFIX}/indexes`], ['indexes'], { strict: false }) diff --git a/test/versioned/mongodb/common.js b/test/versioned/mongodb/common.js index 256d94db16..d4dd44fb22 100644 --- a/test/versioned/mongodb/common.js +++ b/test/versioned/mongodb/common.js @@ -7,7 +7,6 @@ const mongoPackage = require('mongodb/package.json') const params = require('../../lib/params') -const semver = require('semver') const urltils = require('../../../lib/util/urltils') const MONGO_SEGMENT_RE = /^Datastore\/.*?\/MongoDB/ @@ -23,87 +22,17 @@ exports.COLLECTIONS = COLLECTIONS exports.STATEMENT_PREFIX = STATEMENT_PREFIX exports.pkgVersion = mongoPackage.version -// Check package versions to decide which connect function to use below -exports.connect = function connect() { - if (semver.satisfies(mongoPackage.version, '<3')) { - return connectV2.apply(this, arguments) - } else if (semver.satisfies(mongoPackage.version, '>=3 <4.2.0')) { - return connectV3.apply(this, arguments) - } - return connectV4.apply(this, arguments) -} - -exports.close = function close() { - if (semver.satisfies(mongoPackage.version, '<4')) { - return closeLegacy.apply(this, arguments) - } - return closeAsync.apply(this, arguments) -} - +exports.connect = connect +exports.close = close exports.checkMetrics = checkMetrics exports.getHostName = getHostName exports.getPort = getPort -function connectV2(mongodb, path) { - return new Promise((resolve, reject) => { - let server = null - if (path) { - server = new mongodb.Server(path) - } else { - server = new mongodb.Server(params.mongodb_host, params.mongodb_port, { - socketOptions: { - connectionTimeoutMS: 30000, - socketTimeoutMS: 30000 - } - }) - } - - const db = new mongodb.Db(DB_NAME, server) - - db.open(function (err) { - if (err) { - reject(err) - } - - resolve({ db, client: null }) - }) - }) -} - -function connectV3(mongodb, host, replicaSet = false) { - return new Promise((resolve, reject) => { - if (host) { - host = encodeURIComponent(host) - } else { - host = params.mongodb_host + ':' + params.mongodb_port - } - - let connString = `mongodb://${host}` - let options = {} - - if (replicaSet) { - connString = `mongodb://${host},${host},${host}` - options = { useNewUrlParser: true, useUnifiedTopology: true } - } - mongodb.MongoClient.connect(connString, options, function (err, client) { - if (err) { - reject(err) - } - - const db = client.db(DB_NAME) - resolve({ db, client }) - }) - }) -} - -// This is same as connectV3 except it uses a different -// set of params to connect to the mongodb_v4 container -// it is actually just using the `mongodb:5` image -async function connectV4(mongodb, host, replicaSet = false) { +async function connect(mongodb, host, replicaSet = false) { if (host) { host = encodeURIComponent(host) } else { - host = params.mongodb_v4_host + ':' + params.mongodb_v4_port + host = params.mongodb_host + ':' + params.mongodb_port } let connString = `mongodb://${host}` @@ -118,19 +47,7 @@ async function connectV4(mongodb, host, replicaSet = false) { return { db, client } } -function closeLegacy(client, db) { - return new Promise((resolve) => { - if (db && typeof db.close === 'function') { - db.close(resolve) - } else if (client) { - client.close(true, resolve) - } else { - resolve() - } - }) -} - -async function closeAsync(client, db) { +async function close(client, db) { if (db && typeof db.close === 'function') { await db.close() } else if (client) { @@ -139,16 +56,12 @@ async function closeAsync(client, db) { } function getHostName(agent) { - const host = semver.satisfies(mongoPackage.version, '>=4.2.0') - ? params.mongodb_v4_host - : params.mongodb_host + const host = params.mongodb_host return urltils.isLocalhost(host) ? agent.config.getHostnameSafe() : host } function getPort() { - return semver.satisfies(mongoPackage.version, '>=4.2.0') - ? String(params.mongodb_v4_port) - : String(params.mongodb_port) + return String(params.mongodb_port) } function checkMetrics(t, agent, host, port, metrics) { diff --git a/test/versioned/mongodb/db-common.js b/test/versioned/mongodb/db-common.js index ee57ebf320..000db19280 100644 --- a/test/versioned/mongodb/db-common.js +++ b/test/versioned/mongodb/db-common.js @@ -5,7 +5,6 @@ 'use strict' const common = require('./common') -const semver = require('semver') const collectionCommon = require('./collection-common') const helper = require('../../lib/agent_helper') const tap = require('tap') @@ -13,9 +12,6 @@ const tap = require('tap') let MONGO_HOST = null let MONGO_PORT = null const BAD_MONGO_COMMANDS = ['collection'] -if (semver.satisfies(common.pkgVersion, '2.2.x')) { - BAD_MONGO_COMMANDS.push('authenticate', 'logout') -} function dbTest(name, run) { mongoTest(name, function init(t, agent) { diff --git a/test/versioned/mongodb/legacy/bulk.tap.js b/test/versioned/mongodb/legacy/bulk.tap.js deleted file mode 100644 index 662e9b54ea..0000000000 --- a/test/versioned/mongodb/legacy/bulk.tap.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2022 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const common = require('../collection-common') -const semver = require('semver') -const { pkgVersion, STATEMENT_PREFIX } = require('../common') - -// see test/versioned/mongodb/common.js -if (semver.satisfies(pkgVersion, '>=3.2.4')) { - common.test('unorderedBulkOp', function unorderedBulkOpTest(t, collection, verify) { - const bulk = collection.initializeUnorderedBulkOp() - bulk - .find({ - i: 1 - }) - .updateOne({ - $set: { foo: 'bar' } - }) - bulk - .find({ - i: 2 - }) - .updateOne({ - $set: { foo: 'bar' } - }) - - bulk.execute(function done(err) { - t.error(err) - verify(null, [`${STATEMENT_PREFIX}/unorderedBulk/batch`, 'Callback: done'], ['unorderedBulk']) - }) - }) - - common.test('orderedBulkOp', function unorderedBulkOpTest(t, collection, verify) { - const bulk = collection.initializeOrderedBulkOp() - bulk - .find({ - i: 1 - }) - .updateOne({ - $set: { foo: 'bar' } - }) - - bulk - .find({ - i: 2 - }) - .updateOne({ - $set: { foo: 'bar' } - }) - - bulk.execute(function done(err) { - t.error(err) - verify(null, [`${STATEMENT_PREFIX}/orderedBulk/batch`, 'Callback: done'], ['orderedBulk']) - }) - }) -} diff --git a/test/versioned/mongodb/legacy/cursor.tap.js b/test/versioned/mongodb/legacy/cursor.tap.js deleted file mode 100644 index c9ebee7747..0000000000 --- a/test/versioned/mongodb/legacy/cursor.tap.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const common = require('../collection-common') -const concat = require('concat-stream') -const helper = require('../../../lib/agent_helper') -const semver = require('semver') -const tap = require('tap') -const { pkgVersion, STATEMENT_PREFIX, COLLECTIONS } = require('../common') - -common.test('count', function countTest(t, collection, verify) { - collection.find({}).count(function onCount(err, data) { - t.notOk(err, 'should not error') - t.ok(data >= 30, 'should have correct result') - verify(null, [`${STATEMENT_PREFIX}/count`, 'Callback: onCount'], ['count']) - }) -}) - -common.test('explain', function explainTest(t, collection, verify) { - collection.find({}).explain(function onExplain(err, data) { - t.error(err) - // Depending on the version of the mongo server the explain plan is different. - if (data.hasOwnProperty('cursor')) { - t.equal(data.cursor, 'BasicCursor', 'should have correct response') - } else { - t.ok(data.hasOwnProperty('queryPlanner'), 'should have correct response') - } - verify(null, [`${STATEMENT_PREFIX}/explain`, 'Callback: onExplain'], ['explain']) - }) -}) - -if (semver.satisfies(pkgVersion, '<3')) { - common.test('nextObject', function nextObjectTest(t, collection, verify) { - collection.find({}).nextObject(function onNextObject(err, data) { - t.notOk(err) - t.equal(data.i, 0) - verify(null, [`${STATEMENT_PREFIX}/nextObject`, 'Callback: onNextObject'], ['nextObject']) - }) - }) -} - -common.test('next', function nextTest(t, collection, verify) { - collection.find({}).next(function onNext(err, data) { - t.notOk(err) - t.equal(data.i, 0) - verify(null, [`${STATEMENT_PREFIX}/next`, 'Callback: onNext'], ['next']) - }) -}) - -common.test('toArray', function toArrayTest(t, collection, verify) { - collection.find({}).toArray(function onToArray(err, data) { - t.notOk(err) - t.equal(data[0].i, 0) - verify(null, [`${STATEMENT_PREFIX}/toArray`, 'Callback: onToArray'], ['toArray']) - }) -}) - -tap.test('piping cursor stream hides internal calls', function (t) { - let agent = helper.instrumentMockedAgent() - let client = null - let db = null - let collection = null - - t.teardown(async function () { - await common.close(client, db) - helper.unloadAgent(agent) - agent = null - }) - - const mongodb = require('mongodb') - common - .dropTestCollections(mongodb) - .then(() => { - return common.connect(mongodb) - }) - .then((res) => { - client = res.client - db = res.db - - collection = db.collection(COLLECTIONS.collection1) - return common.populate(collection) - }) - .then(runTest) - - function runTest() { - helper.runInTransaction(agent, function (transaction) { - transaction.name = common.TRANSACTION_NAME - const destination = concat(function () {}) - - destination.on('finish', function () { - transaction.end() - t.equal( - transaction.trace.root.children[0].name, - 'Datastore/operation/MongoDB/pipe', - 'should have pipe segment' - ) - t.equal( - 0, - transaction.trace.root.children[0].children.length, - 'pipe should not have any children' - ) - t.end() - }) - - collection.find({}).pipe(destination) - }) - } -}) diff --git a/test/versioned/mongodb/legacy/db.tap.js b/test/versioned/mongodb/legacy/db.tap.js deleted file mode 100644 index e05ded4acc..0000000000 --- a/test/versioned/mongodb/legacy/db.tap.js +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const semver = require('semver') -const { dbTest, mongoTest } = require('../db-common') -const params = require('../../../lib/params') -const helper = require('../../../lib/agent_helper') -const { pkgVersion, COLLECTIONS, DB_NAME } = require('../common') - -if (semver.satisfies(pkgVersion, '<3')) { - mongoTest('open', function openTest(t, agent) { - const mongodb = require('mongodb') - const server = new mongodb.Server(params.mongodb_host, params.mongodb_port) - const db = new mongodb.Db(DB_NAME, server) - - helper.runInTransaction(agent, function inTransaction(transaction) { - db.open(function onOpen(err, _db) { - const segment = agent.tracer.getSegment() - t.error(err, 'db.open should not error') - t.equal(db, _db, 'should pass through the arguments correctly') - t.equal(agent.getTransaction(), transaction, 'should not lose tx state') - t.equal(segment.name, 'Callback: onOpen', 'should create segments') - t.equal(transaction.trace.root.children.length, 1, 'should only create one') - const parent = transaction.trace.root.children[0] - t.equal(parent.name, 'Datastore/operation/MongoDB/open', 'should name segment correctly') - t.not(parent.children.indexOf(segment), -1, 'should have callback as child') - db.close() - t.end() - }) - }) - }) - - dbTest('logout', function logoutTest(t, db, verify) { - db.logout({}, function loggedOut(err) { - t.error(err, 'should not have error') - verify(['Datastore/operation/MongoDB/logout', 'Callback: loggedOut'], { legacy: true }) - }) - }) -} - -dbTest('addUser, authenticate, removeUser', function addUserTest(t, db, verify) { - const userName = 'user-test' - const userPass = 'user-test-pass' - - db.removeUser(userName, function preRemove() { - // Don't care if this first remove fails, it's just to ensure a clean slate. - db.addUser(userName, userPass, { roles: ['readWrite'] }, added) - }) - - function added(err) { - if (!t.error(err, 'addUser should not have error')) { - return t.end() - } - - if (typeof db.authenticate === 'function') { - db.authenticate(userName, userPass, authed) - } else { - t.comment('Skipping authentication test, not supported on db') - db.removeUser(userName, removedNoAuth) - } - } - - function authed(err) { - if (!t.error(err, 'authenticate should not have error')) { - return t.end() - } - db.removeUser(userName, removed) - } - - function removed(err) { - if (!t.error(err, 'removeUser should not have error')) { - return t.end() - } - verify( - [ - 'Datastore/operation/MongoDB/removeUser', - 'Callback: preRemove', - 'Datastore/operation/MongoDB/addUser', - 'Callback: added', - 'Datastore/operation/MongoDB/authenticate', - 'Callback: authed', - 'Datastore/operation/MongoDB/removeUser', - 'Callback: removed' - ], - { legacy: true } - ) - } - - function removedNoAuth(err) { - if (!t.error(err, 'removeUser should not have error')) { - return t.end() - } - verify( - [ - 'Datastore/operation/MongoDB/removeUser', - 'Callback: preRemove', - 'Datastore/operation/MongoDB/addUser', - 'Callback: added', - 'Datastore/operation/MongoDB/removeUser', - 'Callback: removedNoAuth' - ], - { legacy: true } - ) - } -}) - -dbTest('collection', function collectionTest(t, db, verify) { - db.collection(COLLECTIONS.collection1, function gotCollection(err, collection) { - t.error(err, 'should not have error') - t.ok(collection, 'collection is not null') - verify(['Datastore/operation/MongoDB/collection', 'Callback: gotCollection'], { legacy: true }) - }) -}) - -dbTest('eval', function evalTest(t, db, verify) { - db.eval('function (x) {return x;}', [3], function evaled(err, result) { - t.error(err, 'should not have error') - t.equal(3, result, 'should produce the right result') - verify(['Datastore/operation/MongoDB/eval', 'Callback: evaled'], { legacy: true }) - }) -}) - -dbTest('collections', function collectionTest(t, db, verify) { - db.collections(function gotCollections(err2, collections) { - t.error(err2, 'should not have error') - t.ok(Array.isArray(collections), 'got array of collections') - verify(['Datastore/operation/MongoDB/collections', 'Callback: gotCollections'], { - legacy: true - }) - }) -}) - -dbTest('command', function commandTest(t, db, verify) { - db.command({ ping: 1 }, function onCommand(err, result) { - t.error(err, 'should not have error') - t.same(result, { ok: 1 }, 'got correct result') - verify(['Datastore/operation/MongoDB/command', 'Callback: onCommand'], { legacy: true }) - }) -}) - -dbTest('createCollection', function createTest(t, db, verify) { - db.createCollection(COLLECTIONS.collection1, function gotCollection(err, collection) { - t.error(err, 'should not have error') - t.equal( - collection.collectionName || collection.s.name, - COLLECTIONS.collection1, - 'new collection should have the right name' - ) - verify(['Datastore/operation/MongoDB/createCollection', 'Callback: gotCollection'], { - legacy: true - }) - }) -}) - -dbTest('createIndex', function createIndexTest(t, db, verify) { - db.createIndex(COLLECTIONS.collection1, 'foo', function createdIndex(err, result) { - t.error(err, 'should not have error') - t.equal(result, 'foo_1', 'should have the right result') - verify(['Datastore/operation/MongoDB/createIndex', 'Callback: createdIndex'], { legacy: true }) - }) -}) - -dbTest('dropCollection', function dropTest(t, db, verify) { - db.createCollection(COLLECTIONS.collection1, function gotCollection(err) { - t.error(err, 'should not have error getting collection') - - db.dropCollection(COLLECTIONS.collection1, function droppedCollection(err, result) { - t.error(err, 'should not have error dropping collection') - t.ok(result === true, 'result should be boolean true') - verify( - [ - 'Datastore/operation/MongoDB/createCollection', - 'Callback: gotCollection', - 'Datastore/operation/MongoDB/dropCollection', - 'Callback: droppedCollection' - ], - { legacy: true } - ) - }) - }) -}) - -dbTest('dropDatabase', function dropDbTest(t, db, verify) { - db.dropDatabase(function droppedDatabase(err, result) { - t.error(err, 'should not have error') - t.ok(result, 'result should be truthy') - verify(['Datastore/operation/MongoDB/dropDatabase', 'Callback: droppedDatabase'], { - legacy: true - }) - }) -}) - -dbTest('ensureIndex', function ensureIndexTest(t, db, verify) { - db.ensureIndex(COLLECTIONS.collection1, 'foo', function ensuredIndex(err, result) { - t.error(err, 'should not have error') - t.equal(result, 'foo_1') - verify(['Datastore/operation/MongoDB/ensureIndex', 'Callback: ensuredIndex'], { legacy: true }) - }) -}) - -dbTest('indexInformation', function indexInfoTest(t, db, verify) { - db.ensureIndex(COLLECTIONS.collection1, 'foo', function ensuredIndex(err) { - t.error(err, 'ensureIndex should not have error') - db.indexInformation(COLLECTIONS.collection1, function gotInfo(err2, result) { - t.error(err2, 'indexInformation should not have error') - t.same(result, { _id_: [['_id', 1]], foo_1: [['foo', 1]] }, 'result is the expected object') - verify( - [ - 'Datastore/operation/MongoDB/ensureIndex', - 'Callback: ensuredIndex', - 'Datastore/operation/MongoDB/indexInformation', - 'Callback: gotInfo' - ], - { legacy: true } - ) - }) - }) -}) - -dbTest('renameCollection', function (t, db, verify) { - db.createCollection(COLLECTIONS.collection1, function gotCollection(err) { - t.error(err, 'should not have error getting collection') - db.renameCollection( - COLLECTIONS.collection1, - COLLECTIONS.collection2, - function renamedCollection(err2) { - t.error(err2, 'should not have error renaming collection') - db.dropCollection(COLLECTIONS.collection2, function droppedCollection(err3) { - t.error(err3) - verify( - [ - 'Datastore/operation/MongoDB/createCollection', - 'Callback: gotCollection', - 'Datastore/operation/MongoDB/renameCollection', - 'Callback: renamedCollection', - 'Datastore/operation/MongoDB/dropCollection', - 'Callback: droppedCollection' - ], - { legacy: true } - ) - }) - } - ) - }) -}) - -dbTest('stats', function statsTest(t, db, verify) { - db.stats({}, function gotStats(err, stats) { - t.error(err, 'should not have error') - t.ok(stats, 'got stats') - verify(['Datastore/operation/MongoDB/stats', 'Callback: gotStats'], { legacy: true }) - }) -}) diff --git a/test/versioned/mongodb/legacy/find.tap.js b/test/versioned/mongodb/legacy/find.tap.js deleted file mode 100644 index fc51d1b81c..0000000000 --- a/test/versioned/mongodb/legacy/find.tap.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' -const common = require('../collection-common') -const { STATEMENT_PREFIX } = require('../common') - -const findOpt = { returnOriginal: false } - -common.test('findAndModify', function findAndModifyTest(t, collection, verify) { - collection.findAndModify({ i: 1 }, [['i', 1]], { $set: { a: 15 } }, { new: true }, done) - - function done(err, data) { - t.error(err) - t.equal(data.value.a, 15) - t.equal(data.value.i, 1) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findAndModify`, 'Callback: done'], ['findAndModify']) - } -}) - -common.test('findAndRemove', function findAndRemoveTest(t, collection, verify) { - collection.findAndRemove({ i: 1 }, [['i', 1]], function done(err, data) { - t.error(err) - t.equal(data.value.i, 1) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findAndRemove`, 'Callback: done'], ['findAndRemove']) - }) -}) - -common.test('findOne', function findOneTest(t, collection, verify) { - collection.findOne({ i: 15 }, function done(err, data) { - t.error(err) - t.equal(data.i, 15) - verify(null, [`${STATEMENT_PREFIX}/findOne`, 'Callback: done'], ['findOne']) - }) -}) - -common.test('findOneAndDelete', function findOneAndDeleteTest(t, collection, verify) { - collection.findOneAndDelete({ i: 15 }, function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - t.equal(data.value.i, 15) - verify(null, [`${STATEMENT_PREFIX}/findOneAndDelete`, 'Callback: done'], ['findOneAndDelete']) - }) -}) - -common.test('findOneAndReplace', function findAndReplaceTest(t, collection, verify) { - collection.findOneAndReplace({ i: 15 }, { b: 15 }, findOpt, done) - - function done(err, data) { - t.error(err) - t.equal(data.value.b, 15) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findOneAndReplace`, 'Callback: done'], ['findOneAndReplace']) - } -}) - -common.test('findOneAndUpdate', function findOneAndUpdateTest(t, collection, verify) { - collection.findOneAndUpdate({ i: 15 }, { $set: { a: 15 } }, findOpt, done) - - function done(err, data) { - t.error(err) - t.equal(data.value.a, 15) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findOneAndUpdate`, 'Callback: done'], ['findOneAndUpdate']) - } -}) diff --git a/test/versioned/mongodb/legacy/index.tap.js b/test/versioned/mongodb/legacy/index.tap.js deleted file mode 100644 index 60f168b78d..0000000000 --- a/test/versioned/mongodb/legacy/index.tap.js +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const common = require('../collection-common') -const { STATEMENT_PREFIX, DB_NAME, COLLECTIONS } = require('../common') - -common.test('createIndex', function createIndexTest(t, collection, verify) { - collection.createIndex('i', function onIndex(err, data) { - t.error(err) - t.equal(data, 'i_1') - verify(null, [`${STATEMENT_PREFIX}/createIndex`, 'Callback: onIndex'], ['createIndex']) - }) -}) - -common.test('dropIndex', function dropIndexTest(t, collection, verify) { - collection.createIndex('i', function onIndex(err) { - t.error(err) - collection.dropIndex('i_1', function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - verify( - null, - [ - `${STATEMENT_PREFIX}/createIndex`, - 'Callback: onIndex', - `${STATEMENT_PREFIX}/dropIndex`, - 'Callback: done' - ], - ['createIndex', 'dropIndex'] - ) - }) - }) -}) - -common.test('indexes', function indexesTest(t, collection, verify) { - collection.indexes(function done(err, data) { - t.error(err) - const result = data && data[0] - const expectedResult = { - v: result && result.v, - key: { _id: 1 }, - name: '_id_', - ns: `${DB_NAME}.${COLLECTIONS.collection1}` - } - - t.same(result, expectedResult, 'should have expected results') - - verify(null, [`${STATEMENT_PREFIX}/indexes`, 'Callback: done'], ['indexes']) - }) -}) - -common.test('indexExists', function indexExistsTest(t, collection, verify) { - collection.indexExists(['_id_'], function done(err, data) { - t.error(err) - t.equal(data, true) - - verify(null, [`${STATEMENT_PREFIX}/indexExists`, 'Callback: done'], ['indexExists']) - }) -}) - -common.test('indexInformation', function indexInformationTest(t, collection, verify) { - collection.indexInformation(function done(err, data) { - t.error(err) - t.same(data && data._id_, [['_id', 1]], 'should have expected results') - - verify(null, [`${STATEMENT_PREFIX}/indexInformation`, 'Callback: done'], ['indexInformation']) - }) -}) - -common.test('dropAllIndexes', function dropAllIndexesTest(t, collection, verify) { - collection.dropAllIndexes(function done(err, data) { - t.error(err) - t.equal(data, true) - verify(null, [`${STATEMENT_PREFIX}/dropAllIndexes`, 'Callback: done'], ['dropAllIndexes']) - }) -}) - -common.test('ensureIndex', function ensureIndexTest(t, collection, verify) { - collection.ensureIndex('i', function done(err, data) { - t.error(err) - t.equal(data, 'i_1') - verify(null, [`${STATEMENT_PREFIX}/ensureIndex`, 'Callback: done'], ['ensureIndex']) - }) -}) - -common.test('reIndex', function reIndexTest(t, collection, verify) { - collection.reIndex(function done(err, data) { - t.error(err) - t.equal(data, true) - - verify(null, [`${STATEMENT_PREFIX}/reIndex`, 'Callback: done'], ['reIndex']) - }) -}) diff --git a/test/versioned/mongodb/legacy/misc.tap.js b/test/versioned/mongodb/legacy/misc.tap.js deleted file mode 100644 index b1cd35b3c7..0000000000 --- a/test/versioned/mongodb/legacy/misc.tap.js +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const common = require('../collection-common') -const semver = require('semver') -const { pkgVersion, STATEMENT_PREFIX, COLLECTIONS, DB_NAME } = require('../common') - -function verifyAggregateData(t, data) { - t.equal(data.length, 3, 'should have expected amount of results') - t.same(data, [{ value: 5 }, { value: 15 }, { value: 25 }], 'should have expected results') -} - -common.test('aggregate', function aggregateTest(t, collection, verify) { - const cursor = collection.aggregate([ - { $sort: { i: 1 } }, - { $match: { mod10: 5 } }, - { $limit: 3 }, - { $project: { value: '$i', _id: 0 } } - ]) - - cursor.toArray(function onResult(err, data) { - verifyAggregateData(t, data) - verify( - err, - [`${STATEMENT_PREFIX}/aggregate`, `${STATEMENT_PREFIX}/toArray`], - ['aggregate', 'toArray'], - { childrenLength: 2, strict: false } - ) - }) -}) - -common.test('bulkWrite', function bulkWriteTest(t, collection, verify) { - collection.bulkWrite( - [{ deleteMany: { filter: {} } }, { insertOne: { document: { a: 1 } } }], - { ordered: true, w: 1 }, - onWrite - ) - - function onWrite(err, data) { - t.error(err) - t.equal(data.insertedCount, 1) - t.equal(data.deletedCount, 30) - verify(null, [`${STATEMENT_PREFIX}/bulkWrite`, 'Callback: onWrite'], ['bulkWrite']) - } -}) - -common.test('count', function countTest(t, collection, verify) { - collection.count(function onCount(err, data) { - t.error(err) - t.equal(data, 30) - verify(null, [`${STATEMENT_PREFIX}/count`, 'Callback: onCount'], ['count']) - }) -}) - -common.test('distinct', function distinctTest(t, collection, verify) { - collection.distinct('mod10', function done(err, data) { - t.error(err) - t.same(data.sort(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) - verify(null, [`${STATEMENT_PREFIX}/distinct`, 'Callback: done'], ['distinct']) - }) -}) - -common.test('drop', function dropTest(t, collection, verify) { - collection.drop(function done(err, data) { - t.error(err) - t.equal(data, true) - verify(null, [`${STATEMENT_PREFIX}/drop`, 'Callback: done'], ['drop']) - }) -}) - -if (semver.satisfies(pkgVersion, '<3')) { - common.test('geoNear', function geoNearTest(t, collection, verify) { - collection.ensureIndex({ loc: '2d' }, { bucketSize: 1 }, indexed) - - function indexed(err) { - t.error(err) - collection.geoNear(20, 20, { maxDistance: 5 }, done) - } - - function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - t.equal(data.results.length, 2) - t.equal(data.results[0].obj.i, 21) - t.equal(data.results[1].obj.i, 17) - t.same(data.results[0].obj.loc, [21, 21]) - t.same(data.results[1].obj.loc, [17, 17]) - t.equal(data.results[0].dis, 1.4142135623730951) - t.equal(data.results[1].dis, 4.242640687119285) - verify( - null, - [ - `${STATEMENT_PREFIX}/ensureIndex`, - 'Callback: indexed', - `${STATEMENT_PREFIX}/geoNear`, - 'Callback: done' - ], - ['ensureIndex', 'geoNear'] - ) - } - }) -} - -common.test('isCapped', function isCappedTest(t, collection, verify) { - collection.isCapped(function done(err, data) { - t.error(err) - t.notOk(data) - - verify(null, [`${STATEMENT_PREFIX}/isCapped`, 'Callback: done'], ['isCapped']) - }) -}) - -common.test('mapReduce', function mapReduceTest(t, collection, verify) { - collection.mapReduce(map, reduce, { out: { inline: 1 } }, done) - - function done(err, data) { - t.error(err) - const expectedData = [ - { _id: 0, value: 30 }, - { _id: 1, value: 33 }, - { _id: 2, value: 36 }, - { _id: 3, value: 39 }, - { _id: 4, value: 42 }, - { _id: 5, value: 45 }, - { _id: 6, value: 48 }, - { _id: 7, value: 51 }, - { _id: 8, value: 54 }, - { _id: 9, value: 57 } - ] - - // data is not sorted depending on speed of - // db calls, sort to compare vs expected collection - data.sort((a, b) => a._id - b._id) - t.same(data, expectedData) - - verify(null, [`${STATEMENT_PREFIX}/mapReduce`, 'Callback: done'], ['mapReduce']) - } - - /* eslint-disable */ - function map(obj) { - emit(this.mod10, this.i) - } - /* eslint-enable */ - - function reduce(key, vals) { - return vals.reduce(function sum(prev, val) { - return prev + val - }, 0) - } -}) - -common.test('options', function optionsTest(t, collection, verify) { - collection.options(function done(err, data) { - t.error(err) - - // Depending on the version of the mongo server this will change. - if (data) { - t.same(data, {}, 'should have expected results') - } else { - t.notOk(data, 'should have expected results') - } - - verify(null, [`${STATEMENT_PREFIX}/options`, 'Callback: done'], ['options']) - }) -}) - -common.test('parallelCollectionScan', function (t, collection, verify) { - collection.parallelCollectionScan({ numCursors: 1 }, function done(err, cursors) { - t.error(err) - - cursors[0].toArray(function toArray(err, items) { - t.error(err) - t.equal(items.length, 30) - - const total = items.reduce(function sum(prev, item) { - return item.i + prev - }, 0) - - t.equal(total, 435) - verify( - null, - [ - `${STATEMENT_PREFIX}/parallelCollectionScan`, - 'Callback: done', - `${STATEMENT_PREFIX}/toArray`, - 'Callback: toArray' - ], - ['parallelCollectionScan', 'toArray'] - ) - }) - }) -}) - -common.test('geoHaystackSearch', function haystackSearchTest(t, collection, verify) { - collection.ensureIndex({ loc: 'geoHaystack', type: 1 }, { bucketSize: 1 }, indexed) - - function indexed(err) { - t.error(err) - collection.geoHaystackSearch(15, 15, { maxDistance: 5, search: {} }, done) - } - - function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - t.equal(data.results.length, 2) - t.equal(data.results[0].i, 13) - t.equal(data.results[1].i, 17) - t.same(data.results[0].loc, [13, 13]) - t.same(data.results[1].loc, [17, 17]) - verify( - null, - [ - `${STATEMENT_PREFIX}/ensureIndex`, - 'Callback: indexed', - `${STATEMENT_PREFIX}/geoHaystackSearch`, - 'Callback: done' - ], - ['ensureIndex', 'geoHaystackSearch'] - ) - } -}) - -common.test('group', function groupTest(t, collection, verify) { - collection.group(['mod10'], {}, { count: 0, total: 0 }, count, done) - - function done(err, data) { - t.error(err) - t.same(data.sort(sort), [ - { mod10: 0, count: 3, total: 30 }, - { mod10: 1, count: 3, total: 33 }, - { mod10: 2, count: 3, total: 36 }, - { mod10: 3, count: 3, total: 39 }, - { mod10: 4, count: 3, total: 42 }, - { mod10: 5, count: 3, total: 45 }, - { mod10: 6, count: 3, total: 48 }, - { mod10: 7, count: 3, total: 51 }, - { mod10: 8, count: 3, total: 54 }, - { mod10: 9, count: 3, total: 57 } - ]) - verify(null, [`${STATEMENT_PREFIX}/group`, 'Callback: done'], ['group']) - } - - function count(obj, prev) { - prev.total += obj.i - prev.count++ - } - - function sort(a, b) { - return a.mod10 - b.mod10 - } -}) - -common.test('rename', function renameTest(t, collection, verify) { - collection.rename(COLLECTIONS.collection2, function done(err) { - t.error(err) - - verify(null, [`${STATEMENT_PREFIX}/rename`, 'Callback: done'], ['rename']) - }) -}) - -common.test('stats', function statsTest(t, collection, verify) { - collection.stats({ i: 5 }, function done(err, data) { - t.error(err) - t.equal(data.ns, `${DB_NAME}.${COLLECTIONS.collection1}`) - t.equal(data.count, 30) - t.equal(data.ok, 1) - - verify(null, [`${STATEMENT_PREFIX}/stats`, 'Callback: done'], ['stats']) - }) -}) diff --git a/test/versioned/mongodb/legacy/update.tap.js b/test/versioned/mongodb/legacy/update.tap.js deleted file mode 100644 index 49fb445805..0000000000 --- a/test/versioned/mongodb/legacy/update.tap.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2020 New Relic Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -'use strict' - -const common = require('../collection-common') -const { STATEMENT_PREFIX } = require('../common') - -/** - * The response from the methods in this file differ between versions - * This helper decides which pieces to assert - * - * @param {Object} params fn params - * @param {Tap.Test} params.t tap instance - * @param {Object} params.data result from callback used to assert - * @param {Number} [params.count] count of results - * @param {Object} params.extraValues extra fields to assert - */ -function assertExpectedResult({ t, data, count, extraValues }) { - const expectedResult = { ok: 1, ...extraValues } - if (count) { - expectedResult.n = count - } - t.same(data.result, expectedResult) -} - -common.test('deleteMany', function deleteManyTest(t, collection, verify) { - collection.deleteMany({ mod10: 5 }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 3 - }) - verify(null, [`${STATEMENT_PREFIX}/deleteMany`, 'Callback: done'], ['deleteMany']) - }) -}) - -common.test('deleteOne', function deleteOneTest(t, collection, verify) { - collection.deleteOne({ mod10: 5 }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 1 - }) - verify(null, [`${STATEMENT_PREFIX}/deleteOne`, 'Callback: done'], ['deleteOne']) - }) -}) - -common.test('insert', function insertTest(t, collection, verify) { - collection.insert({ foo: 'bar' }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 1 - }) - - verify(null, [`${STATEMENT_PREFIX}/insert`, 'Callback: done'], ['insert']) - }) -}) - -common.test('insertMany', function insertManyTest(t, collection, verify) { - collection.insertMany([{ foo: 'bar' }, { foo: 'bar2' }], function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 2 - }) - - verify(null, [`${STATEMENT_PREFIX}/insertMany`, 'Callback: done'], ['insertMany']) - }) -}) - -common.test('insertOne', function insertOneTest(t, collection, verify) { - collection.insertOne({ foo: 'bar' }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - extraValues: { - n: 1 - } - }) - - verify(null, [`${STATEMENT_PREFIX}/insertOne`, 'Callback: done'], ['insertOne']) - }) -}) - -common.test('remove', function removeTest(t, collection, verify) { - collection.remove({ mod10: 5 }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 3 - }) - - verify(null, [`${STATEMENT_PREFIX}/remove`, 'Callback: done'], ['remove']) - }) -}) - -common.test('replaceOne', function replaceOneTest(t, collection, verify) { - collection.replaceOne({ i: 5 }, { foo: 'bar' }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 1, - extraValues: { - nModified: 1 - } - }) - - verify(null, [`${STATEMENT_PREFIX}/replaceOne`, 'Callback: done'], ['replaceOne']) - }) -}) - -common.test('save', function saveTest(t, collection, verify) { - collection.save({ foo: 'bar' }, function done(err, data) { - t.error(err) - t.same(data.result, { ok: 1, n: 1 }) - - verify(null, [`${STATEMENT_PREFIX}/save`, 'Callback: done'], ['save']) - }) -}) - -common.test('update', function updateTest(t, collection, verify) { - collection.update({ i: 5 }, { $set: { foo: 'bar' } }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 1, - extraValues: { - nModified: 1 - } - }) - - verify(null, [`${STATEMENT_PREFIX}/update`, 'Callback: done'], ['update']) - }) -}) - -common.test('updateMany', function updateManyTest(t, collection, verify) { - collection.updateMany({ mod10: 5 }, { $set: { a: 5 } }, function done(err, data) { - t.error(err) - assertExpectedResult({ - t, - data, - count: 3, - extraValues: { - nModified: 3 - } - }) - - verify(null, [`${STATEMENT_PREFIX}/updateMany`, 'Callback: done'], ['updateMany']) - }) -}) - -common.test('updateOne', function updateOneTest(t, collection, verify) { - collection.updateOne({ i: 5 }, { $set: { a: 5 } }, function done(err, data) { - t.notOk(err, 'should not error') - assertExpectedResult({ - t, - data, - count: 1, - extraValues: { - nModified: 1 - } - }) - - verify(null, [`${STATEMENT_PREFIX}/updateOne`, 'Callback: done'], ['updateOne']) - }) -}) diff --git a/test/versioned/mongodb/package.json b/test/versioned/mongodb/package.json index 8d0cfd9709..a81df6118d 100644 --- a/test/versioned/mongodb/package.json +++ b/test/versioned/mongodb/package.json @@ -4,26 +4,6 @@ "version": "0.0.0", "private": true, "tests": [ - { - "engines": { - "node": ">=18" - }, - "dependencies": { - "mongodb": { - "versions": ">=2.1 < 4.0.0", - "samples": "2" - } - }, - "files": [ - "legacy/bulk.tap.js", - "legacy/cursor.tap.js", - "legacy/db.tap.js", - "legacy/find.tap.js", - "legacy/index.tap.js", - "legacy/misc.tap.js", - "legacy/update.tap.js" - ] - }, { "engines": { "node": ">=18" @@ -41,9 +21,5 @@ "db.tap.js" ] } - ], - "dependencies": {}, - "engines": { - "node": ">=18" - } + ] } From b6c915337c0a69a6930715b65edcc65548d2fad3 Mon Sep 17 00:00:00 2001 From: Bob Evans Date: Tue, 23 Jul 2024 15:42:37 -0400 Subject: [PATCH 2/3] chore: fixed mongodb esm tests, added comment explaining nuance of cjs vs esm tests, fixed linting issues --- test/versioned/mongodb-esm/bulk.tap.mjs | 127 ++++++------ .../mongodb-esm/collection-find.tap.mjs | 39 +--- .../mongodb-esm/collection-index.tap.mjs | 42 +--- .../mongodb-esm/collection-misc.tap.mjs | 188 ++---------------- .../mongodb-esm/collection-update.tap.mjs | 48 +---- test/versioned/mongodb-esm/common.cjs | 4 +- test/versioned/mongodb-esm/package.json | 3 +- test/versioned/mongodb/package.json | 6 +- 8 files changed, 102 insertions(+), 355 deletions(-) diff --git a/test/versioned/mongodb-esm/bulk.tap.mjs b/test/versioned/mongodb-esm/bulk.tap.mjs index 5655103297..3dfed0d911 100644 --- a/test/versioned/mongodb-esm/bulk.tap.mjs +++ b/test/versioned/mongodb-esm/bulk.tap.mjs @@ -4,81 +4,76 @@ */ import tap from 'tap' -import semver from 'semver' import { test } from './collection-common.mjs' import helper from '../../lib/agent_helper.js' -import { pkgVersion } from './common.cjs' import { STATEMENT_PREFIX } from './common.cjs' -// see test/versioned/mongodb/common.js -if (semver.satisfies(pkgVersion, '>=3.2.4 <4.1.4')) { - tap.test('Bulk operations', (t) => { - t.autoend() - let agent +tap.test('Bulk operations', (t) => { + t.autoend() + let agent - t.before(() => { - agent = helper.instrumentMockedAgent() - }) - - t.teardown(() => { - helper.unloadAgent(agent) - }) + t.before(() => { + agent = helper.instrumentMockedAgent() + }) - test( - { suiteName: 'unorderedBulkOp', agent, t }, - function unorderedBulkOpTest(t, collection, verify) { - const bulk = collection.initializeUnorderedBulkOp() - bulk - .find({ - i: 1 - }) - .updateOne({ - $set: { foo: 'bar' } - }) - bulk - .find({ - i: 2 - }) - .updateOne({ - $set: { foo: 'bar' } - }) + t.teardown(() => { + helper.unloadAgent(agent) + }) - bulk.execute(function done(err) { - t.error(err) - verify( - null, - [`${STATEMENT_PREFIX}/unorderedBulk/batch`, 'Callback: done'], - ['unorderedBulk'] - ) + test( + { suiteName: 'unorderedBulkOp', agent, t }, + function unorderedBulkOpTest(t, collection, verify) { + const bulk = collection.initializeUnorderedBulkOp() + bulk + .find({ + i: 1 + }) + .updateOne({ + $set: { foo: 'bar' } + }) + bulk + .find({ + i: 2 + }) + .updateOne({ + $set: { foo: 'bar' } }) - } - ) - test( - { suiteName: 'orderedBulkOp', agent, t }, - function unorderedBulkOpTest(t, collection, verify) { - const bulk = collection.initializeOrderedBulkOp() - bulk - .find({ - i: 1 - }) - .updateOne({ - $set: { foo: 'bar' } - }) + bulk.execute(function done(err) { + t.error(err) + verify( + null, + [`${STATEMENT_PREFIX}/unorderedBulk/batch`, 'Callback: done'], + ['unorderedBulk'] + ) + }) + } + ) - bulk - .find({ - i: 2 - }) - .updateOne({ - $set: { foo: 'bar' } - }) + test( + { suiteName: 'orderedBulkOp', agent, t }, + function unorderedBulkOpTest(t, collection, verify) { + const bulk = collection.initializeOrderedBulkOp() + bulk + .find({ + i: 1 + }) + .updateOne({ + $set: { foo: 'bar' } + }) - bulk.execute(function done(err) { - t.error(err) - verify(null, [`${STATEMENT_PREFIX}/orderedBulk/batch`, 'Callback: done'], ['orderedBulk']) + bulk + .find({ + i: 2 }) - } - ) - }) -} + .updateOne({ + $set: { foo: 'bar' } + }) + + bulk.execute(function done(err) { + t.error(err) + verify(null, [`${STATEMENT_PREFIX}/orderedBulk/batch`, 'Callback: done'], ['orderedBulk']) + }) + } + ) +}) diff --git a/test/versioned/mongodb-esm/collection-find.tap.mjs b/test/versioned/mongodb-esm/collection-find.tap.mjs index c78c14ad0b..964df3313f 100644 --- a/test/versioned/mongodb-esm/collection-find.tap.mjs +++ b/test/versioned/mongodb-esm/collection-find.tap.mjs @@ -3,17 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import semver from 'semver' import tap from 'tap' import { test } from './collection-common.mjs' import helper from '../../lib/agent_helper.js' -import { pkgVersion, STATEMENT_PREFIX } from './common.cjs' - -let findOpt = { returnOriginal: false } -// 4.0.0 changed this opt https://github.com/mongodb/node-mongodb-native/pull/2803/files -if (semver.satisfies(pkgVersion, '>=4')) { - findOpt = { returnDocument: 'after' } -} +import { STATEMENT_PREFIX } from './common.cjs' +const findOpt = { returnDocument: 'after' } tap.test('Collection(Find) Tests', (t) => { t.autoend() @@ -27,35 +21,6 @@ tap.test('Collection(Find) Tests', (t) => { helper.unloadAgent(agent) }) - if (semver.satisfies(pkgVersion, '<4')) { - test( - { suiteName: 'findAndModify', agent, t }, - function findAndModifyTest(t, collection, verify) { - collection.findAndModify({ i: 1 }, [['i', 1]], { $set: { a: 15 } }, { new: true }, done) - - function done(err, data) { - t.error(err) - t.equal(data.value.a, 15) - t.equal(data.value.i, 1) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findAndModify`, 'Callback: done'], ['findAndModify']) - } - } - ) - - test( - { suiteName: 'findAndRemove', agent, t }, - function findAndRemoveTest(t, collection, verify) { - collection.findAndRemove({ i: 1 }, [['i', 1]], function done(err, data) { - t.error(err) - t.equal(data.value.i, 1) - t.equal(data.ok, 1) - verify(null, [`${STATEMENT_PREFIX}/findAndRemove`, 'Callback: done'], ['findAndRemove']) - }) - } - ) - } - test({ suiteName: 'findOne', agent, t }, function findOneTest(t, collection, verify) { collection.findOne({ i: 15 }, function done(err, data) { t.error(err) diff --git a/test/versioned/mongodb-esm/collection-index.tap.mjs b/test/versioned/mongodb-esm/collection-index.tap.mjs index 465d3b983b..6e9e3fb52e 100644 --- a/test/versioned/mongodb-esm/collection-index.tap.mjs +++ b/test/versioned/mongodb-esm/collection-index.tap.mjs @@ -3,11 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import semver from 'semver' import tap from 'tap' -import { test, DB_NAME } from './collection-common.mjs' +import { test } from './collection-common.mjs' import helper from '../../lib/agent_helper.js' -import { pkgVersion, STATEMENT_PREFIX, COLLECTIONS } from './common.cjs' +import { STATEMENT_PREFIX } from './common.cjs' tap.test('Collection(Index) Tests', (t) => { t.autoend() @@ -58,13 +57,6 @@ tap.test('Collection(Index) Tests', (t) => { name: '_id_' } - // this will fail if running a mongodb server > 4.3.1 - // https://jira.mongodb.org/browse/SERVER-41696 - // we only connect to a server > 4.3.1 when using the mongodb - // driver of 4.2.0+ - if (semver.satisfies(pkgVersion, '<4.2.0')) { - expectedResult.ns = `${DB_NAME}.${COLLECTIONS.collection1}` - } t.same(result, expectedResult, 'should have expected results') verify(null, [`${STATEMENT_PREFIX}/indexes`, 'Callback: done'], ['indexes']) @@ -95,34 +87,4 @@ tap.test('Collection(Index) Tests', (t) => { }) } ) - - if (semver.satisfies(pkgVersion, '<4')) { - test( - { suiteName: 'dropAllIndexes', agent, t }, - function dropAllIndexesTest(t, collection, verify) { - collection.dropAllIndexes(function done(err, data) { - t.error(err) - t.equal(data, true) - verify(null, [`${STATEMENT_PREFIX}/dropAllIndexes`, 'Callback: done'], ['dropAllIndexes']) - }) - } - ) - - test({ suiteName: 'ensureIndex', agent, t }, function ensureIndexTest(t, collection, verify) { - collection.ensureIndex('i', function done(err, data) { - t.error(err) - t.equal(data, 'i_1') - verify(null, [`${STATEMENT_PREFIX}/ensureIndex`, 'Callback: done'], ['ensureIndex']) - }) - }) - - test({ suiteName: 'reIndex', agent, t }, function reIndexTest(t, collection, verify) { - collection.reIndex(function done(err, data) { - t.error(err) - t.equal(data, true) - - verify(null, [`${STATEMENT_PREFIX}/reIndex`, 'Callback: done'], ['reIndex']) - }) - }) - } }) diff --git a/test/versioned/mongodb-esm/collection-misc.tap.mjs b/test/versioned/mongodb-esm/collection-misc.tap.mjs index 4c47854e40..f6388f151f 100644 --- a/test/versioned/mongodb-esm/collection-misc.tap.mjs +++ b/test/versioned/mongodb-esm/collection-misc.tap.mjs @@ -3,11 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import semver from 'semver' import tap from 'tap' import { test, DB_NAME } from './collection-common.mjs' import helper from '../../lib/agent_helper.js' -import { pkgVersion, STATEMENT_PREFIX, COLLECTIONS } from './common.cjs' +import { STATEMENT_PREFIX, COLLECTIONS } from './common.cjs' function verifyAggregateData(t, data) { t.equal(data.length, 3, 'should have expected amount of results') @@ -26,47 +25,26 @@ tap.test('Collection(Index) Tests', (t) => { helper.unloadAgent(agent) }) - if (semver.satisfies(pkgVersion, '<4')) { - test({ suiteName: 'aggregate', agent, t }, function aggregateTest(t, collection, verify) { - const cursor = collection.aggregate([ - { $sort: { i: 1 } }, - { $match: { mod10: 5 } }, - { $limit: 3 }, - { $project: { value: '$i', _id: 0 } } - ]) - - cursor.toArray(function onResult(err, data) { - verifyAggregateData(t, data) - verify( - err, - [`${STATEMENT_PREFIX}/aggregate`, `${STATEMENT_PREFIX}/toArray`], - ['aggregate', 'toArray'], - { childrenLength: 2, strict: false } - ) - }) - }) - } else { - test( - { suiteName: 'aggregate v4', agent, t }, - async function aggregateTest(t, collection, verify) { - const data = await collection - .aggregate([ - { $sort: { i: 1 } }, - { $match: { mod10: 5 } }, - { $limit: 3 }, - { $project: { value: '$i', _id: 0 } } - ]) - .toArray() - verifyAggregateData(t, data) - verify( - null, - [`${STATEMENT_PREFIX}/aggregate`, `${STATEMENT_PREFIX}/toArray`], - ['aggregate', 'toArray'], - { childrenLength: 2 } - ) - } - ) - } + test( + { suiteName: 'aggregate v4', agent, t }, + async function aggregateTest(t, collection, verify) { + const data = await collection + .aggregate([ + { $sort: { i: 1 } }, + { $match: { mod10: 5 } }, + { $limit: 3 }, + { $project: { value: '$i', _id: 0 } } + ]) + .toArray() + verifyAggregateData(t, data) + verify( + null, + [`${STATEMENT_PREFIX}/aggregate`, `${STATEMENT_PREFIX}/toArray`], + ['aggregate', 'toArray'], + { childrenLength: 2 } + ) + } + ) test({ suiteName: 'bulkWrite', agent, t }, function bulkWriteTest(t, collection, verify) { collection.bulkWrite( @@ -107,39 +85,6 @@ tap.test('Collection(Index) Tests', (t) => { }) }) - if (semver.satisfies(pkgVersion, '<3')) { - test({ suiteName: 'geoNear', agent, t }, function geoNearTest(t, collection, verify) { - collection.ensureIndex({ loc: '2d' }, { bucketSize: 1 }, indexed) - - function indexed(err) { - t.error(err) - collection.geoNear(20, 20, { maxDistance: 5 }, done) - } - - function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - t.equal(data.results.length, 2) - t.equal(data.results[0].obj.i, 21) - t.equal(data.results[1].obj.i, 17) - t.same(data.results[0].obj.loc, [21, 21]) - t.same(data.results[1].obj.loc, [17, 17]) - t.equal(data.results[0].dis, 1.4142135623730951) - t.equal(data.results[1].dis, 4.242640687119285) - verify( - null, - [ - `${STATEMENT_PREFIX}/ensureIndex`, - 'Callback: indexed', - `${STATEMENT_PREFIX}/geoNear`, - 'Callback: done' - ], - ['ensureIndex', 'geoNear'] - ) - } - }) - } - test({ suiteName: 'isCapped', agent, t }, function isCappedTest(t, collection, verify) { collection.isCapped(function done(err, data) { t.error(err) @@ -203,97 +148,6 @@ tap.test('Collection(Index) Tests', (t) => { }) }) - if (semver.satisfies(pkgVersion, '<4')) { - test({ suiteName: 'parallelCollectionScan', agent, t }, function (t, collection, verify) { - collection.parallelCollectionScan({ numCursors: 1 }, function done(err, cursors) { - t.error(err) - - cursors[0].toArray(function toArray(err, items) { - t.error(err) - t.equal(items.length, 30) - - const total = items.reduce(function sum(prev, item) { - return item.i + prev - }, 0) - - t.equal(total, 435) - verify( - null, - [ - `${STATEMENT_PREFIX}/parallelCollectionScan`, - 'Callback: done', - `${STATEMENT_PREFIX}/toArray`, - 'Callback: toArray' - ], - ['parallelCollectionScan', 'toArray'] - ) - }) - }) - }) - - test( - { suiteName: 'geoHaystackSearch', agent, t }, - function haystackSearchTest(t, collection, verify) { - collection.ensureIndex({ loc: 'geoHaystack', type: 1 }, { bucketSize: 1 }, indexed) - - function indexed(err) { - t.error(err) - collection.geoHaystackSearch(15, 15, { maxDistance: 5, search: {} }, done) - } - - function done(err, data) { - t.error(err) - t.equal(data.ok, 1) - t.equal(data.results.length, 2) - t.equal(data.results[0].i, 13) - t.equal(data.results[1].i, 17) - t.same(data.results[0].loc, [13, 13]) - t.same(data.results[1].loc, [17, 17]) - verify( - null, - [ - `${STATEMENT_PREFIX}/ensureIndex`, - 'Callback: indexed', - `${STATEMENT_PREFIX}/geoHaystackSearch`, - 'Callback: done' - ], - ['ensureIndex', 'geoHaystackSearch'] - ) - } - } - ) - - test({ suiteName: 'group', agent, t }, function groupTest(t, collection, verify) { - collection.group(['mod10'], {}, { count: 0, total: 0 }, count, done) - - function done(err, data) { - t.error(err) - t.same(data.sort(sort), [ - { mod10: 0, count: 3, total: 30 }, - { mod10: 1, count: 3, total: 33 }, - { mod10: 2, count: 3, total: 36 }, - { mod10: 3, count: 3, total: 39 }, - { mod10: 4, count: 3, total: 42 }, - { mod10: 5, count: 3, total: 45 }, - { mod10: 6, count: 3, total: 48 }, - { mod10: 7, count: 3, total: 51 }, - { mod10: 8, count: 3, total: 54 }, - { mod10: 9, count: 3, total: 57 } - ]) - verify(null, [`${STATEMENT_PREFIX}/group`, 'Callback: done'], ['group']) - } - - function count(obj, prev) { - prev.total += obj.i - prev.count++ - } - - function sort(a, b) { - return a.mod10 - b.mod10 - } - }) - } - test({ suiteName: 'rename', agent, t }, function renameTest(t, collection, verify) { collection.rename(COLLECTIONS.collection2, function done(err) { t.error(err) diff --git a/test/versioned/mongodb-esm/collection-update.tap.mjs b/test/versioned/mongodb-esm/collection-update.tap.mjs index fbe6594d9b..845ea08f82 100644 --- a/test/versioned/mongodb-esm/collection-update.tap.mjs +++ b/test/versioned/mongodb-esm/collection-update.tap.mjs @@ -3,11 +3,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -import semver from 'semver' import tap from 'tap' import { test } from './collection-common.mjs' import helper from '../../lib/agent_helper.js' -import { pkgVersion, STATEMENT_PREFIX } from './common.cjs' +import { STATEMENT_PREFIX } from './common.cjs' /** * The response from the methods in this file differ between versions @@ -19,22 +18,13 @@ import { pkgVersion, STATEMENT_PREFIX } from './common.cjs' * @param {Number} params.count, optional * @param {string} params.keyPrefix prefix where the count exists * @param {Object} params.extraValues extra fields to assert on >=4.0.0 version of module - * @param {Object} params.legaycValues extra fields to assert on <4.0.0 version of module */ -function assertExpectedResult({ t, data, count, keyPrefix, extraValues, legacyValues }) { - if (semver.satisfies(pkgVersion, '<4')) { - const expectedResult = { ok: 1, ...legacyValues } - if (count) { - expectedResult.n = count - } - t.same(data.result, expectedResult) - } else { - const expectedResult = { acknowledged: true, ...extraValues } - if (count) { - expectedResult[`${keyPrefix}Count`] = count - } - t.same(data, expectedResult) +function assertExpectedResult({ t, data, count, keyPrefix, extraValues }) { + const expectedResult = { acknowledged: true, ...extraValues } + if (count) { + expectedResult[`${keyPrefix}Count`] = count } + t.same(data, expectedResult) } tap.test('Collection(Update) Tests', (t) => { @@ -120,9 +110,6 @@ tap.test('Collection(Update) Tests', (t) => { assertExpectedResult({ t, data, - legacyValues: { - n: 1 - }, extraValues: { insertedId: {} } @@ -154,9 +141,6 @@ tap.test('Collection(Update) Tests', (t) => { data, count: 1, keyPrefix: 'modified', - legacyValues: { - nModified: 1 - }, extraValues: { matchedCount: 1, upsertedCount: 0, @@ -168,17 +152,6 @@ tap.test('Collection(Update) Tests', (t) => { }) }) - if (semver.satisfies(pkgVersion, '<4')) { - test({ suiteName: 'save', agent, t }, function saveTest(t, collection, verify) { - collection.save({ foo: 'bar' }, function done(err, data) { - t.error(err) - t.same(data.result, { ok: 1, n: 1 }) - - verify(null, [`${STATEMENT_PREFIX}/save`, 'Callback: done'], ['save']) - }) - }) - } - test({ suiteName: 'update', agent, t }, function updateTest(t, collection, verify) { collection.update({ i: 5 }, { $set: { foo: 'bar' } }, function done(err, data) { t.error(err) @@ -187,9 +160,6 @@ tap.test('Collection(Update) Tests', (t) => { data, count: 1, keyPrefix: 'modified', - legacyValues: { - nModified: 1 - }, extraValues: { matchedCount: 1, upsertedCount: 0, @@ -209,9 +179,6 @@ tap.test('Collection(Update) Tests', (t) => { data, count: 3, keyPrefix: 'modified', - legacyValues: { - nModified: 3 - }, extraValues: { matchedCount: 3, upsertedCount: 0, @@ -231,9 +198,6 @@ tap.test('Collection(Update) Tests', (t) => { data, count: 1, keyPrefix: 'modified', - legacyValues: { - nModified: 1 - }, extraValues: { matchedCount: 1, upsertedCount: 0, diff --git a/test/versioned/mongodb-esm/common.cjs b/test/versioned/mongodb-esm/common.cjs index a28f7f0afe..487a888507 100644 --- a/test/versioned/mongodb-esm/common.cjs +++ b/test/versioned/mongodb-esm/common.cjs @@ -4,8 +4,9 @@ */ 'use strict' +module.exports = require('../mongodb/common') -const fs = require('fs') +/* const fs = require('fs') const mongoPackage = require('mongodb/package.json') const params = require('../../lib/params') const semver = require('semver') @@ -226,3 +227,4 @@ function getDomainSocketPath() { function getMetrics(agent) { return agent.metrics._metrics } +*/ diff --git a/test/versioned/mongodb-esm/package.json b/test/versioned/mongodb-esm/package.json index 48ab5eb649..d5ac6b5dbf 100644 --- a/test/versioned/mongodb-esm/package.json +++ b/test/versioned/mongodb-esm/package.json @@ -6,11 +6,12 @@ "private": true, "tests": [ { + "comment": "Only tests callback based instrumentation which is only in v4 of mongodb. For promised-based v5+ tests see `test/versioned/mongodb`", "engines": { "node": ">=18" }, "dependencies": { - "mongodb": ">=2.1 < 4.0.0 || >= 4.1.4 < 5" + "mongodb": ">=4.1.4 <5" }, "files": [ "bulk.tap.mjs", diff --git a/test/versioned/mongodb/package.json b/test/versioned/mongodb/package.json index a81df6118d..32855f7195 100644 --- a/test/versioned/mongodb/package.json +++ b/test/versioned/mongodb/package.json @@ -5,6 +5,7 @@ "private": true, "tests": [ { + "comment": "Only tests promise based instrumentation. Callback based instrumentation is tested for v4 of mongodb in `test/version/mongodb-esm` folder", "engines": { "node": ">=18" }, @@ -21,5 +22,8 @@ "db.tap.js" ] } - ] + ], + "engines": { + "node": ">=18" + } } From da71afe42b5018c97bbfb097fd504c36fb0059e2 Mon Sep 17 00:00:00 2001 From: Bob Evans Date: Tue, 23 Jul 2024 15:57:10 -0400 Subject: [PATCH 3/3] test: added unit test for logging warning for unsupported mongodb version --- lib/instrumentation/mongodb.js | 10 ++--- test/unit/instrumentation/mongodb.test.js | 54 +++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 test/unit/instrumentation/mongodb.test.js diff --git a/lib/instrumentation/mongodb.js b/lib/instrumentation/mongodb.js index 0cafb38e1d..1e82f33cff 100644 --- a/lib/instrumentation/mongodb.js +++ b/lib/instrumentation/mongodb.js @@ -32,15 +32,15 @@ function initialize(agent, mongodb, moduleName, shim) { return } - shim.setDatastore(shim.MONGODB) - const mongoVersion = shim.pkgVersion - if (semver.satisfies(mongoVersion, '>=4.0.0')) { - instrumentV4(shim, mongodb) - } else { + if (semver.satisfies(mongoVersion, '<4.0.0')) { shim.logger.warn( 'New Relic Node.js agent no longer supports mongodb < 4, current version %s. Please downgrade to v11 for support, if needed', mongoVersion ) + return } + + shim.setDatastore(shim.MONGODB) + instrumentV4(shim, mongodb) } diff --git a/test/unit/instrumentation/mongodb.test.js b/test/unit/instrumentation/mongodb.test.js new file mode 100644 index 0000000000..66cfc35b83 --- /dev/null +++ b/test/unit/instrumentation/mongodb.test.js @@ -0,0 +1,54 @@ +/* + * Copyright 2020 New Relic Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +'use strict' + +const tap = require('tap') + +const helper = require('../../lib/agent_helper') +const proxyquire = require('proxyquire') +const sinon = require('sinon') + +tap.beforeEach((t) => { + const sandbox = sinon.createSandbox() + t.context.sandbox = sandbox + t.context.agent = helper.loadMockedAgent() + t.context.initialize = proxyquire('../../../lib/instrumentation/mongodb', { + './mongodb/v4-mongo': function stub() {} + }) + const shim = { + setDatastore: sandbox.stub(), + pkgVersion: '4.0.0', + logger: { + warn: sandbox.stub() + } + } + shim.pkgVersion = '4.0.0' + t.context.shim = shim +}) + +tap.afterEach((t) => { + helper.unloadAgent(t.context.agent) + t.context.sandbox.restore() +}) + +tap.test('should not log warning if version is >= 4', function (t) { + const { agent, shim, initialize } = t.context + initialize(agent, {}, 'mongodb', shim) + t.equal(shim.logger.warn.callCount, 0) + t.equal(shim.setDatastore.callCount, 1) + t.end() +}) + +tap.test('should log warning if using unsupported version of mongo', function (t) { + const { agent, shim, initialize } = t.context + shim.pkgVersion = '2.0.0' + initialize(agent, {}, 'mongodb', shim) + t.same(shim.logger.warn.args[0], [ + 'New Relic Node.js agent no longer supports mongodb < 4, current version %s. Please downgrade to v11 for support, if needed', + '2.0.0' + ]) + t.end() +})