dd-trace 2.21.0 → 2.22.0
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 +11 -0
- 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/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/jest.js +102 -42
- 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 +1 -1
- 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 +3 -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 +2 -0
- 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 +9 -8
- package/packages/dd-trace/src/proxy.js +5 -1
- package/packages/dd-trace/src/tracer.js +4 -3
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
Component,Origin,License,Copyright
|
|
2
2
|
require,@datadog/native-appsec,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
3
3
|
require,@datadog/native-metrics,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
4
|
+
require,@datadog/native-iast-rewriter,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
5
|
+
require,@datadog/native-iast-taint-tracking,Apache license 2.0,Copyright 2018 Datadog Inc.
|
|
4
6
|
require,@datadog/pprof,Apache license 2.0,Copyright 2019 Google Inc.
|
|
5
7
|
require,@datadog/sketches-js,Apache license 2.0,Copyright 2020 Datadog Inc.
|
|
6
8
|
require,@types/node,MIT,Copyright Authors
|
package/index.d.ts
CHANGED
|
@@ -167,6 +167,11 @@ export declare interface SpanContext extends opentracing.SpanContext {
|
|
|
167
167
|
* Returns the string representation of the internal span ID.
|
|
168
168
|
*/
|
|
169
169
|
toSpanId(): string;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Returns the string representation used for DBM integration.
|
|
173
|
+
*/
|
|
174
|
+
toTraceparent(): string;
|
|
170
175
|
}
|
|
171
176
|
|
|
172
177
|
/**
|
|
@@ -463,6 +468,12 @@ export declare interface TracerOptions {
|
|
|
463
468
|
*/
|
|
464
469
|
orphanable?: boolean
|
|
465
470
|
|
|
471
|
+
/**
|
|
472
|
+
* Enables DBM to APM link using tag injection.
|
|
473
|
+
* @default 'disabled'
|
|
474
|
+
*/
|
|
475
|
+
dbmPropagationMode?: 'disabled' | 'service' | 'full'
|
|
476
|
+
|
|
466
477
|
/**
|
|
467
478
|
* Configuration of the AppSec protection. Can be a boolean as an alias to `appsec.enabled`.
|
|
468
479
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.22.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -58,7 +58,9 @@
|
|
|
58
58
|
"node": ">=12"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@datadog/native-appsec": "
|
|
61
|
+
"@datadog/native-appsec": "2.0.0",
|
|
62
|
+
"@datadog/native-iast-rewriter": "1.0.0",
|
|
63
|
+
"@datadog/native-iast-taint-tracking": "1.0.0",
|
|
62
64
|
"@datadog/native-metrics": "^1.5.0",
|
|
63
65
|
"@datadog/pprof": "^1.1.1",
|
|
64
66
|
"@datadog/sketches-js": "^2.1.0",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
4
|
+
|
|
5
|
+
const bodyParserReadCh = channel('datadog:body-parser:read:finish')
|
|
6
|
+
|
|
7
|
+
function publishRequestBodyAndNext (request, next) {
|
|
8
|
+
return function () {
|
|
9
|
+
if (bodyParserReadCh.hasSubscribers && request) {
|
|
10
|
+
bodyParserReadCh.publish({ request })
|
|
11
|
+
}
|
|
12
|
+
next.apply(this, arguments)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
addHook({
|
|
17
|
+
name: 'body-parser',
|
|
18
|
+
file: 'lib/read.js',
|
|
19
|
+
versions: ['>=1']
|
|
20
|
+
}, read => {
|
|
21
|
+
return function (req, res, next) {
|
|
22
|
+
const nextResource = new AsyncResource('bound-anonymous-fn')
|
|
23
|
+
arguments[2] = nextResource.bind(publishRequestBodyAndNext(req, next))
|
|
24
|
+
read.apply(this, arguments)
|
|
25
|
+
}
|
|
26
|
+
})
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook
|
|
6
|
+
} = require('./helpers/instrument')
|
|
7
|
+
const shimmer = require('../../datadog-shimmer')
|
|
8
|
+
|
|
9
|
+
const childProcessChannel = channel('datadog:child_process:execution:start')
|
|
10
|
+
const execMethods = ['exec', 'execFile', 'fork', 'spawn', 'execFileSync', 'execSync', 'spawnSync']
|
|
11
|
+
const names = ['child_process', 'node:child_process']
|
|
12
|
+
names.forEach(name => {
|
|
13
|
+
addHook({ name }, childProcess => {
|
|
14
|
+
shimmer.massWrap(childProcess, execMethods, wrapChildProcessMethod())
|
|
15
|
+
return childProcess
|
|
16
|
+
})
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
function wrapChildProcessMethod () {
|
|
20
|
+
function wrapMethod (childProcessMethod) {
|
|
21
|
+
return function () {
|
|
22
|
+
if (childProcessChannel.hasSubscribers && arguments.length > 0) {
|
|
23
|
+
const command = arguments[0]
|
|
24
|
+
childProcessChannel.publish({ command })
|
|
25
|
+
}
|
|
26
|
+
return childProcessMethod.apply(this, arguments)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return wrapMethod
|
|
30
|
+
}
|
|
@@ -50,7 +50,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
50
50
|
|
|
51
51
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
52
52
|
return asyncResource.runInAsyncScope(() => {
|
|
53
|
-
runStartCh.publish({
|
|
53
|
+
runStartCh.publish({ testName: this.pickle.name, fullTestSuite: this.pickle.uri })
|
|
54
54
|
try {
|
|
55
55
|
const promise = run.apply(this, arguments)
|
|
56
56
|
promise.finally(() => {
|
|
@@ -142,19 +142,19 @@ function reply (request, h) {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
addHook({ name: '@hapi/hapi', versions: ['>=17.9'] }, hapi => {
|
|
145
|
+
addHook({ name: '@hapi/hapi', versions: ['>=17.9 <=20.2.1'] }, hapi => {
|
|
146
146
|
shimmer.massWrap(hapi, ['server', 'Server'], wrapServer)
|
|
147
147
|
|
|
148
148
|
return hapi
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
addHook({ name: '@hapi/hapi', versions: ['>=17.9'], file: 'lib/core.js' }, Core => {
|
|
151
|
+
addHook({ name: '@hapi/hapi', versions: ['>=17.9 <=20.2.1'], file: 'lib/core.js' }, Core => {
|
|
152
152
|
shimmer.wrap(Core.prototype, '_dispatch', wrapDispatch)
|
|
153
153
|
|
|
154
154
|
return Core
|
|
155
155
|
})
|
|
156
156
|
|
|
157
|
-
addHook({ name: '@hapi/hapi', versions: ['>=17.9'], file: 'lib/route.js' }, Route => {
|
|
157
|
+
addHook({ name: '@hapi/hapi', versions: ['>=17.9 <=20.2.1'], file: 'lib/route.js' }, Route => {
|
|
158
158
|
shimmer.wrap(Route.prototype, 'rebuild', wrapRebuild)
|
|
159
159
|
|
|
160
160
|
return Route
|
|
@@ -8,6 +8,7 @@ module.exports = {
|
|
|
8
8
|
'@grpc/grpc-js': () => require('../grpc'),
|
|
9
9
|
'@hapi/hapi': () => require('../hapi'),
|
|
10
10
|
'@jest/core': () => require('../jest'),
|
|
11
|
+
'@jest/reporters': () => require('../jest'),
|
|
11
12
|
'@koa/router': () => require('../koa'),
|
|
12
13
|
'@node-redis/client': () => require('../redis'),
|
|
13
14
|
'@opensearch-project/opensearch': () => require('../opensearch'),
|
|
@@ -16,8 +17,11 @@ module.exports = {
|
|
|
16
17
|
'amqplib': () => require('../amqplib'),
|
|
17
18
|
'aws-sdk': () => require('../aws-sdk'),
|
|
18
19
|
'bluebird': () => require('../bluebird'),
|
|
20
|
+
'body-parser': () => require('../body-parser'),
|
|
19
21
|
'bunyan': () => require('../bunyan'),
|
|
20
22
|
'cassandra-driver': () => require('../cassandra-driver'),
|
|
23
|
+
'child_process': () => require('../child-process'),
|
|
24
|
+
'node:child_process': () => require('../child-process'),
|
|
21
25
|
'connect': () => require('../connect'),
|
|
22
26
|
'couchbase': () => require('../couchbase'),
|
|
23
27
|
'crypto': () => require('../crypto'),
|
|
@@ -65,6 +69,7 @@ module.exports = {
|
|
|
65
69
|
'promise-js': () => require('../promise-js'),
|
|
66
70
|
'promise': () => require('../promise'),
|
|
67
71
|
'q': () => require('../q'),
|
|
72
|
+
'qs': () => require('../qs'),
|
|
68
73
|
'redis': () => require('../redis'),
|
|
69
74
|
'restify': () => require('../restify'),
|
|
70
75
|
'rhea': () => require('../rhea'),
|
|
@@ -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,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
|
+
})
|
|
@@ -68,7 +68,7 @@ function wrapNext (req, next) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
addHook({ name: 'restify', versions: ['>=3'], file: 'lib/server.js' }, Server => {
|
|
71
|
+
addHook({ name: 'restify', versions: ['>=3 <=8.6.1'], file: 'lib/server.js' }, Server => {
|
|
72
72
|
shimmer.wrap(Server.prototype, '_setupRequest', wrapSetupRequest)
|
|
73
73
|
shimmer.massWrap(Server.prototype, handlers, wrapHandler)
|
|
74
74
|
shimmer.massWrap(Server.prototype, methods, wrapMethod)
|