Skip to content
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

add tests to detect memory leaks #225

Merged
merged 5 commits into from
Aug 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
75 changes: 46 additions & 29 deletions .circleci/config.yml
@@ -1,8 +1,45 @@
version: 2
docker-base: &docker-base
docker:
- image: node:8
- &postgres
image: postgres:9.5
- &mysql
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_PASSWORD=userpass
- MYSQL_USER=user
- MYSQL_DATABASE=db
- &redis
image: redis:4.0-alpine
- &mongo
image: mongo:3.6
- &elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4
- &rabbitmq
image: rabbitmq:3.6-alpine
build-node-base: &node-base
<<: *docker-base
working_directory: ~/dd-trace-js
steps:
- checkout
- run:
name: Versions
command: npm version
- run:
name: Install dependencies
command: npm install
- run:
name: Test
command: npm test
- run:
name: Benchmark
command: npm run bench
jobs:
lint:
docker:
- image: node:alpine
- image: node
working_directory: ~/dd-trace-js
steps:
- checkout
Expand All @@ -15,26 +52,8 @@ jobs:
- run:
name: Lint
command: npm run lint
build-node-base: &node-base
docker:
- image: node:alpine
- &postgres
image: postgres:9.5
- &mysql
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=rootpass
- MYSQL_PASSWORD=userpass
- MYSQL_USER=user
- MYSQL_DATABASE=db
- &redis
image: redis:4.0-alpine
- &mongo
image: mongo:3.6
- &elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4
- &rabbitmq
image: rabbitmq:3.6-alpine
test-memory-leaks:
<<: *docker-base
working_directory: ~/dd-trace-js
steps:
- checkout
Expand All @@ -46,14 +65,11 @@ jobs:
command: npm install
- run:
name: Test
command: npm test
- run:
name: Benchmark
command: npm run bench
command: npm run leak
build-node-4:
<<: *node-base
docker:
- image: node:4-alpine
- image: node:4
- *postgres
- *mysql
- *redis
Expand All @@ -63,7 +79,7 @@ jobs:
build-node-6:
<<: *node-base
docker:
- image: node:6-alpine
- image: node:6
- *postgres
- *mysql
- *redis
Expand All @@ -73,7 +89,7 @@ jobs:
build-node-8:
<<: *node-base
docker:
- image: node:8-alpine
- image: node:8
- *postgres
- *mysql
- *redis
Expand All @@ -83,7 +99,7 @@ jobs:
build-node-latest:
<<: *node-base
docker:
- image: node:alpine
- image: node
- *postgres
- *mysql
- *redis
Expand All @@ -96,6 +112,7 @@ workflows:
build:
jobs:
- lint
- test-memory-leaks
- build-node-4
- build-node-6
- build-node-8
Expand Down
2 changes: 2 additions & 0 deletions LICENSE-3rdparty.csv
Expand Up @@ -16,6 +16,7 @@ require,require-in-the-middle,MIT,Copyright 2016-2018 Thomas Watson Steen
require,safe-buffer,MIT,Copyright Feross Aboukhadijeh
require,shimmer,BSD-2-Clause,Copyright Forrest L Norvell
require,url-parse,MIT,Copyright 2015 Unshift.io Arnout Kazemier the Contributors
dev,@airbnb/node-memwatch,WTFPL,Copyright Lloyd Hilaiel
dev,amqplib,MIT,Copyright 2013-2014 Michael Bridgen
dev,axios,MIT,Copyright 2014-present Matt Zabriskie
dev,benchmark,MIT,Copyright 2010-2016 Mathias Bynens Robert Kieffer John-David Dalton
Expand Down Expand Up @@ -49,3 +50,4 @@ dev,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
dev,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
dev,tape,MIT,Copyright James Halliday
13 changes: 13 additions & 0 deletions README.md
Expand Up @@ -40,6 +40,8 @@ docker-compose configuration:
$ docker-compose up -d
```

#### Unit Tests

To run the unit tests, use:

```sh
Expand All @@ -52,6 +54,16 @@ To run the unit tests continuously in watch mode while developing, use:
$ npm run tdd
```

#### Memory Leaks

To run the memory leak tests, use:

```sh
$ npm run leak
```

Please note that memory leak tests only run on Node `>=8`.

### Linting

We use [ESLint](https://eslint.org) to make sure that new code is
Expand All @@ -73,6 +85,7 @@ After installing the `circleci` CLI, simply run one of the following:

```sh
$ circleci build --job lint
$ circleci build --job test-memory-leaks
$ circleci build --job build-node-4
$ circleci build --job build-node-6
$ circleci build --job build-node-8
Expand Down
9 changes: 7 additions & 2 deletions package.json
Expand Up @@ -9,7 +9,8 @@
"jsdoc:watch": "gulp jsdoc:watch",
"lint": "eslint . && node scripts/check_licenses.js",
"tdd": "mocha --watch",
"test": "nyc --reporter text --reporter lcov mocha 'test/**/*.spec.js'"
"test": "nyc --reporter text --reporter lcov mocha 'test/**/*.spec.js'",
"leak": "node --no-warnings ./node_modules/.bin/tape 'test/leak/**/*.js'"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -83,6 +84,10 @@
"redis": "^2.8.0",
"retry": "^0.10.1",
"sinon": "^4.2.1",
"sinon-chai": "^2.14.0"
"sinon-chai": "^2.14.0",
"tape": "^4.9.1"
},
"optionalDependencies": {
"@airbnb/node-memwatch": "^1.0.2"
}
}
1 change: 1 addition & 0 deletions scripts/check_licenses.js
Expand Up @@ -8,6 +8,7 @@ const pkg = require(path.join(__dirname, '..', '/package.json'))
const filePath = path.join(__dirname, '..', '/LICENSE-3rdparty.csv')
const deps = Object.keys(pkg.dependencies)
.concat(Object.keys(pkg.devDependencies))
.concat(Object.keys(pkg.optionalDependencies))
.sort()

let index = 0
Expand Down
40 changes: 40 additions & 0 deletions test/leak/plugins/amqplib.js
@@ -0,0 +1,40 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('amqplib')

const test = require('tape')
const profile = require('../../profile')

test('amqplib plugin should not leak when using callbacks', t => {
require('amqplib/callback_api')
.connect((err, conn) => {
if (err) return t.fail(err)

conn.createChannel((err, ch) => {
if (err) return t.fail(err)

profile(t, operation).then(() => conn.close())

function operation (done) {
ch.assertQueue('test', {}, done)
}
})
})
})

test('amqplib plugin should not leak when using promises', t => {
require('amqplib').connect()
.then(conn => {
return conn.createChannel()
.then(ch => {
profile(t, operation).then(() => conn.close())

function operation (done) {
ch.assertQueue('test', {}).then(done)
}
})
})
.catch(t.fail)
})
25 changes: 25 additions & 0 deletions test/leak/plugins/graphql.js
@@ -0,0 +1,25 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('graphql')

const test = require('tape')
const graphql = require('graphql')
const profile = require('../../profile')

test('graphql plugin should not leak', t => {
const schema = graphql.buildSchema(`
type Query {
hello: String
}
`)

const source = `{ hello }`

profile(t, operation)

function operation (done) {
graphql.graphql(schema, source).then(done)
}
})
29 changes: 29 additions & 0 deletions test/leak/plugins/mongodb-core.js
@@ -0,0 +1,29 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('mongodb-core')

const test = require('tape')
const mongo = require('mongodb-core')
const profile = require('../../profile')

test('mongodb-core plugin should not leak', t => {
const server = new mongo.Server({
host: 'localhost',
port: 27017,
reconnect: false
})

server.on('connect', () => {
profile(t, operation).then(() => server.destroy())
})

server.on('error', t.fail)

server.connect()

function operation (done) {
server.insert(`test.1234`, [{ a: 1 }], {}, done)
}
})
28 changes: 28 additions & 0 deletions test/leak/plugins/mysql.js
@@ -0,0 +1,28 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('mysql')

const test = require('tape')
const mysql = require('mysql')
const profile = require('../../profile')

test('mysql plugin should not leak', t => {
const connection = mysql.createConnection({
host: 'localhost',
user: 'user',
password: 'userpass',
database: 'db'
})

connection.connect(err => {
if (err) return t.fail(err)

profile(t, operation).then(() => connection.end())
})

function operation (done) {
connection.query('SELECT 1 + 1 AS solution', done)
}
})
28 changes: 28 additions & 0 deletions test/leak/plugins/mysql2.js
@@ -0,0 +1,28 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('mysql2')

const test = require('tape')
const mysql2 = require('mysql2')
const profile = require('../../profile')

test('mysql2 plugin should not leak', t => {
const connection = mysql2.createConnection({
host: 'localhost',
user: 'user',
password: 'userpass',
database: 'db'
})

connection.connect(err => {
if (err) return t.fail(err)

profile(t, operation).then(() => connection.end())
})

function operation (done) {
connection.query('SELECT 1 + 1 AS solution', done)
}
})
28 changes: 28 additions & 0 deletions test/leak/plugins/pg.js
@@ -0,0 +1,28 @@
'use strict'

require('../../..')
.init({ plugins: false, sampleRate: 0 })
.use('pg')

const test = require('tape')
const pg = require('pg')
const profile = require('../../profile')

test('pg plugin should not leak', t => {
const client = new pg.Client({
user: 'postgres',
password: 'postgres',
database: 'postgres',
application_name: 'test'
})

client.connect(err => {
if (err) return t.fail(err)

profile(t, operation).then(() => client.end())
})

function operation (done) {
client.query('SELECT 1 + 1 AS solution', done)
}
})