-
Notifications
You must be signed in to change notification settings - Fork 39
test: added esm test for tedious #2253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1b3c2df
92c7f49
5bf702f
faea90f
ed27116
0906e2e
941a3f4
86abdbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,15 +14,19 @@ process.on('SIGTERM', () => { | |
| require('@instana/collector')(); | ||
| const express = require('express'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const { isCI } = require('@instana/core/test/test_util'); | ||
| const port = require('../../test_util/app-port')(); | ||
|
|
||
| // collector -> typeorm -> mssql v10 -> tedious v16 | ||
| // We cant install typeorm on root because we have mssql v11 installed on root. | ||
| // If we require tedious here, it will load the dependency from the | ||
| // node_modules folder of the collector package. | ||
| // TODO: https://jsw.ibm.com/browse/INSTA-7722 | ||
| const tedious = require('../../../../../node_modules/tedious'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I auto-resolved this. We have to ensure we are using the right Tedious instance. |
||
| const tedious = require('tedious'); | ||
|
|
||
| const tediousPath = require.resolve('tedious'); | ||
| const expectedLocalPath = path.resolve(__dirname, 'node_modules', 'tedious'); | ||
| if (!tediousPath.includes(expectedLocalPath)) { | ||
| throw new Error( | ||
| // eslint-disable-next-line max-len | ||
| `tedious must be loaded from local node_modules. Expected path containing: ${expectedLocalPath}, but got: ${tediousPath}` | ||
| ); | ||
| } | ||
|
|
||
| const Connection = tedious.Connection; | ||
| const Request = tedious.Request; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| /* | ||
| * (c) Copyright IBM Corp. 2025 | ||
| */ | ||
|
|
||
| /* eslint-disable no-console */ | ||
|
|
||
| // NOTE: c8 bug https://github.com/bcoe/c8/issues/166 | ||
| process.on('SIGTERM', () => { | ||
| process.disconnect(); | ||
| process.exit(0); | ||
| }); | ||
|
|
||
| import express from 'express'; | ||
| import fs from 'fs'; | ||
| import bodyParser from 'body-parser'; | ||
| import { createRequire } from 'module'; | ||
| import { fileURLToPath } from 'url'; | ||
| import { dirname, resolve } from 'path'; | ||
| import testUtil from '../../../../core/test/test_util/index.js'; | ||
| import getAppPort from '../../test_util/app-port.js'; | ||
| const port = getAppPort(); | ||
| const isCI = testUtil.isCI; | ||
| import tedious from 'tedious'; | ||
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = dirname(__filename); | ||
| const require = createRequire(import.meta.url); | ||
| const tediousPath = require.resolve('tedious'); | ||
| const expectedLocalPath = resolve(__dirname, 'node_modules', 'tedious'); | ||
| if (!tediousPath.includes(expectedLocalPath)) { | ||
| throw new Error( | ||
| `tedious must be loaded from local node_modules. Expected path containing: ${expectedLocalPath}, but got: ${tediousPath}` | ||
| ); | ||
| } | ||
|
|
||
| const Connection = tedious.Connection; | ||
| const Request = tedious.Request; | ||
| const app = express(); | ||
|
|
||
| app.use(bodyParser.json()); | ||
|
|
||
| // Locally: | ||
| // To obtain the credentials for the Azure SQL Database, you can find them in 1password. Search for | ||
| // "Team Node.js: Azure SQL credentials", download the file and copy this to your CMD line: | ||
| // export AZURE_SQL_CONFIG=~/Downloads/nodejs-tracer-azure-sql-server.json | ||
| if (!isCI() && !process.env.AZURE_SQL_CONFIG) { | ||
| throw new Error('Please set the env variable `AZURE_SQL_CONFIG`.'); | ||
| } | ||
|
|
||
| const azureConfig = process.env.AZURE_SQL_CONFIG | ||
| ? JSON.parse(fs.readFileSync(process.env.AZURE_SQL_CONFIG, 'utf-8')) | ||
| : null; | ||
|
|
||
| const config = { | ||
| server: azureConfig?.AZURE_SQL_SERVER || process.env.AZURE_SQL_SERVER, | ||
| authentication: { | ||
| type: 'default', | ||
| options: { | ||
| userName: azureConfig?.AZURE_SQL_USERNAME || process.env.AZURE_SQL_USERNAME, | ||
| password: azureConfig?.AZURE_SQL_PWD || process.env.AZURE_SQL_PWD | ||
| } | ||
| }, | ||
| options: { | ||
| database: azureConfig?.AZURE_SQL_DATABASE || process.env.AZURE_SQL_DATABASE, | ||
| connectTimeout: 30000 | ||
| } | ||
| }; | ||
|
|
||
| let connected = false; | ||
| let connection; | ||
|
|
||
| const retryDelay = 30000; | ||
| const maxRetries = 2; | ||
| let currentRetry = 0; | ||
|
|
||
| (function connectWithRetry() { | ||
| if (connection) { | ||
| connection.close(); | ||
| } | ||
| connection = new Connection(config); | ||
| connection.connect(); | ||
|
|
||
| connection.on('connect', err => { | ||
| if (err) { | ||
| console.warn('Connection error', err); | ||
| if (currentRetry < maxRetries) { | ||
| currentRetry++; | ||
| console.warn(`Retrying connection after ${retryDelay} ms (Retry ${currentRetry}/${maxRetries})`); | ||
| setTimeout(connectWithRetry, retryDelay); | ||
| } else { | ||
| console.error('Maximum retries reached. Unable to establish a connection.'); | ||
| connection.close(); | ||
| } | ||
| } else { | ||
| connected = true; | ||
| console.warn('Connected to the database'); | ||
| } | ||
| }); | ||
| })(); | ||
|
|
||
| const executeStatement = (query, isBatch, res) => { | ||
| const request = new Request(query, error => { | ||
| if (error) { | ||
| console.error('Error on executeStatement.', error); | ||
| res.status(500).send('Internal Server Error'); | ||
| } | ||
| }); | ||
|
|
||
| request.on('requestCompleted', () => { | ||
| res.send('OK'); | ||
| }); | ||
|
|
||
| if (isBatch) { | ||
| connection.execSqlBatch(request); | ||
| } else { | ||
| connection.execSql(request); | ||
| } | ||
| }; | ||
|
|
||
| app.get('/', (req, res) => { | ||
| if (!connected) { | ||
| res.sendStatus(500); | ||
| } else { | ||
| res.sendStatus(200); | ||
| } | ||
| }); | ||
|
|
||
| app.get('/packages', (req, res) => { | ||
| const query = 'SELECT * FROM packages'; | ||
| executeStatement(query, false, res); | ||
| }); | ||
|
|
||
| app.delete('/packages', (req, res) => { | ||
| const id = 11; | ||
| const query = `DELETE FROM packages WHERE id = ${id}`; | ||
| executeStatement(query, false, res); | ||
| }); | ||
|
|
||
| app.post('/packages/batch', (req, res) => { | ||
| const batchQuery = ` | ||
| INSERT INTO packages (id, name, version) VALUES (11, 'BatchPackage1', 1); | ||
| INSERT INTO packages (id, name, version) VALUES (11, 'BatchPackage2', 2); | ||
| `; | ||
| executeStatement(batchQuery, true, res); | ||
| }); | ||
| app.listen(port, () => { | ||
| // eslint-disable-next-line no-console | ||
| console.warn(`Listening on port: ${port}`); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,9 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| return; | ||
| } | ||
|
|
||
| execSync('rm -rf package-lock.json', { cwd: __dirname, stdio: 'inherit' }); | ||
| execSync('rm -rf package.json', { cwd: __dirname, stdio: 'inherit' }); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both files in gitignore. |
||
| execSync('rm -rf node_modules', { cwd: __dirname, stdio: 'inherit' }); | ||
| execSync('./preinstall.sh', { cwd: __dirname, stdio: 'inherit' }); | ||
| }); | ||
|
|
||
|
|
@@ -53,18 +56,35 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| if (process.env.INSTANA_TEST_SKIP_INSTALLING_DEPS === 'true') { | ||
| return; | ||
| } | ||
| execSync('npm install --no-save --no-package-lock --prefix ./ ./core.tgz', { | ||
|
|
||
| execSync('npm install --save --prefix ./ ./core.tgz', { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI if we dont use --save, multiple execSync commands will remove previous installations. Using package.json with save + gitignore. |
||
| cwd: __dirname, | ||
| stdio: 'inherit' | ||
| }); | ||
|
|
||
| execSync('npm install --save --prefix ./ ./collector.tgz', { | ||
| cwd: __dirname, | ||
| stdio: 'inherit' | ||
| }); | ||
|
|
||
| execSync('npm install --save --prefix ./ @opentelemetry/api@1.9.0', { | ||
| cwd: __dirname, | ||
| stdio: 'inherit' | ||
| }); | ||
|
|
||
| execSync('npm install --no-save --no-package-lock --prefix ./ ./collector.tgz', { | ||
| execSync('npm install --save --prefix ./ "@opentelemetry/api-v1.3.0@npm:@opentelemetry/api@1.3.0"', { | ||
| cwd: __dirname, | ||
| stdio: 'inherit' | ||
| }); | ||
| }); | ||
|
|
||
| // TODO: Restify test is broken in v24. See Issue: https://github.com/restify/node-restify/issues/1984 | ||
| const restifyTest = semver.gte(process.versions.node, '24.0.0') ? describe.skip : describe; | ||
| let restifyTest = semver.gte(process.versions.node, '24.0.0') ? describe.skip : describe; | ||
|
|
||
| if (process.env.RUN_ESM === 'true') { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to manually skip them because currently we don't have a strategy when multiple describes/apps are in one test file and some of them have esm support and some not. Just skipping them manually for now (not ideal). |
||
| restifyTest = describe.skip; | ||
| } | ||
|
|
||
| restifyTest('restify', function () { | ||
| describe('opentelemetry is enabled', function () { | ||
| globalAgent.setUpCleanUpHooks(); | ||
|
|
@@ -275,7 +295,12 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| }); | ||
| }); | ||
|
|
||
| describe('fs', function () { | ||
| let runFs = describe; | ||
| if (process.env.RUN_ESM === 'true') { | ||
| runFs = describe.skip; | ||
| } | ||
|
|
||
| runFs('fs', function () { | ||
| globalAgent.setUpCleanUpHooks(); | ||
| const agentControls = globalAgent.instance; | ||
|
|
||
|
|
@@ -396,7 +421,12 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| .then(() => retry(() => agentControls.getSpans().then(spans => expect(spans).to.be.empty)))); | ||
| }); | ||
|
|
||
| describe('socket.io', function () { | ||
| let runSocketIo = describe; | ||
| if (process.env.RUN_ESM === 'true') { | ||
| runSocketIo = describe.skip; | ||
| } | ||
|
|
||
| runSocketIo('socket.io', function () { | ||
| globalAgent.setUpCleanUpHooks(); | ||
| const agentControls = globalAgent.instance; | ||
| let socketIOServerPort; | ||
|
|
@@ -567,10 +597,20 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| this.timeout(1000 * 60 * 2); | ||
|
|
||
| before(async () => { | ||
| if (process.env.INSTANA_TEST_SKIP_INSTALLING_DEPS !== 'true') { | ||
| const rootPackageJson = require('../../../../../package.json'); | ||
| const tediousVersion = rootPackageJson.devDependencies.tedious; | ||
| execSync(`npm i "tedious@${tediousVersion}" --prefix ./ --save`, { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Manually installing tedious into our otel test application space. Full production simulation. No more require tedious from root. |
||
| cwd: __dirname, | ||
| stdio: 'inherit' | ||
| }); | ||
| } | ||
|
|
||
| controls = new ProcessControls({ | ||
| appPath: path.join(__dirname, './tedious-app'), | ||
| useGlobalAgent: true, | ||
| cwd: __dirname, | ||
| esmLoaderPath: path.join(__dirname, 'node_modules', '@instana', 'collector', 'esm-register.mjs'), | ||
| enableOtelIntegration: true, | ||
| env: { | ||
| OTEL_API_VERSION: version | ||
|
|
@@ -700,7 +740,12 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| }); | ||
| }); | ||
|
|
||
| describe('OracleDB', function () { | ||
| let runOracleDb = describe; | ||
| if (process.env.RUN_ESM === 'true') { | ||
| runOracleDb = describe.skip; | ||
| } | ||
|
|
||
| runOracleDb('OracleDB', function () { | ||
| this.timeout(1000 * 60); | ||
|
|
||
| describe('opentelemetry is enabled', function () { | ||
|
|
@@ -836,12 +881,18 @@ mochaSuiteFn('opentelemetry tests', function () { | |
| }); | ||
| }); | ||
|
|
||
| mochaSuiteFn('when otel sdk and instana is enabled', function () { | ||
| let runOtelSdkAndInstana = mochaSuiteFn; | ||
| if (process.env.RUN_ESM === 'true') { | ||
| runOtelSdkAndInstana = describe.skip; | ||
| } | ||
|
|
||
| runOtelSdkAndInstana('when otel sdk and instana is enabled', function () { | ||
| this.timeout(config.getTestTimeout() * 4); | ||
| before(async () => { | ||
| if (process.env.INSTANA_TEST_SKIP_INSTALLING_DEPS === 'true') { | ||
| return; | ||
| } | ||
|
|
||
| execSync('rm -rf ./otel-sdk-and-instana/node_modules', { cwd: __dirname, stdio: 'inherit' }); | ||
| execSync('npm install --no-save --no-package-lock', { | ||
| cwd: path.join(__dirname, './otel-sdk-and-instana'), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otel integration has its complete own testing space (we dont use anything from outside). Offering a way to specify the esm handler inside the otel app space.