Skip to content

Commit

Permalink
add tests to detect memory leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
rochdev committed Aug 10, 2018
1 parent d3cfb25 commit a4fcecf
Show file tree
Hide file tree
Showing 14 changed files with 344 additions and 8 deletions.
28 changes: 22 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2
jobs:
lint:
docker:
- image: node:alpine
- image: node
working_directory: ~/dd-trace-js
steps:
- checkout
Expand All @@ -15,9 +15,24 @@ jobs:
- run:
name: Lint
command: npm run lint
test-memory-leaks:
docker:
- image: node:8
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 run leak
build-node-base: &node-base
docker:
- image: node:alpine
- image: node
- &postgres
image: postgres:9.5
- &mysql
Expand Down Expand Up @@ -53,7 +68,7 @@ jobs:
build-node-4:
<<: *node-base
docker:
- image: node:4-alpine
- image: node:4
- *postgres
- *mysql
- *redis
Expand All @@ -63,7 +78,7 @@ jobs:
build-node-6:
<<: *node-base
docker:
- image: node:6-alpine
- image: node:6
- *postgres
- *mysql
- *redis
Expand All @@ -73,7 +88,7 @@ jobs:
build-node-8:
<<: *node-base
docker:
- image: node:8-alpine
- image: node:8
- *postgres
- *mysql
- *redis
Expand All @@ -83,7 +98,7 @@ jobs:
build-node-latest:
<<: *node-base
docker:
- image: node:alpine
- image: node
- *postgres
- *mysql
- *redis
Expand All @@ -96,6 +111,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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"
}
}
40 changes: 40 additions & 0 deletions test/leak/plugins/amqplib.js
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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)
}
})
19 changes: 19 additions & 0 deletions test/leak/plugins/redis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict'

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

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

test('redis plugin should not leak', t => {
const client = redis.createClient()

profile(t, operation).then(() => client.quit())

function operation (done) {
client.get('foo', done)
}
})
14 changes: 14 additions & 0 deletions test/leak/scope_manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

require('../..').init()

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

test('ScopeManager should destroy executions even if their context is already destroyed', t => {
profile(t, operation)

function operation (done) {
Promise.resolve().then(done)
}
})
15 changes: 15 additions & 0 deletions test/leak/tracer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict'

const tracer = require('../..').init()

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

test('Tracer should not keep unfinished spans in memory if they are no longer needed', t => {
profile(t, operation)

function operation (done) {
tracer.startSpan('test')
done()
}
})

0 comments on commit a4fcecf

Please sign in to comment.