dd-trace 3.7.1 → 3.9.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/helpers/hooks.js +5 -0
- package/packages/datadog-instrumentations/src/jest.js +110 -40
- 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-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 +14 -4
- package/packages/datadog-plugin-http/src/server.js +3 -0
- package/packages/datadog-plugin-http2/src/client.js +20 -1
- package/packages/datadog-plugin-http2/src/server.js +3 -0
- package/packages/datadog-plugin-jest/src/index.js +11 -129
- 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-oracledb/src/index.js +0 -1
- 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 +3 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +3 -4
- package/packages/dd-trace/src/config.js +41 -20
- 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 +6 -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 +4 -3
- package/packages/dd-trace/src/span_processor.js +1 -0
- 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,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
|
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": "3.
|
|
3
|
+
"version": "3.9.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": ">=14"
|
|
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(() => {
|
|
@@ -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'),
|
|
@@ -64,6 +68,7 @@ module.exports = {
|
|
|
64
68
|
'promise-js': () => require('../promise-js'),
|
|
65
69
|
'promise': () => require('../promise'),
|
|
66
70
|
'q': () => require('../q'),
|
|
71
|
+
'qs': () => require('../qs'),
|
|
67
72
|
'redis': () => require('../redis'),
|
|
68
73
|
'restify': () => require('../restify'),
|
|
69
74
|
'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',
|
|
@@ -263,6 +282,9 @@ function jestAdapterWrapper (jestAdapter) {
|
|
|
263
282
|
const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
|
|
264
283
|
const newAdapter = shimmer.wrap(adapter, function () {
|
|
265
284
|
const environment = arguments[2]
|
|
285
|
+
if (!environment) {
|
|
286
|
+
return adapter.apply(this, arguments)
|
|
287
|
+
}
|
|
266
288
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
267
289
|
return asyncResource.runInAsyncScope(() => {
|
|
268
290
|
testSuiteStartCh.publish({
|
|
@@ -278,11 +300,16 @@ function jestAdapterWrapper (jestAdapter) {
|
|
|
278
300
|
status = 'fail'
|
|
279
301
|
}
|
|
280
302
|
testSuiteFinishCh.publish({ status, errorMessage })
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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(() => {
|
|
284
311
|
testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
|
|
285
|
-
}
|
|
312
|
+
})
|
|
286
313
|
}
|
|
287
314
|
return suiteResults
|
|
288
315
|
})
|
|
@@ -305,15 +332,15 @@ addHook({
|
|
|
305
332
|
|
|
306
333
|
function configureTestEnvironment (readConfigsResult) {
|
|
307
334
|
const { configs } = readConfigsResult
|
|
308
|
-
configs.forEach(config => {
|
|
309
|
-
skippableSuites.forEach((suite) => {
|
|
310
|
-
config.testMatch.push(`!**/${suite}`)
|
|
311
|
-
})
|
|
312
|
-
skippableSuites = []
|
|
313
|
-
})
|
|
314
335
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
315
336
|
testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
|
|
316
337
|
})
|
|
338
|
+
// We can't directly use isCodeCoverageEnabled when reporting coverage in `jestAdapterWrapper`
|
|
339
|
+
// because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
|
|
340
|
+
configs.forEach(config => {
|
|
341
|
+
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
|
|
342
|
+
})
|
|
343
|
+
|
|
317
344
|
if (isCodeCoverageEnabled) {
|
|
318
345
|
const globalConfig = {
|
|
319
346
|
...readConfigsResult.globalConfig,
|
|
@@ -321,6 +348,16 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
321
348
|
}
|
|
322
349
|
readConfigsResult.globalConfig = globalConfig
|
|
323
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
|
+
|
|
324
361
|
return readConfigsResult
|
|
325
362
|
}
|
|
326
363
|
|
|
@@ -342,6 +379,39 @@ function jestConfigSyncWrapper (jestConfig) {
|
|
|
342
379
|
return jestConfig
|
|
343
380
|
}
|
|
344
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
|
+
|
|
345
415
|
// from 25.1.0 on, readConfigs becomes async
|
|
346
416
|
addHook({
|
|
347
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
|
+
})
|
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const CiPlugin = require('../../dd-trace/src/plugins/ci_plugin')
|
|
4
4
|
const { storage } = require('../../datadog-core')
|
|
5
5
|
|
|
6
6
|
const {
|
|
7
|
-
CI_APP_ORIGIN,
|
|
8
7
|
TEST_SKIP_REASON,
|
|
9
|
-
ERROR_MESSAGE,
|
|
10
8
|
TEST_STATUS,
|
|
11
|
-
TEST_CODE_OWNERS,
|
|
12
9
|
finishAllTraceSpans,
|
|
13
|
-
|
|
14
|
-
getTestSuitePath,
|
|
15
|
-
getCodeOwnersFileEntries,
|
|
16
|
-
getCodeOwnersForFilename,
|
|
17
|
-
getTestCommonTags
|
|
10
|
+
getTestSuitePath
|
|
18
11
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
19
12
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
13
|
+
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
20
14
|
|
|
21
|
-
class CucumberPlugin extends
|
|
15
|
+
class CucumberPlugin extends CiPlugin {
|
|
22
16
|
static get name () {
|
|
23
17
|
return 'cucumber'
|
|
24
18
|
}
|
|
@@ -26,36 +20,18 @@ class CucumberPlugin extends Plugin {
|
|
|
26
20
|
constructor (...args) {
|
|
27
21
|
super(...args)
|
|
28
22
|
|
|
29
|
-
const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber', this.config)
|
|
30
|
-
const sourceRoot = process.cwd()
|
|
31
|
-
const codeOwnersEntries = getCodeOwnersFileEntries(sourceRoot)
|
|
32
|
-
|
|
33
23
|
this.addSub('ci:cucumber:session:finish', () => {
|
|
34
24
|
this.tracer._exporter._writer.flush()
|
|
35
25
|
})
|
|
36
26
|
|
|
37
|
-
this.addSub('ci:cucumber:run:start', ({
|
|
27
|
+
this.addSub('ci:cucumber:run:start', ({ testName, fullTestSuite }) => {
|
|
38
28
|
const store = storage.getStore()
|
|
39
29
|
const childOf = store ? store.span : store
|
|
40
|
-
const testSuite = getTestSuitePath(
|
|
41
|
-
|
|
42
|
-
const commonTags = getTestCommonTags(pickleName, testSuite, this.tracer._version)
|
|
30
|
+
const testSuite = getTestSuitePath(fullTestSuite, process.cwd())
|
|
43
31
|
|
|
44
|
-
const
|
|
45
|
-
if (codeOwners) {
|
|
46
|
-
commonTags[TEST_CODE_OWNERS] = codeOwners
|
|
47
|
-
}
|
|
32
|
+
const testSpan = this.startTestSpan(testName, testSuite, childOf)
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
childOf,
|
|
51
|
-
tags: {
|
|
52
|
-
...commonTags,
|
|
53
|
-
...testEnvironmentMetadata
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
span.context()._trace.origin = CI_APP_ORIGIN
|
|
58
|
-
this.enter(span, store)
|
|
34
|
+
this.enter(testSpan, store)
|
|
59
35
|
})
|
|
60
36
|
|
|
61
37
|
this.addSub('ci:cucumber:run-step:start', ({ resource }) => {
|
|
@@ -64,6 +40,7 @@ class CucumberPlugin extends Plugin {
|
|
|
64
40
|
const span = this.tracer.startSpan('cucumber.step', {
|
|
65
41
|
childOf,
|
|
66
42
|
tags: {
|
|
43
|
+
[COMPONENT]: this.constructor.name,
|
|
67
44
|
'cucumber.step': resource,
|
|
68
45
|
[RESOURCE_NAME]: resource
|
|
69
46
|
}
|
|
@@ -98,6 +75,10 @@ class CucumberPlugin extends Plugin {
|
|
|
98
75
|
}
|
|
99
76
|
})
|
|
100
77
|
}
|
|
78
|
+
|
|
79
|
+
startTestSpan (testName, testSuite, childOf) {
|
|
80
|
+
return super.startTestSpan(testName, testSuite, {}, childOf)
|
|
81
|
+
}
|
|
101
82
|
}
|
|
102
83
|
|
|
103
84
|
module.exports = CucumberPlugin
|