dd-trace 2.21.0 → 2.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +2 -0
- package/index.d.ts +42 -31
- package/package.json +4 -2
- package/packages/datadog-instrumentations/src/body-parser.js +26 -0
- package/packages/datadog-instrumentations/src/child-process.js +30 -0
- package/packages/datadog-instrumentations/src/connect.js +15 -15
- package/packages/datadog-instrumentations/src/cucumber.js +1 -1
- package/packages/datadog-instrumentations/src/hapi.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
- package/packages/datadog-instrumentations/src/http/server.js +11 -12
- package/packages/datadog-instrumentations/src/jest.js +102 -42
- package/packages/datadog-instrumentations/src/koa.js +32 -32
- package/packages/datadog-instrumentations/src/mocha.js +87 -6
- package/packages/datadog-instrumentations/src/pg.js +1 -2
- package/packages/datadog-instrumentations/src/qs.js +24 -0
- package/packages/datadog-instrumentations/src/restify.js +6 -3
- package/packages/datadog-instrumentations/src/router.js +22 -22
- package/packages/datadog-plugin-cucumber/src/index.js +13 -32
- package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +0 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +0 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +0 -1
- package/packages/datadog-plugin-http/src/client.js +5 -3
- package/packages/datadog-plugin-http/src/server.js +11 -0
- package/packages/datadog-plugin-http2/src/client.js +2 -0
- package/packages/datadog-plugin-http2/src/server.js +3 -0
- package/packages/datadog-plugin-jest/src/index.js +11 -131
- package/packages/datadog-plugin-mocha/src/index.js +33 -46
- package/packages/datadog-plugin-net/src/index.js +4 -0
- package/packages/datadog-plugin-next/src/index.js +3 -0
- package/packages/datadog-plugin-pg/src/index.js +5 -2
- package/packages/datadog-plugin-router/src/index.js +9 -1
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +3 -5
- package/packages/dd-trace/src/appsec/gateway/engine/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +6 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +8 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +125 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +66 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +52 -6
- package/packages/dd-trace/src/appsec/index.js +8 -0
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +34 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
- package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
- package/packages/dd-trace/src/appsec/rule_manager.js +3 -0
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +5 -7
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +1 -3
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -3
- package/packages/dd-trace/src/config.js +25 -9
- package/packages/dd-trace/src/constants.js +6 -1
- package/packages/dd-trace/src/exporters/common/request.js +7 -1
- package/packages/dd-trace/src/format.js +12 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
- package/packages/dd-trace/src/opentracing/span_context.js +9 -0
- package/packages/dd-trace/src/plugin_manager.js +4 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +132 -0
- package/packages/dd-trace/src/plugins/database.js +46 -0
- package/packages/dd-trace/src/plugins/tracing.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +61 -8
- package/packages/dd-trace/src/plugins/util/web.js +14 -9
- package/packages/dd-trace/src/profiling/config.js +3 -1
- package/packages/dd-trace/src/profiling/index.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +35 -6
- package/packages/dd-trace/src/proxy.js +5 -1
- package/packages/dd-trace/src/tracer.js +4 -3
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const istanbul = require('istanbul-lib-coverage')
|
|
3
2
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
3
|
const shimmer = require('../../datadog-shimmer')
|
|
5
4
|
const log = require('../../dd-trace/src/log')
|
|
5
|
+
const { getCoveredFilenamesFromCoverage } = require('../../dd-trace/src/plugins/util/test')
|
|
6
6
|
|
|
7
7
|
const testSessionStartCh = channel('ci:jest:session:start')
|
|
8
8
|
const testSessionFinishCh = channel('ci:jest:session:finish')
|
|
@@ -23,6 +23,7 @@ const jestConfigurationCh = channel('ci:jest:configuration')
|
|
|
23
23
|
|
|
24
24
|
let skippableSuites = []
|
|
25
25
|
let isCodeCoverageEnabled = false
|
|
26
|
+
let isSuitesSkippingEnabled = false
|
|
26
27
|
|
|
27
28
|
const {
|
|
28
29
|
getTestSuitePath,
|
|
@@ -33,21 +34,6 @@ const { getFormattedJestTestParameters, getJestTestName } = require('../../datad
|
|
|
33
34
|
|
|
34
35
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
35
36
|
|
|
36
|
-
function extractCoverageInformation (coverage, rootDir) {
|
|
37
|
-
const coverageMap = istanbul.createCoverageMap(coverage)
|
|
38
|
-
|
|
39
|
-
return coverageMap
|
|
40
|
-
.files()
|
|
41
|
-
.filter(filename => {
|
|
42
|
-
const fileCoverage = coverageMap.fileCoverageFor(filename)
|
|
43
|
-
const lineCoverage = fileCoverage.getLineCoverage()
|
|
44
|
-
const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
|
|
45
|
-
|
|
46
|
-
return isAnyLineExecuted
|
|
47
|
-
})
|
|
48
|
-
.map(filename => filename.replace(`${rootDir}/`, ''))
|
|
49
|
-
}
|
|
50
|
-
|
|
51
37
|
const specStatusToTestStatus = {
|
|
52
38
|
'pending': 'skip',
|
|
53
39
|
'disabled': 'skip',
|
|
@@ -186,38 +172,42 @@ addHook({
|
|
|
186
172
|
|
|
187
173
|
function cliWrapper (cli) {
|
|
188
174
|
const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
|
|
189
|
-
let
|
|
190
|
-
const configurationPromise = new Promise((resolve
|
|
191
|
-
|
|
192
|
-
onError = reject
|
|
175
|
+
let onDone
|
|
176
|
+
const configurationPromise = new Promise((resolve) => {
|
|
177
|
+
onDone = resolve
|
|
193
178
|
})
|
|
194
179
|
|
|
195
180
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
196
|
-
jestConfigurationCh.publish({
|
|
181
|
+
jestConfigurationCh.publish({ onDone })
|
|
197
182
|
})
|
|
198
183
|
|
|
199
|
-
let isSuitesSkippingEnabled = false
|
|
200
|
-
|
|
201
184
|
try {
|
|
202
|
-
const config = await configurationPromise
|
|
185
|
+
const { err, config } = await configurationPromise
|
|
186
|
+
if (err) {
|
|
187
|
+
log.error(err)
|
|
188
|
+
}
|
|
203
189
|
isCodeCoverageEnabled = config.isCodeCoverageEnabled
|
|
204
190
|
isSuitesSkippingEnabled = config.isSuitesSkippingEnabled
|
|
205
191
|
} catch (e) {
|
|
206
|
-
|
|
192
|
+
log.error(e)
|
|
207
193
|
}
|
|
208
194
|
|
|
209
195
|
if (isSuitesSkippingEnabled) {
|
|
210
|
-
const skippableSuitesPromise = new Promise((resolve
|
|
211
|
-
|
|
212
|
-
onError = reject
|
|
196
|
+
const skippableSuitesPromise = new Promise((resolve) => {
|
|
197
|
+
onDone = resolve
|
|
213
198
|
})
|
|
214
199
|
|
|
215
200
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
216
|
-
skippableSuitesCh.publish({
|
|
201
|
+
skippableSuitesCh.publish({ onDone })
|
|
217
202
|
})
|
|
218
203
|
|
|
219
204
|
try {
|
|
220
|
-
skippableSuites = await skippableSuitesPromise
|
|
205
|
+
const { err, skippableSuites: receivedSkippableSuites } = await skippableSuitesPromise
|
|
206
|
+
if (err) {
|
|
207
|
+
log.error(err)
|
|
208
|
+
} else {
|
|
209
|
+
skippableSuites = receivedSkippableSuites
|
|
210
|
+
}
|
|
221
211
|
} catch (e) {
|
|
222
212
|
log.error(e)
|
|
223
213
|
}
|
|
@@ -253,6 +243,35 @@ function cliWrapper (cli) {
|
|
|
253
243
|
return cli
|
|
254
244
|
}
|
|
255
245
|
|
|
246
|
+
function coverageReporterWrapper (coverageReporter) {
|
|
247
|
+
const CoverageReporter = coverageReporter.default ? coverageReporter.default : coverageReporter
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* If ITR is active, we're running fewer tests, so of course the total code coverage is reduced.
|
|
251
|
+
* This calculation adds no value, so we'll skip it.
|
|
252
|
+
*/
|
|
253
|
+
shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => async function () {
|
|
254
|
+
if (isSuitesSkippingEnabled) {
|
|
255
|
+
return Promise.resolve()
|
|
256
|
+
}
|
|
257
|
+
return addUntestedFiles.apply(this, arguments)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
return coverageReporter
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
addHook({
|
|
264
|
+
name: '@jest/reporters',
|
|
265
|
+
file: 'build/coverage_reporter.js',
|
|
266
|
+
versions: ['>=24.8.0 <26.6.2']
|
|
267
|
+
}, coverageReporterWrapper)
|
|
268
|
+
|
|
269
|
+
addHook({
|
|
270
|
+
name: '@jest/reporters',
|
|
271
|
+
file: 'build/CoverageReporter.js',
|
|
272
|
+
versions: ['>=26.6.2']
|
|
273
|
+
}, coverageReporterWrapper)
|
|
274
|
+
|
|
256
275
|
addHook({
|
|
257
276
|
name: '@jest/core',
|
|
258
277
|
file: 'build/cli/index.js',
|
|
@@ -281,13 +300,16 @@ function jestAdapterWrapper (jestAdapter) {
|
|
|
281
300
|
status = 'fail'
|
|
282
301
|
}
|
|
283
302
|
testSuiteFinishCh.publish({ status, errorMessage })
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
303
|
+
|
|
304
|
+
const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
|
|
305
|
+
.map(filename => getTestSuitePath(filename, environment.rootDir))
|
|
306
|
+
|
|
307
|
+
if (coverageFiles &&
|
|
308
|
+
environment.testEnvironmentOptions &&
|
|
309
|
+
environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
|
|
310
|
+
asyncResource.runInAsyncScope(() => {
|
|
289
311
|
testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
|
|
290
|
-
}
|
|
312
|
+
})
|
|
291
313
|
}
|
|
292
314
|
return suiteResults
|
|
293
315
|
})
|
|
@@ -310,12 +332,6 @@ addHook({
|
|
|
310
332
|
|
|
311
333
|
function configureTestEnvironment (readConfigsResult) {
|
|
312
334
|
const { configs } = readConfigsResult
|
|
313
|
-
configs.forEach(config => {
|
|
314
|
-
skippableSuites.forEach((suite) => {
|
|
315
|
-
config.testMatch.push(`!**/${suite}`)
|
|
316
|
-
})
|
|
317
|
-
skippableSuites = []
|
|
318
|
-
})
|
|
319
335
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
320
336
|
testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
|
|
321
337
|
})
|
|
@@ -324,6 +340,7 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
324
340
|
configs.forEach(config => {
|
|
325
341
|
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
|
|
326
342
|
})
|
|
343
|
+
|
|
327
344
|
if (isCodeCoverageEnabled) {
|
|
328
345
|
const globalConfig = {
|
|
329
346
|
...readConfigsResult.globalConfig,
|
|
@@ -331,6 +348,16 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
331
348
|
}
|
|
332
349
|
readConfigsResult.globalConfig = globalConfig
|
|
333
350
|
}
|
|
351
|
+
if (isSuitesSkippingEnabled) {
|
|
352
|
+
// If suite skipping is enabled, the code coverage results are not going to be relevant,
|
|
353
|
+
// so we do not show them.
|
|
354
|
+
const globalConfig = {
|
|
355
|
+
...readConfigsResult.globalConfig,
|
|
356
|
+
coverageReporters: ['none']
|
|
357
|
+
}
|
|
358
|
+
readConfigsResult.globalConfig = globalConfig
|
|
359
|
+
}
|
|
360
|
+
|
|
334
361
|
return readConfigsResult
|
|
335
362
|
}
|
|
336
363
|
|
|
@@ -352,6 +379,39 @@ function jestConfigSyncWrapper (jestConfig) {
|
|
|
352
379
|
return jestConfig
|
|
353
380
|
}
|
|
354
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Hook to remove the test paths (test suite) that are part of `skippableSuites`
|
|
384
|
+
*/
|
|
385
|
+
addHook({
|
|
386
|
+
name: '@jest/core',
|
|
387
|
+
versions: ['>=24.8.0'],
|
|
388
|
+
file: 'build/SearchSource.js'
|
|
389
|
+
}, searchSourcePackage => {
|
|
390
|
+
const SearchSource = searchSourcePackage.default ? searchSourcePackage.default : searchSourcePackage
|
|
391
|
+
|
|
392
|
+
shimmer.wrap(SearchSource.prototype, 'getTestPaths', getTestPaths => async function () {
|
|
393
|
+
if (!skippableSuites.length) {
|
|
394
|
+
return getTestPaths.apply(this, arguments)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const [{ rootDir }] = arguments
|
|
398
|
+
|
|
399
|
+
const testPaths = await getTestPaths.apply(this, arguments)
|
|
400
|
+
const { tests } = testPaths
|
|
401
|
+
|
|
402
|
+
const filteredTests = tests.filter(({ path: testPath }) => {
|
|
403
|
+
const relativePath = testPath.replace(`${rootDir}/`, '')
|
|
404
|
+
return !skippableSuites.includes(relativePath)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
skippableSuites = []
|
|
408
|
+
|
|
409
|
+
return { ...testPaths, tests: filteredTests }
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
return searchSourcePackage
|
|
413
|
+
})
|
|
414
|
+
|
|
355
415
|
// from 25.1.0 on, readConfigs becomes async
|
|
356
416
|
addHook({
|
|
357
417
|
name: 'jest-config',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel
|
|
4
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const enterChannel = channel('apm:koa:middleware:enter')
|
|
7
7
|
const exitChannel = channel('apm:koa:middleware:exit')
|
|
8
8
|
const errorChannel = channel('apm:koa:middleware:error')
|
|
9
9
|
const nextChannel = channel('apm:koa:middleware:next')
|
|
10
|
+
const finishChannel = channel('apm:koa:middleware:finish')
|
|
10
11
|
const handleChannel = channel('apm:koa:request:handle')
|
|
11
12
|
const routeChannel = channel('apm:koa:request:route')
|
|
12
13
|
|
|
@@ -86,42 +87,41 @@ function wrapMiddleware (fn, layer) {
|
|
|
86
87
|
return function (ctx, next) {
|
|
87
88
|
if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments)
|
|
88
89
|
|
|
89
|
-
const middlewareResource = new AsyncResource('bound-anonymous-fn')
|
|
90
90
|
const req = ctx.req
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
|
|
92
|
+
const path = layer && layer.path
|
|
93
|
+
const route = typeof path === 'string' && !path.endsWith('(.*)') && !path.endsWith('([^/]*)') && path
|
|
95
94
|
|
|
96
|
-
|
|
95
|
+
enterChannel.publish({ req, name, route })
|
|
97
96
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
if (typeof next === 'function') {
|
|
98
|
+
arguments[1] = wrapNext(req, next)
|
|
99
|
+
}
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
} catch (e) {
|
|
121
|
-
fulfill(ctx, e)
|
|
122
|
-
throw e
|
|
101
|
+
try {
|
|
102
|
+
const result = fn.apply(this, arguments)
|
|
103
|
+
|
|
104
|
+
if (result && typeof result.then === 'function') {
|
|
105
|
+
return result.then(
|
|
106
|
+
result => {
|
|
107
|
+
fulfill(ctx)
|
|
108
|
+
return result
|
|
109
|
+
},
|
|
110
|
+
err => {
|
|
111
|
+
fulfill(ctx, err)
|
|
112
|
+
throw err
|
|
113
|
+
}
|
|
114
|
+
)
|
|
115
|
+
} else {
|
|
116
|
+
fulfill(ctx)
|
|
117
|
+
return result
|
|
123
118
|
}
|
|
124
|
-
})
|
|
119
|
+
} catch (e) {
|
|
120
|
+
fulfill(ctx, e)
|
|
121
|
+
throw e
|
|
122
|
+
} finally {
|
|
123
|
+
exitChannel.publish({ req })
|
|
124
|
+
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -138,7 +138,7 @@ function fulfill (ctx, error) {
|
|
|
138
138
|
routeChannel.publish({ req, route })
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
finishChannel.publish({ req })
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
function wrapNext (req, next) {
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
const { createCoverageMap } = require('istanbul-lib-coverage')
|
|
2
|
+
|
|
1
3
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
2
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
const log = require('../../dd-trace/src/log')
|
|
6
|
+
const {
|
|
7
|
+
getCoveredFilenamesFromCoverage,
|
|
8
|
+
resetCoverage,
|
|
9
|
+
mergeCoverage,
|
|
10
|
+
getTestSuitePath,
|
|
11
|
+
fromCoverageMapToCoverage
|
|
12
|
+
} = require('../../dd-trace/src/plugins/util/test')
|
|
3
13
|
|
|
4
14
|
const testStartCh = channel('ci:mocha:test:start')
|
|
5
15
|
const errorCh = channel('ci:mocha:test:error')
|
|
@@ -7,12 +17,16 @@ const skipCh = channel('ci:mocha:test:skip')
|
|
|
7
17
|
const testFinishCh = channel('ci:mocha:test:finish')
|
|
8
18
|
const parameterizedTestCh = channel('ci:mocha:test:parameterize')
|
|
9
19
|
|
|
20
|
+
const configurationCh = channel('ci:mocha:configuration')
|
|
21
|
+
const skippableSuitesCh = channel('ci:mocha:test-suite:skippable')
|
|
22
|
+
|
|
10
23
|
const testSessionStartCh = channel('ci:mocha:session:start')
|
|
11
24
|
const testSessionFinishCh = channel('ci:mocha:session:finish')
|
|
12
25
|
|
|
13
26
|
const testSuiteStartCh = channel('ci:mocha:test-suite:start')
|
|
14
27
|
const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
|
|
15
28
|
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
29
|
+
const testSuiteCodeCoverageCh = channel('ci:mocha:test-suite:code-coverage')
|
|
16
30
|
|
|
17
31
|
// TODO: remove when root hooks and fixtures are implemented
|
|
18
32
|
const patched = new WeakSet()
|
|
@@ -21,6 +35,11 @@ const testToAr = new WeakMap()
|
|
|
21
35
|
const originalFns = new WeakMap()
|
|
22
36
|
const testFileToSuiteAr = new Map()
|
|
23
37
|
|
|
38
|
+
// We'll preserve the original coverage here
|
|
39
|
+
const originalCoverageMap = createCoverageMap()
|
|
40
|
+
|
|
41
|
+
let suitesToSkip = []
|
|
42
|
+
|
|
24
43
|
function getSuitesByTestFile (root) {
|
|
25
44
|
const suitesByTestFile = {}
|
|
26
45
|
function getSuites (suite) {
|
|
@@ -46,13 +65,13 @@ function getSuitesByTestFile (root) {
|
|
|
46
65
|
}
|
|
47
66
|
|
|
48
67
|
function getTestStatus (test) {
|
|
49
|
-
if (test.
|
|
68
|
+
if (test.isPending()) {
|
|
50
69
|
return 'skip'
|
|
51
70
|
}
|
|
52
|
-
if (test.
|
|
53
|
-
return '
|
|
71
|
+
if (test.isFailed() || test.timedOut) {
|
|
72
|
+
return 'fail'
|
|
54
73
|
}
|
|
55
|
-
return '
|
|
74
|
+
return 'pass'
|
|
56
75
|
}
|
|
57
76
|
|
|
58
77
|
function isRetry (test) {
|
|
@@ -93,6 +112,8 @@ function mochaHook (Runner) {
|
|
|
93
112
|
}
|
|
94
113
|
testFileToSuiteAr.clear()
|
|
95
114
|
testSessionFinishCh.publish(status)
|
|
115
|
+
// restore the original coverage
|
|
116
|
+
global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
|
|
96
117
|
}))
|
|
97
118
|
|
|
98
119
|
this.once('start', testRunAsyncResource.bind(function () {
|
|
@@ -140,9 +161,21 @@ function mochaHook (Runner) {
|
|
|
140
161
|
})
|
|
141
162
|
}
|
|
142
163
|
|
|
164
|
+
if (global.__coverage__) {
|
|
165
|
+
const coverageFiles = getCoveredFilenamesFromCoverage(global.__coverage__)
|
|
166
|
+
|
|
167
|
+
testSuiteCodeCoverageCh.publish({
|
|
168
|
+
coverageFiles,
|
|
169
|
+
suiteFile: suite.file
|
|
170
|
+
})
|
|
171
|
+
// We need to reset coverage to get a code coverage per suite
|
|
172
|
+
// Before that, we preserve the original coverage
|
|
173
|
+
mergeCoverage(global.__coverage__, originalCoverageMap)
|
|
174
|
+
resetCoverage(global.__coverage__)
|
|
175
|
+
}
|
|
176
|
+
|
|
143
177
|
const asyncResource = testFileToSuiteAr.get(suite.file)
|
|
144
178
|
asyncResource.runInAsyncScope(() => {
|
|
145
|
-
// get suite status
|
|
146
179
|
testSuiteFinishCh.publish(status)
|
|
147
180
|
})
|
|
148
181
|
})
|
|
@@ -229,7 +262,8 @@ function mochaHook (Runner) {
|
|
|
229
262
|
skipCh.publish(test)
|
|
230
263
|
})
|
|
231
264
|
} else {
|
|
232
|
-
// if there is no async resource, the test has been skipped through `test.skip
|
|
265
|
+
// if there is no async resource, the test has been skipped through `test.skip`
|
|
266
|
+
// or the parent suite is skipped
|
|
233
267
|
const skippedTestAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
234
268
|
if (test.fn) {
|
|
235
269
|
testToAr.set(test.fn, skippedTestAsyncResource)
|
|
@@ -242,6 +276,11 @@ function mochaHook (Runner) {
|
|
|
242
276
|
}
|
|
243
277
|
})
|
|
244
278
|
|
|
279
|
+
// We remove the suites that we skip through ITR
|
|
280
|
+
this.suite.suites = this.suite.suites.filter(suite =>
|
|
281
|
+
!suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
|
|
282
|
+
)
|
|
283
|
+
|
|
245
284
|
return run.apply(this, arguments)
|
|
246
285
|
})
|
|
247
286
|
|
|
@@ -266,6 +305,48 @@ function mochaEachHook (mochaEach) {
|
|
|
266
305
|
})
|
|
267
306
|
}
|
|
268
307
|
|
|
308
|
+
addHook({
|
|
309
|
+
name: 'mocha',
|
|
310
|
+
versions: ['>=5.2.0'],
|
|
311
|
+
file: 'lib/mocha.js'
|
|
312
|
+
}, (Mocha) => {
|
|
313
|
+
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get ITR configuration and skippable suites
|
|
317
|
+
* If ITR is disabled, `onDone` is called immediately on the subscriber
|
|
318
|
+
*/
|
|
319
|
+
shimmer.wrap(Mocha.prototype, 'run', run => function () {
|
|
320
|
+
const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
|
|
321
|
+
if (err) {
|
|
322
|
+
log.error(err)
|
|
323
|
+
suitesToSkip = []
|
|
324
|
+
} else {
|
|
325
|
+
suitesToSkip = skippableSuites
|
|
326
|
+
}
|
|
327
|
+
run.apply(this, arguments)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const onReceivedConfiguration = ({ err }) => {
|
|
331
|
+
if (err) {
|
|
332
|
+
log.error(err)
|
|
333
|
+
return run.apply(this, arguments)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
skippableSuitesCh.publish({
|
|
337
|
+
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
mochaRunAsyncResource.runInAsyncScope(() => {
|
|
342
|
+
configurationCh.publish({
|
|
343
|
+
onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
|
|
344
|
+
})
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
return Mocha
|
|
348
|
+
})
|
|
349
|
+
|
|
269
350
|
addHook({
|
|
270
351
|
name: 'mocha',
|
|
271
352
|
versions: ['>=5.2.0'],
|
|
@@ -37,13 +37,12 @@ function wrapQuery (query) {
|
|
|
37
37
|
return retval
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const statement = pgQuery.text
|
|
41
40
|
const callbackResource = new AsyncResource('bound-anonymous-fn')
|
|
42
41
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
43
42
|
const processId = this.processID
|
|
44
43
|
|
|
45
44
|
return asyncResource.runInAsyncScope(() => {
|
|
46
|
-
startCh.publish({ params: this.connectionParameters,
|
|
45
|
+
startCh.publish({ params: this.connectionParameters, query: pgQuery, processId })
|
|
47
46
|
|
|
48
47
|
const finish = asyncResource.bind(function (error) {
|
|
49
48
|
if (error) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
|
|
6
|
+
const qsParseCh = channel('datadog:qs:parse:finish')
|
|
7
|
+
|
|
8
|
+
function wrapParse (originalParse) {
|
|
9
|
+
return function () {
|
|
10
|
+
const qsParsedObj = originalParse.apply(this, arguments)
|
|
11
|
+
if (qsParseCh.hasSubscribers && qsParsedObj) {
|
|
12
|
+
qsParseCh.publish({ qs: qsParsedObj })
|
|
13
|
+
}
|
|
14
|
+
return qsParsedObj
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
addHook({
|
|
19
|
+
name: 'qs',
|
|
20
|
+
versions: ['>=1']
|
|
21
|
+
}, qs => {
|
|
22
|
+
shimmer.wrap(qs, 'parse', wrapParse)
|
|
23
|
+
return qs
|
|
24
|
+
})
|
|
@@ -9,6 +9,7 @@ const handleChannel = channel('apm:restify:request:handle')
|
|
|
9
9
|
const errorChannel = channel('apm:restify:middleware:error')
|
|
10
10
|
const enterChannel = channel('apm:restify:middleware:enter')
|
|
11
11
|
const exitChannel = channel('apm:restify:middleware:exit')
|
|
12
|
+
const finishChannel = channel('apm:restify:middleware:finish')
|
|
12
13
|
const nextChannel = channel('apm:restify:middleware:next')
|
|
13
14
|
|
|
14
15
|
function wrapSetupRequest (setupRequest) {
|
|
@@ -53,8 +54,10 @@ function wrapFn (fn) {
|
|
|
53
54
|
} catch (error) {
|
|
54
55
|
errorChannel.publish({ req, error })
|
|
55
56
|
nextChannel.publish({ req })
|
|
56
|
-
|
|
57
|
+
finishChannel.publish({ req })
|
|
57
58
|
throw error
|
|
59
|
+
} finally {
|
|
60
|
+
exitChannel.publish({ req })
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
}
|
|
@@ -62,13 +65,13 @@ function wrapFn (fn) {
|
|
|
62
65
|
function wrapNext (req, next) {
|
|
63
66
|
return function () {
|
|
64
67
|
nextChannel.publish({ req })
|
|
65
|
-
|
|
68
|
+
finishChannel.publish({ req })
|
|
66
69
|
|
|
67
70
|
next.apply(this, arguments)
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
addHook({ name: 'restify', versions: ['>=3'], file: 'lib/server.js' }, Server => {
|
|
74
|
+
addHook({ name: 'restify', versions: ['>=3 <=8.6.1'], file: 'lib/server.js' }, Server => {
|
|
72
75
|
shimmer.wrap(Server.prototype, '_setupRequest', wrapSetupRequest)
|
|
73
76
|
shimmer.massWrap(Server.prototype, handlers, wrapHandler)
|
|
74
77
|
shimmer.massWrap(Server.prototype, methods, wrapMethod)
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
const METHODS = require('methods').concat('all')
|
|
4
4
|
const pathToRegExp = require('path-to-regexp')
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
|
-
const { addHook, channel
|
|
6
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
7
7
|
|
|
8
8
|
function createWrapRouterMethod (name) {
|
|
9
9
|
const enterChannel = channel(`apm:${name}:middleware:enter`)
|
|
10
10
|
const exitChannel = channel(`apm:${name}:middleware:exit`)
|
|
11
|
+
const finishChannel = channel(`apm:${name}:middleware:finish`)
|
|
11
12
|
const errorChannel = channel(`apm:${name}:middleware:error`)
|
|
12
13
|
const nextChannel = channel(`apm:${name}:middleware:next`)
|
|
13
14
|
|
|
@@ -21,7 +22,6 @@ function createWrapRouterMethod (name) {
|
|
|
21
22
|
if (!enterChannel.hasSubscribers) return original.apply(this, arguments)
|
|
22
23
|
|
|
23
24
|
const matchers = layerMatchers.get(layer)
|
|
24
|
-
const middlewareResource = new AsyncResource('bound-anonymous-fn')
|
|
25
25
|
const lastIndex = arguments.length - 1
|
|
26
26
|
const name = original._name || original.name
|
|
27
27
|
const req = arguments[arguments.length > 3 ? 1 : 0]
|
|
@@ -31,32 +31,32 @@ function createWrapRouterMethod (name) {
|
|
|
31
31
|
arguments[lastIndex] = wrapNext(req, next)
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
let route
|
|
34
|
+
let route
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
if (matchers) {
|
|
37
|
+
// Try to guess which path actually matched
|
|
38
|
+
for (let i = 0; i < matchers.length; i++) {
|
|
39
|
+
if (matchers[i].test(layer)) {
|
|
40
|
+
route = matchers[i].path
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
}
|
|
42
|
+
break
|
|
45
43
|
}
|
|
46
44
|
}
|
|
45
|
+
}
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
enterChannel.publish({ name, req, route })
|
|
49
48
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
try {
|
|
50
|
+
return original.apply(this, arguments)
|
|
51
|
+
} catch (error) {
|
|
52
|
+
errorChannel.publish({ req, error })
|
|
53
|
+
nextChannel.publish({ req })
|
|
54
|
+
finishChannel.publish({ req })
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
throw error
|
|
57
|
+
} finally {
|
|
58
|
+
exitChannel.publish({ req })
|
|
59
|
+
}
|
|
60
60
|
})
|
|
61
61
|
|
|
62
62
|
// This is a workaround for the `loopback` library so that it can find the correct express layer
|
|
@@ -95,7 +95,7 @@ function createWrapRouterMethod (name) {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
nextChannel.publish({ req })
|
|
98
|
-
|
|
98
|
+
finishChannel.publish({ req })
|
|
99
99
|
|
|
100
100
|
next.apply(this, arguments)
|
|
101
101
|
}
|