Skip to content

Commit

Permalink
test: add 'test-services' system for running tests locally with requi…
Browse files Browse the repository at this point in the history
…site services in Docker

tl;dr:
    npm run test-services:start     # starts services in Docker
    npm run test:with-test-services # runs 'npm test' with envvars from test/test-services.env
    npm run test-services:stop      # stops Docker containers

Closes: open-telemetry#2038
  • Loading branch information
trentm committed May 16, 2024
1 parent 0bec64e commit ae4886e
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 52 deletions.
20 changes: 20 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,26 @@ 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 some test-services to be running (e.g. a MongoDB server to test the `instrumentation-mongodb` package). Use the `test-services`-related npm scripts to start test services in Docker and to run the tests with the appropriate configuration to use them:

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

This set of commands works in the top-level directory to test all packages, or
in a specific package directory that requires a test service (e.g. `plugins/node/opentelemetry-instrumentation-mongodb`).


### 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
33 changes: 26 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
"test:ci:changed": "lerna run test --since origin/main",
"test:browser": "lerna run test:browser --concurrency 1",
"test-all-versions": "npm run --if-present --workspaces 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-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=./test/test-services.env npm test",
"bump": "lerna publish",
"changelog": "lerna-changelog",
"lint": "lerna run lint",
Expand All @@ -41,6 +44,7 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "5.8.1",
"@typescript-eslint/parser": "5.8.1",
"dotenv": "^16.4.5",
"eslint": "8.7.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "8.8.0",
Expand Down
1 change: 0 additions & 1 deletion packages/opentelemetry-test-utils/src/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ const dockerRunCmds = {
'docker run --rm -d --name otel-mysql -p 33306:3306 -e MYSQL_ROOT_PASSWORD=rootpw -e MYSQL_DATABASE=test_db -e MYSQL_USER=otel -e MYSQL_PASSWORD=secret mysql:5.7 --log_output=TABLE --general_log=ON',
postgres:
'docker run --rm -d --name otel-postgres -p 54320:5432 -e POSTGRES_PASSWORD=postgres postgres:16-alpine',
redis: 'docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine',
};

export function startDocker(db: keyof typeof dockerRunCmds) {
Expand Down
5 changes: 4 additions & 1 deletion plugins/node/instrumentation-mongoose/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js-contrib",
"scripts": {
"docker:start": "docker run -e MONGODB_DB=opentelemetry-tests -e MONGODB_PORT=27017 -e MONGODB_HOST=127.0.0.1 -p 27017:27017 --rm mongo",
"test": "ts-mocha -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/**/*.test.ts'",
"test-all-versions": "tav",
"test-services:start": "cd ../../.. && npm run test-services:start mongo",
"test-services:stop": "cd ../../.. && npm run test-services:stop mongo",
"test:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm test",
"test-all-versions:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm run test-all-versions",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"lint": "eslint . --ext .ts",
Expand Down
5 changes: 5 additions & 0 deletions plugins/node/instrumentation-mongoose/test/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ export const MONGO_HOST = process.env.MONGODB_HOST || 'localhost';
export const MONGO_PORT = Number(process.env.MONGODB_PORT || 27017);

export const MONGO_URI = `mongodb://${MONGO_HOST}/${MONGO_PORT}`;

export const shouldTest = process.env.RUN_MONGODB_TESTS != null;
if (!shouldTest) {
console.log('Skipping mongodb tests. Set RUN_MONGODB_TESTS=1 to run them.');
}
17 changes: 14 additions & 3 deletions plugins/node/instrumentation-mongoose/test/mongoose.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ const instrumentation = registerInstrumentationTesting(
import * as mongoose from 'mongoose';
import User, { IUser, loadUsers } from './user';
import { assertSpan, getStatement } from './asserts';
import { DB_NAME, MONGO_URI } from './config';
import { shouldTest, DB_NAME, MONGO_URI } from './config';

// Please run mongodb in the background: docker run -d -p 27017:27017 -v ~/data:/data/db mongo
describe('mongoose instrumentation', () => {
before(async () => {
if (!shouldTest) {
return;
}
try {
await mongoose.connect(MONGO_URI, {
useNewUrlParser: true,
Expand All @@ -63,7 +65,13 @@ describe('mongoose instrumentation', () => {
await mongoose.connection.close();
});

beforeEach(async () => {
beforeEach(async function mongooseBeforeEach() {
// Skipping all tests in beforeEach() is a workaround. Mocha does not work
// properly when skipping tests in before() on nested describe() calls.
// https://github.com/mochajs/mocha/issues/2819
if (!shouldTest) {
this.skip();
}
instrumentation.disable();
instrumentation.setConfig({
dbStatementSerializer: (_operation: string, payload) =>
Expand All @@ -75,6 +83,9 @@ describe('mongoose instrumentation', () => {
});

afterEach(async () => {
if (!shouldTest) {
return;
}
instrumentation.disable();
await User.collection.drop().catch();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
"repository": "open-telemetry/opentelemetry-js-contrib",
"scripts": {
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/**/*.test.ts'",
"test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test",
"test-services:start": "cd ../../.. && npm run test-services:start redis",
"test-services:stop": "cd ../../.. && npm run test-services:stop redis",
"test:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm test",
"test:debug": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/**/*.test.ts'",
"test-all-versions": "tav",
"test-all-versions:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test-all-versions",
"test-all-versions:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm run test-all-versions",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"lint": "eslint . --ext .ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
"types": "build/src/index.d.ts",
"repository": "open-telemetry/opentelemetry-js-contrib",
"scripts": {
"docker:start": "docker run -e MONGODB_DB=opentelemetry-tests -e MONGODB_PORT=27017 -e MONGODB_HOST=127.0.0.1 -p 27017:27017 --rm mongo",
"test": "npm run test-v5-v6",
"test-v3": "nyc ts-mocha -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/**/mongodb-v3.test.ts'",
"test-v4": "nyc ts-mocha -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v4.test.ts'",
"test-v5-v6": "nyc ts-mocha -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/mongodb-v4-v5-v6.metrics.test.ts' 'test/**/mongodb-v5-v6.test.ts'",
"test-all-versions": "tav",
"test-services:start": "cd ../../.. && npm run test-services:start mongo",
"test-services:stop": "cd ../../.. && npm run test-services:stop mongo",
"test:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm test",
"test-all-versions:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm run test-all-versions",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"lint": "eslint . --ext .ts",
Expand Down
10 changes: 5 additions & 5 deletions plugins/node/opentelemetry-instrumentation-redis-4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
"repository": "open-telemetry/opentelemetry-js-contrib",
"scripts": {
"test": "nyc ts-mocha -p tsconfig.json --require '@opentelemetry/contrib-test-utils' 'test/redis.test.ts'",
"test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/redis.test.ts'",
"test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test",
"test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine",
"test:docker:stop": "docker stop otel-redis",
"test-services:start": "cd ../../.. && npm run test-services:start redis",
"test-services:stop": "cd ../../.. && npm run test-services:stop redis",
"test:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm test",
"test:debug": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/redis.test.ts'",
"test-all-versions": "tav",
"test-all-versions:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test-all-versions",
"test-all-versions:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm run test-all-versions",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"lint": "eslint . --ext .ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ import {
redisTestConfig,
redisTestUrl,
shouldTest,
shouldTestLocal,
} from './utils';
import * as testUtils from '@opentelemetry/contrib-test-utils';

const instrumentation = registerInstrumentationTesting(
new RedisInstrumentation()
Expand Down Expand Up @@ -61,16 +59,6 @@ describe('redis@^4.0.0', () => {
this.test!.parent!.pending = true;
this.skip();
}

if (shouldTestLocal) {
testUtils.startDocker('redis');
}
});

after(() => {
if (shouldTestLocal) {
testUtils.cleanUpDocker('redis');
}
});

let client: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@ export const redisTestConfig = {

export const redisTestUrl = `redis://${redisTestConfig.host}:${redisTestConfig.port}`;

export const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL;
export const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal;
export const shouldTest = process.env.RUN_REDIS_TESTS;
10 changes: 5 additions & 5 deletions plugins/node/opentelemetry-instrumentation-redis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
"repository": "open-telemetry/opentelemetry-js-contrib",
"scripts": {
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"test:debug": "cross-env RUN_REDIS_TESTS_LOCAL=true ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/**/*.test.ts'",
"test:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test",
"test:docker:run": "docker run --rm -d --name otel-redis -p 63790:6379 redis:alpine",
"test:docker:stop": "docker stop otel-redis",
"test-services:start": "cd ../../.. && npm run test-services:start redis",
"test-services:stop": "cd ../../.. && npm run test-services:stop redis",
"test:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm test",
"test:debug": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env ts-mocha --inspect-brk --no-timeouts -p tsconfig.json 'test/redis.test.ts'",
"test-all-versions": "tav",
"test-all-versions:local": "cross-env RUN_REDIS_TESTS_LOCAL=true npm run test-all-versions",
"test-all-versions:with-test-services": "NODE_OPTIONS='-r dotenv/config' DOTENV_CONFIG_PATH=../../../test/test-services.env npm run test-all-versions",
"tdd": "npm run test -- --watch-extensions ts --watch",
"clean": "rimraf build/*",
"lint": "eslint . --ext .ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ describe('redis@2.x', () => {
const provider = new NodeTracerProvider();
const tracer = provider.getTracer('external');
let redis: typeof redisTypes;
const shouldTestLocal = process.env.RUN_REDIS_TESTS_LOCAL;
const shouldTest = process.env.RUN_REDIS_TESTS || shouldTestLocal;
const shouldTest = process.env.RUN_REDIS_TESTS;

let contextManager: AsyncHooksContextManager;
beforeEach(() => {
Expand All @@ -93,22 +92,12 @@ describe('redis@2.x', () => {
this.skip();
}

if (shouldTestLocal) {
testUtils.startDocker('redis');
}

redis = require('redis');
provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
instrumentation.setTracerProvider(provider);
instrumentation.enable();
});

after(() => {
if (shouldTestLocal) {
testUtils.cleanUpDocker('redis');
}
});

describe('#createClient()', () => {
it('should propagate the current span to event handlers', done => {
const span = tracer.startSpan('test span');
Expand Down
33 changes: 33 additions & 0 deletions test/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# A `docker compose` config file to run services required for testing some
# packages.
#
# Note: This isn't used in CI. CI uses GitHub Actions' `services: ...` for
# defining test services.
#
# Usage:
# npm run test-services:start [SERVICE ...]
# npm run test:with-test-services # runs test with 'test-services.env' envvars
# npm run test-services:stop [SERVICE ...]

name: oteljs-test-services

services:
redis:
image: redis:7
ports:
- "63790:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 1s
timeout: 10s
retries: 30

mongo:
image: mongo:7
ports:
- "27017:27017"
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "--quiet"]
interval: 1s
timeout: 10s
retries: 30
8 changes: 8 additions & 0 deletions test/test-services.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RUN_REDIS_TESTS=1
OPENTELEMETRY_REDIS_HOST=localhost
OPENTELEMETRY_REDIS_PORT=63790

RUN_MONGODB_TESTS: 1
MONGODB_DB: opentelemetry-tests
MONGODB_HOST: 127.0.0.1
MONGODB_PORT: 27017

0 comments on commit ae4886e

Please sign in to comment.