Skip to content

Commit 9ba17b8

Browse files
committed
Added mysql2 promise support and tests
1 parent b4f6e7a commit 9ba17b8

File tree

5 files changed

+144
-49
lines changed

5 files changed

+144
-49
lines changed

lib/instrumentation.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ exports.callbackInitialize = function callbackInitialize(shim, mysql) {
4343
}
4444
}
4545

46-
exports.promiseInitialize = function promiseInitialize(shim, mysql) {
46+
exports.promiseInitialize = function promiseInitialize(shim) {
47+
const callbackAPI = shim.require('./index')
4748

49+
if (callbackAPI && !shim.isWrapped(callbackAPI.createConnection)) {
50+
exports.callbackInitialize(shim, callbackAPI)
51+
}
4852
}
4953

5054
function wrapGetConnection(shim, connectable) {

tests/versioned/common/basic.js

+1-41
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ module.exports = (t, requireMySQL) => {
157157
})
158158
})
159159

160-
t.test('ensure database name changes with a use statement', (t) => {
160+
t.test('database name should change with use statement', (t) => {
161161
helper.runInTransaction((txn) => {
162162
withRetry.getClient((err, client) => {
163163
if (!t.error(err)) {
@@ -354,46 +354,6 @@ module.exports = (t, requireMySQL) => {
354354
})
355355
})
356356
})
357-
358-
t.test('ensure database name changes with a use statement', (t) => {
359-
helper.runInTransaction((txn) => {
360-
withRetry.getClient((err, client) => {
361-
client.query('create database if not exists test_db;', (err) => {
362-
t.error(err)
363-
client.query('use test_db;', (err) => {
364-
t.error(err)
365-
client.query('SELECT 1 + 1 AS solution', (err) => {
366-
var seg = helper.agent.tracer.getSegment().parent
367-
t.error(err)
368-
if (t.ok(seg, 'should have a segment')) {
369-
t.equal(
370-
seg.parameters.host,
371-
urltils.isLocalhost(params.mysql_host)
372-
? helper.agent.config.getHostnameSafe()
373-
: params.mysql_host,
374-
'should set host parameter'
375-
)
376-
t.equal(
377-
seg.parameters.database_name,
378-
'test_db',
379-
'should use new database name'
380-
)
381-
t.equal(
382-
seg.parameters.port_path_or_id,
383-
'3306',
384-
'should set port parameter'
385-
)
386-
}
387-
client.query('drop test_db;', () => {
388-
withRetry.release(client)
389-
txn.end(t.end)
390-
})
391-
})
392-
})
393-
})
394-
})
395-
})
396-
})
397357
})
398358
}
399359

tests/versioned/common/transactions.js

-5
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,6 @@ module.exports = (t, requireMySQL) => {
1515

1616
// set up the instrumentation before loading MySQL
1717
const helper = utils.TestAgent.makeInstrumented()
18-
helper.registerInstrumentation({
19-
moduleName: 'mysql',
20-
type: 'datastore',
21-
onRequire: require('../../../lib/instrumentation').callbackInitialize
22-
})
2318
const mysql = requireMySQL(helper)
2419

2520
t.tearDown(() => helper.unload())

tests/versioned/mysql2/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"basic-pool.tap.js",
1515
"basic.tap.js",
1616
"pooling.tap.js",
17-
"transactions.tap.js"
17+
"transactions.tap.js",
18+
"promises.tap.js"
1819
]
1920
},
2021
{
@@ -28,7 +29,8 @@
2829
"basic-pool.tap.js",
2930
"basic.tap.js",
3031
"pooling.tap.js",
31-
"transactions.tap.js"
32+
"transactions.tap.js",
33+
"promises.tap.js"
3234
]
3335
}
3436
],
+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
'use strict'
2+
3+
const setup = require('../common/setup')
4+
const tap = require('tap')
5+
const urltils = require('newrelic/lib/util/urltils') // TODO: Expose via test utilities
6+
const utils = require('@newrelic/test-utilities')
7+
8+
const params = setup.params
9+
const DBUSER = 'test_user'
10+
const DBNAME = 'agent_integration'
11+
12+
13+
utils(tap)
14+
15+
tap.test('mysql2 promises', {timeout: 30000}, (t) => {
16+
t.autoend()
17+
18+
let helper = null
19+
let mysql = null
20+
let client = null
21+
22+
t.beforeEach((done) => {
23+
helper = utils.TestAgent.makeInstrumented()
24+
25+
// Stub the normal mysql2 instrumentation to avoid it hiding issues with the
26+
// promise instrumentation.
27+
helper.registerInstrumentation({
28+
moduleName: 'mysql2',
29+
type: 'datastore',
30+
onRequire: () => {}
31+
})
32+
33+
helper.registerInstrumentation({
34+
moduleName: 'mysql2/promise',
35+
type: 'datastore',
36+
onRequire: require('../../../lib/instrumentation').promiseInitialize
37+
})
38+
mysql = require('mysql2/promise')
39+
40+
// Perform the setup using the callback API.
41+
setup(require('mysql2'), (err) => {
42+
if (err) {
43+
done(err)
44+
} else {
45+
mysql.createConnection({
46+
user: DBUSER,
47+
databsae: DBNAME,
48+
host: params.mysql_host,
49+
port: params.mysql_port
50+
}).then((c) => {client = c; done()}, done)
51+
}
52+
})
53+
})
54+
55+
t.afterEach((done) => {
56+
helper.unload()
57+
if (client) {
58+
client.end().then(done, done)
59+
client = null
60+
} else {
61+
done()
62+
}
63+
})
64+
65+
t.test('basic transaction', (t) => {
66+
return helper.runInTransaction((tx) => {
67+
return client.query('SELECT 1').then(() => {
68+
t.transaction(tx)
69+
return endAsync(tx)
70+
})
71+
}).then(() => checkQueries(t, helper))
72+
})
73+
74+
t.test('query with values', (t) => {
75+
return helper.runInTransaction((tx) => {
76+
return client.query('SELECT 1', []).then(() => {
77+
t.transaction(tx)
78+
return endAsync(tx)
79+
})
80+
}).then(() => checkQueries(t, helper))
81+
})
82+
83+
t.test('database name should change with use statement', (t) => {
84+
return helper.runInTransaction((tx) => {
85+
return client.query('create database if not exists test_db').then(() => {
86+
t.transaction(tx)
87+
return client.query('use test_db')
88+
}).then(() => {
89+
t.transaction(tx)
90+
return client.query('SELECT 1 + 1 AS solution')
91+
}).then(() => {
92+
t.transaction(tx)
93+
94+
const segment = tx.trace.root.children[2]
95+
const parameters = segment.parameters
96+
t.equal(parameters.host, getHostName(helper), 'should set host name')
97+
t.equal(parameters.database_name, 'test_db', 'should follow use statement')
98+
t.equal(parameters.port_path_or_id, '3306', 'should set port')
99+
100+
return endAsync(tx)
101+
})
102+
}).then(() => checkQueries(t, helper))
103+
})
104+
105+
t.test('query with options object rather than sql', (t) => {
106+
return helper.runInTransaction((tx) => {
107+
return client.query({sql: 'SELECT 1'}).then(() => endAsync(tx))
108+
}).then(() => checkQueries(t, helper))
109+
})
110+
111+
t.test('query with options object and values', (t) => {
112+
return helper.runInTransaction((tx) => {
113+
return client.query({sql: 'SELECT 1'}, []).then(() => endAsync(tx))
114+
}).then(() => checkQueries(t, helper))
115+
})
116+
})
117+
118+
function checkQueries(t, helper) {
119+
const querySamples = helper.agent.queries.samples
120+
t.ok(querySamples.size > 0, 'there should be a query sample')
121+
for (let sample of querySamples.values()) {
122+
t.ok(sample.total > 0, 'the samples should have positive duration')
123+
}
124+
}
125+
126+
function endAsync(tx) {
127+
return new Promise((resolve) => tx.end(() => resolve()))
128+
}
129+
130+
function getHostName(helper) {
131+
return urltils.isLocalhost(params.mysql_host)
132+
? helper.agent.config.getHostnameSafe()
133+
: params.mysql_host
134+
}

0 commit comments

Comments
 (0)