Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/test-all-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,6 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Set MySQL variables
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for reviewer: this is required only for testing @opentelemetry/instrumentation-mysql and can be executed as a query using the client. Hence is removed from there and added in plugins/node/opentelemetry-instrumentation-mysql/test/mysql.test.ts

run: mysql --user=root --password=${MYSQL_ROOT_PASSWORD} --host=${MYSQL_HOST} --port=${MYSQL_PORT} -e "SET GLOBAL log_output='TABLE'; SET GLOBAL general_log = 1;" mysql
- name: Install
run: npm ci
- name: Download Build Artifacts
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Set MySQL variables
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for reviewer: same here

run: mysql --user=root --password=${MYSQL_ROOT_PASSWORD} --host=${MYSQL_HOST} --port=${MYSQL_PORT} -e "SET GLOBAL log_output='TABLE'; SET GLOBAL general_log = 1;" mysql
- name: Install
run: npm ci
- name: Download Build Artifacts
Expand Down
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,34 @@ The conventional commit type (in PR title) is very important to automatically bu

There is no need to update the CHANGELOG in a PR because it will be updated as part of the release process (see [RELEASING.md](RELEASING.md) for more details).

### Testing

Most unit tests case be run via:

```sh
npm test
```

However, some instrumentations require test-services to be running (e.g. the `instrumentation-mongodb` package requires a MongoDB server). Use the `test-services`-related npm scripts to start all required services in Docker and then run the tests with the appropriate configuration to use those services:

```sh
npm run test-services:start # starts services in Docker
npm run test:with-services-config # runs 'npm test' with envvars from test/test-services.env
npm run test-services:stop # stops services in Docker
```

If you only want to test a sigle package (e.g. the `instrumentation-mongodb`) you can `cd` into it and run the tests after you started the services.

```sh
npm run test-services:start # starts services in Docker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could optionally be npm run test-services:start mongodb but probably don't need to bother mentioning this. Easier to keep it simple.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm planning to do a follow up PR to add scripts for each package which will use this feature. I'll remember to update this description.

cd plugins/node/opentelemetry-instrumentation-mongodb # get into the instrumenation folder
RUN_MONGODB_TESTS=1 npm test # run the test with the proper config (check each package)
cd ../../.. # go back to root folder
npm run test-services:stop # stops services in Docker
```

NOTE: scripts for each package will be added to avoid extra consumption of resources and improve the development experience.

### Benchmarks

When two or more approaches must be compared, please write a benchmark in the benchmark/index.js module so that we can keep track of the most efficient algorithm.
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"test:browser": "nx run-many -t test:browser",
"test:ci:changed": "nx affected -t test --base=origin/main --head=HEAD",
"test-all-versions": "nx run-many -t test-all-versions",
"test-services:start": "docker compose -f ./test/docker-compose.yaml up -d --wait",
"test-services:stop": "docker compose -f ./test/docker-compose.yaml down",
"test:with-services-config": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=./test/test-services.env npm test",
"changelog": "lerna-changelog",
"lint": "nx run-many -t lint && npm run lint:deps && npm run lint:readme && npm run lint:markdown && npm run lint:semconv-deps",
"lint:fix": "nx run-many -t lint:fix && npm run lint:markdown:fix",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
} from '@opentelemetry/sdk-metrics';
import * as assert from 'assert';
import { MySQLInstrumentation } from '../src';
import * as testUtils from '@opentelemetry/contrib-test-utils';
import { registerInstrumentationTesting } from '@opentelemetry/contrib-test-utils';

const instrumentation = registerInstrumentationTesting(
Expand Down Expand Up @@ -62,9 +61,9 @@ import * as mysqlTypes from 'mysql';
describe('[email protected]', () => {
let otelTestingMeterProvider;
let inMemoryMetricsExporter: InMemoryMetricExporter;
const testMysql = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available
const testMysqlLocally = process.env.RUN_MYSQL_TESTS_LOCAL; // For local: spins up local mysql db via docker
const shouldTest = testMysql || testMysqlLocally; // Skips these tests if false (default)
// assumes local mysql db is already available in CI or
// using `npm run test-services:start` script at the root folder
const shouldTest = process.env.RUN_MYSQL_TESTS;

function initMeterProvider() {
inMemoryMetricsExporter = new InMemoryMetricExporter(
Expand All @@ -90,22 +89,7 @@ describe('[email protected]', () => {
console.log('Skipping test-mysql for metrics.');
this.skip();
}

if (testMysqlLocally) {
testUtils.startDocker('mysql');
// wait 15 seconds for docker container to start
this.timeout(20000);
setTimeout(done, 15000);
} else {
done();
}
});

after(function () {
if (testMysqlLocally) {
this.timeout(5000);
testUtils.cleanUpDocker('mysql');
}
done();
});

describe('#Pool - metrics', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
SEMATTRS_NET_PEER_NAME,
SEMATTRS_NET_PEER_PORT,
} from '@opentelemetry/semantic-conventions';
import * as testUtils from '@opentelemetry/contrib-test-utils';
import {
BasicTracerProvider,
InMemorySpanExporter,
Expand Down Expand Up @@ -54,9 +53,9 @@ describe('[email protected]', () => {
let connection: mysqlTypes.Connection;
let pool: mysqlTypes.Pool;
let poolCluster: mysqlTypes.PoolCluster;
const testMysql = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available
const testMysqlLocally = process.env.RUN_MYSQL_TESTS_LOCAL; // For local: spins up local mysql db via docker
const shouldTest = testMysql || testMysqlLocally; // Skips these tests if false (default)
// assumes local mysql db is already available in CI or
// using `npm run test-services:start` script at the root folder
const shouldTest = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available
const memoryExporter = new InMemorySpanExporter();
const provider = new BasicTracerProvider({
spanProcessors: [new SimpleSpanProcessor(memoryExporter)],
Expand All @@ -68,25 +67,11 @@ describe('[email protected]', () => {
// https://github.com/mochajs/mocha/issues/2683#issuecomment-375629901
this.test!.parent!.pending = true;
this.skip();
}

if (testMysqlLocally) {
testUtils.startDocker('mysql');
// wait 15 seconds for docker container to start
this.timeout(20000);
setTimeout(done, 15000);
} else {
done();
}
});

after(function () {
if (testMysqlLocally) {
this.timeout(5000);
testUtils.cleanUpDocker('mysql');
}
});

beforeEach(() => {
instrumentation.disable();
contextManager = new AsyncLocalStorageContextManager().enable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,28 +64,38 @@ interface Result extends RowDataPacket {
solution: number;
}

describe('mysql2', () => {
const testMysql = process.env.RUN_MYSQL_TESTS; // For CI: assumes local mysql db is already available
const testMysqlLocally = process.env.RUN_MYSQL_TESTS_LOCAL; // For local: spins up local mysql db via docker
const shouldTest = testMysql || testMysqlLocally; // Skips these tests if false (default)

before(function (done) {
if (testMysqlLocally) {
testUtils.startDocker('mysql');
// wait 15 seconds for docker container to start
this.timeout(20000);
setTimeout(done, 15000);
} else {
done();
}
// Helper function to setup the database
const execPromise = (conn: Connection, command: string) => {
return new Promise<void>((res, rej) => {
conn.execute(command, err => {
if (err) rej(err);
else res();
});
});
};

after(function (done) {
if (testMysqlLocally) {
this.timeout(5000);
testUtils.cleanUpDocker('mysql');
describe('mysql2', () => {
// assumes local mysql db is already available in CI or
// using `npm run test-services:start` script at the root folder
const shouldTest = process.env.RUN_MYSQL_TESTS;

before(async function () {
const connection = createConnection({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for reviewer: enabling here the general_log setting instead of doing it in the workflows

port,
user: 'root',
host,
password: rootPassword,
database,
});
try {
await execPromise(connection, "SET GLOBAL log_output='TABLE'");
await execPromise(connection, 'SET GLOBAL general_log = 1');
} catch (execErr) {
console.error('MySQL seup error: ', execErr);
this.skip();
} finally {
connection.end();
}
done();
});

describe('callback API', () => {
Expand Down Expand Up @@ -358,7 +368,9 @@ describe('mysql2', () => {
it('should not add comment by default', done => {
const span = provider.getTracer('default').startSpan('test span');
context.with(trace.setSpan(context.active(), span), () => {
connection.query('SELECT 1+1 as solution', () => {
connection.query('SELECT 1+1 as solution', (e, r) => {
console.log(e);
console.log(r);
const spans = memoryExporter.getFinishedSpans();
assert.strictEqual(spans.length, 1);
getLastQueries(1).then(([query]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const memoryExporter = new InMemorySpanExporter();
const CONFIG = {
user: process.env.POSTGRES_USER || 'postgres',
password: process.env.POSTGRES_PASSWORD || 'postgres',
database: process.env.POSTGRES_DB || 'postgres',
database: process.env.POSTGRES_DB || 'otel_pg_database',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note for reviewer: align the value with the one in workflow services

host: process.env.POSTGRES_HOST || 'localhost',
port: process.env.POSTGRES_PORT
? parseInt(process.env.POSTGRES_PORT, 10)
Expand Down
119 changes: 119 additions & 0 deletions test/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# A `docker compose` config file to run tests services for testing
# `@opentelemetry/instrumentation-*` locally.
#
# Note: This isn't used in CI. CI uses GitHub Actions' `services: ...` for
# defining test services.
#
# Usage:
# npm run test-services:start [services...]
# npm run test-services:stop [services...]

name: opentelemetry-nodejs-test-services

services:
cassandra:
image: cassandra:3
environment:
MAX_HEAP_SIZE: "1G"
HEAP_NEWSIZE: 400m
ports:
- "9042:9042"
healthcheck:
test: ["CMD-SHELL", "[ $$(nodetool statusgossip) = running ]"]
interval: 1s
timeout: 10s
retries: 30

memcached:
image: memcached:1.6.37-alpine
ports:
- 11211:11211
mongodb:
image: mongo:7
ports:
- "27017:27017"
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "--quiet"]
interval: 1s
timeout: 10s
retries: 30

mssql:
# Tags listed at https://hub.docker.com/r/microsoft/mssql-server
# Docs: https://learn.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker
image: mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04
platform: linux/amd64
environment:
- ACCEPT_EULA=Y
- MSSQL_SA_PASSWORD=mssql_passw0rd
ports:
- "1433:1433"
healthcheck:
test: ["CMD", "/opt/mssql-tools18/bin/sqlcmd", "-C", "-S", "mssql", "-U", "sa", "-P", "mssql_passw0rd", "-Q", "select 1"]
interval: 1s
timeout: 10s
retries: 30

mysql:
image: mysql:5.7
# No ARM64 image layer. See https://stackoverflow.com/a/65592942
platform: linux/x86_64
environment:
MYSQL_USER: "otel"
MYSQL_PASSWORD: "secret"
MYSQL_DATABASE: "otel_mysql_database"
MYSQL_ROOT_PASSWORD: "rootpw"
ports:
- "33306:3306"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping"]
interval: 1s
timeout: 10s
retries: 30

oracledb:
image: gvenzl/oracle-free:slim
environment:
APP_USER: "otel"
APP_USER_PASSWORD: "secret"
ORACLE_PASSWORD: "oracle"
ports:
- 1521:1521
healthcheck:
test: ["CMD", "sqlplus" ,"system/oracle@//localhost/FREEPDB1"]
interval: 10s
timeout: 5s
retries: 30
postgres:
# https://github.com/docker-library/docs/blob/master/postgres/README.md#how-to-extend-this-image
image: postgres:16-alpine
ports:
- "54320:5432"
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
POSTGRES_USER: "postgres"
POSTGRES_DB: "otel_pg_database"
POSTGRES_PASSWORD: "postgres"
healthcheck:
test: ["CMD", "pg_isready"]
interval: 1s
timeout: 10s
retries: 30

rabbitmq:
image: rabbitmq:3
environment:
RABBITMQ_DEFAULT_USER: "username"
RABBITMQ_DEFAULT_PASS: "password"
ports:
- "22221:5672"

redis:
image: redis:7
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 10s
retries: 30
35 changes: 35 additions & 0 deletions test/test-services.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
RUN_CASSANDRA_TESTS=1
RUN_MEMCACHED_TESTS=1
RUN_MONGODB_TESTS=1
RUN_MYSQL_TESTS=1
RUN_MSSQL_TESTS=1
RUN_ORACLEDB_TESTS=1
RUN_POSTGRES_TESTS=1
RUN_REDIS_TESTS=1
RUN_RABBIT_TESTS=1
CASSANDRA_HOST=localhost
MONGODB_DB=opentelemetry-tests
MONGODB_HOST=127.0.0.1
MONGODB_PORT=27017
MSSQL_PASSWORD=mssql_passw0rd
MYSQL_DATABASE=otel_mysql_database
MYSQL_HOST=127.0.0.1
MYSQL_PASSWORD=secret
MYSQL_ROOT_PASSWORD=rootpw
MYSQL_PORT=33306
MYSQL_USER=otel
OPENTELEMETRY_MEMCACHED_HOST=localhost
OPENTELEMETRY_MEMCACHED_PORT=11211
OPENTELEMETRY_REDIS_HOST=localhost
OPENTELEMETRY_REDIS_PORT=6379
ORACLE_HOSTNAME=localhost
ORACLE_PORT=1521
ORACLE_CONNECTSTRING=localhost:1521/freepdb1
ORACLE_USER=otel
ORACLE_PASSWORD=secret
ORACLE_SERVICENAME=FREEPDB1
POSTGRES_DB=otel_pg_database
POSTGRES_HOST=localhost
POSTGRES_PORT=54320
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres