Skip to content

Commit 7e95984

Browse files
authored
test: clean up usage of agent.assertTelemetryReceived (#5883)
Ensure that: - We always await calls to `agent.assertTelemetryReceived` (instead of either ignoring the promise, or chaining a `.then()` call) - We always use a reasonable timeout. Additionally, `agent.assertTelemetryReceived` is updated to allow the function to be optional. A bug in `assertObjectContains` is also fixed to allow arrays to be checked. * Address review comments
1 parent b9e0157 commit 7e95984

File tree

9 files changed

+121
-92
lines changed

9 files changed

+121
-92
lines changed

integration-tests/helpers/fake-agent.js

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const bodyParser = require('body-parser')
88
const msgpack = require('@msgpack/msgpack')
99
const upload = require('multer')()
1010

11+
const noop = () => {}
12+
1113
module.exports = class FakeAgent extends EventEmitter {
1214
constructor (port = 0) {
1315
// Redirect rejections to the error event
@@ -161,8 +163,32 @@ module.exports = class FakeAgent extends EventEmitter {
161163
return resultPromise
162164
}
163165

164-
assertTelemetryReceived (fn, timeout, requestType, expectedMessageCount = 1) {
165-
timeout = timeout || 30000
166+
/**
167+
* Assert that a telemetry message is received.
168+
*
169+
* @overload
170+
* @param {string} requestType - The request type to assert.
171+
* @param {number} [timeout=30_000] - The timeout in milliseconds.
172+
* @param {number} [expectedMessageCount=1] - The number of messages to expect.
173+
* @returns {Promise<void>} A promise that resolves when the telemetry message of type `requestType` is received.
174+
*
175+
* @overload
176+
* @param {Function} fn - The function to call with the telemetry message of type `requestType`.
177+
* @param {string} requestType - The request type to assert.
178+
* @param {number} [timeout=30_000] - The timeout in milliseconds.
179+
* @param {number} [expectedMessageCount=1] - The number of messages to expect.
180+
* @returns {Promise<void>} A promise that resolves when the telemetry message of type `requestType` is received and
181+
* the function `fn` has finished running. If `fn` throws an error, the promise will be rejected once `timeout`
182+
* is reached.
183+
*/
184+
assertTelemetryReceived (fn, requestType, timeout = 30_000, expectedMessageCount = 1) {
185+
if (typeof fn !== 'function') {
186+
expectedMessageCount = timeout
187+
timeout = requestType
188+
requestType = fn
189+
fn = noop
190+
}
191+
166192
let resultResolve
167193
let resultReject
168194
let msgCount = 0

integration-tests/helpers/index.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,31 @@ function setShouldKill (value) {
390390
}
391391

392392
const assertObjectContains = assert.partialDeepStrictEqual || function assertObjectContains (actual, expected) {
393+
if (Array.isArray(expected)) {
394+
assert.ok(Array.isArray(actual), `Expected array but got ${typeof actual}`)
395+
let startIndex = 0
396+
for (const expectedItem of expected) {
397+
let found = false
398+
for (let i = startIndex; i < actual.length; i++) {
399+
const actualItem = actual[i]
400+
try {
401+
if (expectedItem !== null && typeof expectedItem === 'object') {
402+
assertObjectContains(actualItem, expectedItem)
403+
} else {
404+
assert.strictEqual(actualItem, expectedItem)
405+
}
406+
startIndex = i + 1
407+
found = true
408+
break
409+
} catch {
410+
continue
411+
}
412+
}
413+
assert.ok(found, `Expected array to contain ${JSON.stringify(expectedItem)}`)
414+
}
415+
return
416+
}
417+
393418
for (const [key, val] of Object.entries(expected)) {
394419
if (val !== null && typeof val === 'object') {
395420
assert.ok(Object.hasOwn(actual, key))

integration-tests/opentelemetry.spec.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ const { join } = require('path')
66
const { assert } = require('chai')
77
const axios = require('axios')
88

9-
function check (agent, proc, timeout, onMessage = () => { }, isMetrics) {
9+
async function check (agent, proc, timeout, onMessage = () => { }, isMetrics) {
1010
const messageReceiver = isMetrics
11-
? agent.assertTelemetryReceived(onMessage, timeout, 'generate-metrics')
11+
? agent.assertTelemetryReceived(onMessage, 'generate-metrics', timeout)
1212
: agent.assertMessageReceived(onMessage, timeout)
1313

14-
return Promise.all([
14+
const [res] = await Promise.all([
1515
messageReceiver,
1616
new Promise((resolve, reject) => {
1717
const timer = setTimeout(() => {
@@ -30,7 +30,9 @@ function check (agent, proc, timeout, onMessage = () => { }, isMetrics) {
3030
}
3131
})
3232
})
33-
]).then(([res]) => res)
33+
])
34+
35+
return res
3436
}
3537

3638
function allEqual (spans, fn) {
@@ -76,7 +78,7 @@ describe('opentelemetry', () => {
7678
await sandbox.remove()
7779
})
7880

79-
it("should not capture telemetry DD and OTEL vars don't conflict", () => {
81+
it("should not capture telemetry DD and OTEL vars don't conflict", async () => {
8082
proc = fork(join(cwd, 'opentelemetry/basic.js'), {
8183
cwd,
8284
env: {
@@ -94,7 +96,7 @@ describe('opentelemetry', () => {
9496
}
9597
})
9698

97-
return check(agent, proc, timeout, ({ payload }) => {
99+
await check(agent, proc, timeout, ({ payload }) => {
98100
assert.strictEqual(payload.request_type, 'generate-metrics')
99101

100102
const metrics = payload.payload
@@ -108,7 +110,7 @@ describe('opentelemetry', () => {
108110
}, true)
109111
})
110112

111-
it('should capture telemetry if both DD and OTEL env vars are set', () => {
113+
it('should capture telemetry if both DD and OTEL env vars are set', async () => {
112114
proc = fork(join(cwd, 'opentelemetry/basic.js'), {
113115
cwd,
114116
env: {
@@ -136,7 +138,7 @@ describe('opentelemetry', () => {
136138
}
137139
})
138140

139-
return check(agent, proc, timeout, ({ payload }) => {
141+
await check(agent, proc, timeout, ({ payload }) => {
140142
assert.strictEqual(payload.request_type, 'generate-metrics')
141143

142144
const metrics = payload.payload
@@ -188,7 +190,7 @@ describe('opentelemetry', () => {
188190
}, true)
189191
})
190192

191-
it('should capture telemetry when OTEL env vars are invalid', () => {
193+
it('should capture telemetry when OTEL env vars are invalid', async () => {
192194
proc = fork(join(cwd, 'opentelemetry/basic.js'), {
193195
cwd,
194196
env: {
@@ -209,7 +211,7 @@ describe('opentelemetry', () => {
209211
}
210212
})
211213

212-
return check(agent, proc, timeout, ({ payload }) => {
214+
await check(agent, proc, timeout, ({ payload }) => {
213215
assert.strictEqual(payload.request_type, 'generate-metrics')
214216

215217
const metrics = payload.payload
@@ -274,7 +276,7 @@ describe('opentelemetry', () => {
274276
DD_TRACE_AGENT_PORT: agent.port
275277
}
276278
})
277-
return check(agent, proc, timeout, ({ payload }) => {
279+
await check(agent, proc, timeout, ({ payload }) => {
278280
// Should have a single trace with a single span
279281
assert.strictEqual(payload.length, 1)
280282
const [trace] = payload
@@ -286,7 +288,7 @@ describe('opentelemetry', () => {
286288
})
287289
})
288290

289-
it('should capture telemetry', () => {
291+
it('should capture telemetry', async () => {
290292
proc = fork(join(cwd, 'opentelemetry/basic.js'), {
291293
cwd,
292294
env: {
@@ -297,7 +299,7 @@ describe('opentelemetry', () => {
297299
}
298300
})
299301

300-
return check(agent, proc, timeout, ({ payload }) => {
302+
await check(agent, proc, timeout, ({ payload }) => {
301303
assert.strictEqual(payload.request_type, 'generate-metrics')
302304

303305
const metrics = payload.payload
@@ -342,7 +344,7 @@ describe('opentelemetry', () => {
342344
await new Promise(resolve => setTimeout(resolve, 1000)) // Adjust the delay as necessary
343345
await axios.get(`http://localhost:${SERVER_PORT}/first-endpoint`)
344346

345-
return check(agent, proc, 10000, ({ payload }) => {
347+
await check(agent, proc, 10000, ({ payload }) => {
346348
assert.strictEqual(payload.request_type, 'generate-metrics')
347349

348350
const metrics = payload.payload
@@ -379,7 +381,7 @@ describe('opentelemetry', () => {
379381
DD_TRACE_AGENT_PORT: agent.port
380382
}
381383
})
382-
return check(agent, proc, timeout, ({ payload }) => {
384+
await check(agent, proc, timeout, ({ payload }) => {
383385
// Should have three spans
384386
const [trace] = payload
385387
assert.strictEqual(trace.length, 3)
@@ -414,7 +416,7 @@ describe('opentelemetry', () => {
414416
await new Promise(resolve => setTimeout(resolve, 1000)) // Adjust the delay as necessary
415417
await axios.get(`http://localhost:${SERVER_PORT}/first-endpoint`)
416418

417-
return check(agent, proc, 10000, ({ payload }) => {
419+
await check(agent, proc, 10000, ({ payload }) => {
418420
assert.strictEqual(payload.length, 2)
419421
// combine the traces
420422
const trace = payload.flat()
@@ -457,7 +459,7 @@ describe('opentelemetry', () => {
457459
DD_TRACE_AGENT_PORT: agent.port
458460
}
459461
})
460-
return check(agent, proc, timeout, ({ payload }) => {
462+
await check(agent, proc, timeout, ({ payload }) => {
461463
// Should have a single trace with a single span
462464
assert.strictEqual(payload.length, 1)
463465
const [trace] = payload

integration-tests/profiler/profiler.spec.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -539,21 +539,21 @@ describe('profiler', () => {
539539
proc.kill()
540540
})
541541

542-
it('records profile on process exit', () => {
542+
it('records profile on process exit', async () => {
543543
proc = fork(profilerTestFile, {
544544
cwd,
545545
env: {
546546
DD_TRACE_AGENT_PORT: agent.port,
547547
DD_PROFILING_ENABLED: 1
548548
}
549549
})
550-
const checkTelemetry = agent.assertTelemetryReceived(_ => {}, 1000, 'generate-metrics')
550+
const checkTelemetry = agent.assertTelemetryReceived('generate-metrics', 1000)
551551
// SSI telemetry is not supposed to have been emitted when DD_INJECTION_ENABLED is absent,
552552
// so expect telemetry callback to time out
553-
return Promise.all([checkProfiles(agent, proc, timeout), expectTimeout(checkTelemetry)])
553+
await Promise.all([checkProfiles(agent, proc, timeout), expectTimeout(checkTelemetry)])
554554
})
555555

556-
it('records SSI telemetry on process exit', () => {
556+
it('records SSI telemetry on process exit', async () => {
557557
proc = fork(profilerTestFile, {
558558
cwd,
559559
env: {
@@ -588,8 +588,9 @@ describe('profiler', () => {
588588
assert.equal(series[1].type, 'count')
589589
checkTags(series[1].tags)
590590
assert.equal(series[1].points[0][1], 1)
591-
}, timeout, 'generate-metrics')
592-
return Promise.all([checkProfiles(agent, proc, timeout), checkTelemetry])
591+
}, 'generate-metrics', timeout)
592+
593+
await Promise.all([checkProfiles(agent, proc, timeout), checkTelemetry])
593594
})
594595

595596
if (process.platform !== 'win32') { // PROF-8905
@@ -706,7 +707,7 @@ describe('profiler', () => {
706707
await agent.stop()
707708
})
708709

709-
it('sends profiler API telemetry', () => {
710+
it('sends profiler API telemetry', async () => {
710711
proc = fork(profilerTestFile, {
711712
cwd,
712713
env: {
@@ -739,7 +740,7 @@ describe('profiler', () => {
739740

740741
// Same number of requests and responses
741742
assert.equal(series[1].points[0][1], requestCount)
742-
}, timeout, 'generate-metrics')
743+
}, 'generate-metrics', timeout)
743744

744745
const checkDistributions = agent.assertTelemetryReceived(({ _, payload }) => {
745746
const pp = payload.payload
@@ -752,12 +753,12 @@ describe('profiler', () => {
752753
// Same number of points
753754
pointsCount = series[0].points.length
754755
assert.equal(pointsCount, series[1].points.length)
755-
}, timeout, 'distributions')
756+
}, 'distributions', timeout)
756757

757-
return Promise.all([checkProfiles(agent, proc, timeout), checkMetrics, checkDistributions]).then(() => {
758-
// Same number of requests and points
759-
assert.equal(requestCount, pointsCount)
760-
})
758+
await Promise.all([checkProfiles(agent, proc, timeout), checkMetrics, checkDistributions])
759+
760+
// Same number of requests and points
761+
assert.equal(requestCount, pointsCount)
761762
})
762763
})
763764

integration-tests/telemetry.spec.js

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict'
22

3-
const { createSandbox, FakeAgent, spawnProc } = require('./helpers')
4-
const assert = require('assert')
3+
const { createSandbox, FakeAgent, spawnProc, assertObjectContains } = require('./helpers')
54
const path = require('path')
65

76
describe('telemetry', () => {
@@ -38,11 +37,11 @@ describe('telemetry', () => {
3837
await agent.stop()
3938
})
4039

41-
it('Test that tracer and iitm are sent as dependencies', (done) => {
40+
it('Test that tracer and iitm are sent as dependencies', async () => {
4241
let ddTraceFound = false
4342
let importInTheMiddleFound = false
4443

45-
agent.assertTelemetryReceived(msg => {
44+
await agent.assertTelemetryReceived(msg => {
4645
const { payload } = msg
4746

4847
if (payload.request_type === 'app-dependencies-loaded') {
@@ -55,35 +54,23 @@ describe('telemetry', () => {
5554
importInTheMiddleFound = true
5655
}
5756
})
58-
if (ddTraceFound && importInTheMiddleFound) {
59-
done()
60-
}
6157
}
6258
}
63-
}, null, 'app-dependencies-loaded', 1)
64-
})
59+
}, 'app-dependencies-loaded', 5_000, 1)
6560

66-
it('Assert configuration chaining data is sent', (done) => {
67-
agent.assertTelemetryReceived(msg => {
68-
if (msg.payload.request_type !== 'app-started') return
61+
expect(ddTraceFound).to.be.true
62+
expect(importInTheMiddleFound).to.be.true
63+
})
6964

65+
it('Assert configuration chaining data is sent', async () => {
66+
await agent.assertTelemetryReceived(msg => {
7067
const { configuration } = msg.payload.payload
71-
72-
const expectedConfigs = [
68+
assertObjectContains(configuration, [
7369
{ name: 'DD_LOG_INJECTION', value: false, origin: 'default' },
7470
{ name: 'DD_LOG_INJECTION', value: true, origin: 'env_var' },
7571
{ name: 'DD_LOG_INJECTION', value: false, origin: 'code' }
76-
]
77-
expectedConfigs.forEach(expected => {
78-
const found = configuration.find(config =>
79-
config.name === expected.name &&
80-
config.origin === expected.origin &&
81-
config.value === expected.value
82-
)
83-
assert.ok(found, `Expected to find config: ${JSON.stringify(expected)}`)
84-
})
85-
done()
86-
}, null, 'app-started', 1)
72+
])
73+
}, 'app-started', 5_000, 1)
8774
})
8875
})
8976
})

packages/dd-trace/test/appsec/iast/code_injection.integration.spec.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('IAST - code_injection - integration', () => {
5151
})
5252
assert.isNotNull(instrumentedSink)
5353
}
54-
}, 30_000, 'generate-metrics', 2)
54+
}, 'generate-metrics', 30_000, 2)
5555

5656
const checkMessages = agent.assertMessageReceived(({ headers, payload }) => {
5757
assert.strictEqual(payload[0][0].metrics['_dd.iast.enabled'], 1)
@@ -67,11 +67,9 @@ describe('IAST - code_injection - integration', () => {
6767
assert.isTrue(vulnerabilities.has('CODE_INJECTION'))
6868
})
6969

70-
return Promise.all([checkMessages, checkTelemetry]).then(() => {
71-
assert.equal(iastTelemetryReceived, true)
70+
await Promise.all([checkMessages, checkTelemetry])
7271

73-
return true
74-
})
72+
assert.equal(iastTelemetryReceived, true)
7573
}
7674

7775
describe('SourceTextModule', () => {

0 commit comments

Comments
 (0)