From d894e3c5dd89e5fc5e30e091cc8506b1f9765c15 Mon Sep 17 00:00:00 2001 From: Trent Mick Date: Mon, 27 Sep 2021 15:20:34 -0700 Subject: [PATCH] tests: avoid test crash getting @elastic/elasticsearch version (#2351) The tests were using `require('@elastic/elasticsearch/package.json')` which runs afoul of EOL'd folder mappings in "exports" (https://nodejs.org/api/all.html#DEP0148) with current ES client versions and the latest node v17 nightly. Fixes: #2350 --- package.json | 1 + test/_utils.js | 35 ++++++++++++++++++- test/config.test.js | 3 +- .../modules/@elastic/elasticsearch.test.js | 9 ++--- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 1deaf29591b..66ba014d5d4 100644 --- a/package.json +++ b/package.json @@ -162,6 +162,7 @@ "memcached": "^2.2.2", "mimic-response": "^2.1.0", "mkdirp": "^0.5.1", + "module-details-from-path": "^1.0.3", "mongodb": "^4.1.0", "mongodb-core": "^3.2.7", "mysql": "^2.18.1", diff --git a/test/_utils.js b/test/_utils.js index 76292697a3c..f4ace207176 100644 --- a/test/_utils.js +++ b/test/_utils.js @@ -1,5 +1,9 @@ 'use strict' +const fs = require('fs') + +const moduleDetailsFromPath = require('module-details-from-path') + // Lookup the property "str" (given in dot-notation) in the object "obj". // If the property isn't found, then `undefined` is returned. function dottedLookup (obj, str) { @@ -30,7 +34,36 @@ function findObjInArray (arr, key, val) { return result } +// "Safely" get the version of the given package, if possible. Otherwise return +// null. +// +// Here "safely" means avoiding `require("$packageName/package.json")` because +// that can fail if the package uses an old form of "exports" +// (e.g. https://github.com/elastic/apm-agent-nodejs/issues/2350). +function safeGetPackageVersion (packageName) { + let file + try { + file = require.resolve(packageName) + } catch (_err) { + return null + } + + // Use the same logic as require-in-the-middle for finding the 'basedir' of + // the package from `file`. + const details = moduleDetailsFromPath(file) + if (!details) { + return null + } + + try { + return JSON.parse(fs.readFileSync(details.basedir + '/package.json')).version + } catch (_err) { + return null + } +} + module.exports = { dottedLookup, - findObjInArray + findObjInArray, + safeGetPackageVersion } diff --git a/test/config.test.js b/test/config.test.js index 1bdd0b6d696..5b82c044dbf 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -17,6 +17,7 @@ var test = require('tape') const Agent = require('../lib/agent') const { MockAPMServer } = require('./_mock_apm_server') const { NoopTransport } = require('../lib/noop-transport') +const { safeGetPackageVersion } = require('./_utils') var config = require('../lib/config') var Instrumentation = require('../lib/instrumentation') var apmVersion = require('../package').version @@ -860,7 +861,7 @@ usePathAsTransactionNameTests.forEach(function (usePathAsTransactionNameTest) { test('disableInstrumentations', function (t) { var expressGraphqlVersion = require('express-graphql/package.json').version - var esVersion = require('@elastic/elasticsearch/package.json').version + var esVersion = safeGetPackageVersion('@elastic/elasticsearch') // require('apollo-server-core') is a hard crash on nodes < 12.0.0 const apolloServerCoreVersion = require('apollo-server-core/package.json').version diff --git a/test/instrumentation/modules/@elastic/elasticsearch.test.js b/test/instrumentation/modules/@elastic/elasticsearch.test.js index 9b339e17f4a..11403b7bec3 100644 --- a/test/instrumentation/modules/@elastic/elasticsearch.test.js +++ b/test/instrumentation/modules/@elastic/elasticsearch.test.js @@ -10,9 +10,11 @@ const agent = require('../../../..').start({ spanFramesMinDuration: -1 // always capture stack traces with spans }) +const { safeGetPackageVersion } = require('../../../_utils') + // Skip (exit the process) if this package version doesn't support this version // of node. -const esVersion = require('@elastic/elasticsearch/package.json').version +const esVersion = safeGetPackageVersion('@elastic/elasticsearch') const semver = require('semver') if (semver.lt(process.version, '10.0.0') && semver.gte(esVersion, '7.12.0')) { console.log(`# SKIP @elastic/elasticsearch@${esVersion} does not support node ${process.version}`) @@ -34,7 +36,6 @@ const { MockES } = require('./_mock_es') const host = (process.env.ES_HOST || 'localhost') + ':9200' const node = 'http://' + host -const pkgVersion = require('@elastic/elasticsearch/package.json').version test('client.ping with promise', function (t) { resetAgent(checkDataAndEnd(t, 'HEAD', '/', null)) @@ -334,7 +335,7 @@ test('DeserializationError', function (t) { }) }) -if (semver.gte(pkgVersion, '7.14.0')) { +if (semver.gte(esVersion, '7.14.0')) { test('ProductNotSupportedError', function (t) { // Create a mock Elasticsearch server that responds to "GET /" with a body // that triggers ProductNotSupportedError. @@ -377,7 +378,7 @@ if (semver.gte(pkgVersion, '7.14.0')) { }) } -if (semver.gte(pkgVersion, '7.7.0')) { +if (semver.gte(esVersion, '7.7.0')) { // Abort handling was added to @elastic/elasticsearch@7.7.0. test('request.abort() works', function (t) {