dd-trace 4.43.0 → 4.45.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/ext/formats.d.ts +1 -0
- package/ext/formats.js +2 -1
- package/index.d.ts +2 -1
- package/init.js +3 -15
- package/package.json +4 -3
- package/packages/datadog-instrumentations/src/body-parser.js +14 -2
- package/packages/datadog-instrumentations/src/cucumber.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +21 -12
- package/packages/datadog-instrumentations/src/http/client.js +7 -1
- package/packages/datadog-instrumentations/src/http/server.js +50 -13
- package/packages/datadog-instrumentations/src/mocha/main.js +111 -78
- package/packages/datadog-instrumentations/src/nyc.js +23 -0
- package/packages/datadog-instrumentations/src/process.js +29 -0
- package/packages/datadog-instrumentations/src/vitest.js +65 -25
- package/packages/datadog-plugin-aws-sdk/src/base.js +15 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +3 -3
- package/packages/datadog-plugin-cucumber/src/index.js +12 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +53 -12
- package/packages/datadog-plugin-jest/src/index.js +17 -4
- package/packages/datadog-plugin-mocha/src/index.js +25 -6
- package/packages/datadog-plugin-nyc/src/index.js +35 -0
- package/packages/datadog-plugin-playwright/src/index.js +9 -4
- package/packages/datadog-plugin-vitest/src/index.js +32 -5
- package/packages/dd-trace/src/appsec/blocking.js +10 -1
- package/packages/dd-trace/src/appsec/channels.js +4 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +16 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +11 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/code-injection-sensitive-analyzer.js +25 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +12 -7
- package/packages/dd-trace/src/appsec/rasp.js +121 -7
- package/packages/dd-trace/src/appsec/recommended.json +220 -2
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +40 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -4
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -4
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +8 -7
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -4
- package/packages/dd-trace/src/ci-visibility/telemetry.js +29 -2
- package/packages/dd-trace/src/config.js +158 -153
- package/packages/dd-trace/src/data_streams.js +44 -0
- package/packages/dd-trace/src/datastreams/pathway.js +4 -2
- package/packages/dd-trace/src/log/index.js +32 -0
- package/packages/dd-trace/src/opentelemetry/context_manager.js +22 -39
- package/packages/dd-trace/src/opentelemetry/span_context.js +2 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +23 -14
- package/packages/dd-trace/src/opentelemetry/tracer_provider.js +9 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +60 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +43 -0
- package/packages/dd-trace/src/opentracing/span_context.js +1 -0
- package/packages/dd-trace/src/opentracing/tracer.js +10 -6
- package/packages/dd-trace/src/plugins/ci_plugin.js +11 -4
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +12 -1
- package/packages/dd-trace/src/plugins/util/git.js +14 -1
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/telemetry/index.js +1 -1
- package/packages/dd-trace/src/tracer.js +2 -0
package/ext/formats.d.ts
CHANGED
package/ext/formats.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -1837,9 +1837,10 @@ declare namespace tracer {
|
|
|
1837
1837
|
/**
|
|
1838
1838
|
* Construct a new TracerProvider to register with @opentelemetry/api
|
|
1839
1839
|
*
|
|
1840
|
+
* @param config Configuration object for the TracerProvider
|
|
1840
1841
|
* @returns TracerProvider A TracerProvider instance
|
|
1841
1842
|
*/
|
|
1842
|
-
new(): TracerProvider;
|
|
1843
|
+
new(config?: Record<string, unknown>): TracerProvider;
|
|
1843
1844
|
|
|
1844
1845
|
/**
|
|
1845
1846
|
* Returns a Tracer, creating one if one with the given name and version is
|
package/init.js
CHANGED
|
@@ -2,22 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const Module = require('module')
|
|
5
|
-
const telemetry = require('./packages/dd-trace/src/telemetry/init-telemetry')
|
|
6
5
|
const semver = require('semver')
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line no-console
|
|
13
|
-
let log = { info: isTrue(process.env.DD_TRACE_DEBUG) ? console.log : () => {} }
|
|
14
|
-
if (semver.satisfies(process.versions.node, '>=16')) {
|
|
15
|
-
const Config = require('./packages/dd-trace/src/config')
|
|
16
|
-
log = require('./packages/dd-trace/src/log')
|
|
17
|
-
|
|
18
|
-
// eslint-disable-next-line no-new
|
|
19
|
-
new Config() // we need this to initialize the logger
|
|
20
|
-
}
|
|
6
|
+
const log = require('./packages/dd-trace/src/log')
|
|
7
|
+
const { isTrue } = require('./packages/dd-trace/src/util')
|
|
8
|
+
const telemetry = require('./packages/dd-trace/src/telemetry/init-telemetry')
|
|
21
9
|
|
|
22
10
|
let initBailout = false
|
|
23
11
|
let clobberBailout = false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.45.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"test:profiler": "tap \"packages/dd-trace/test/profiling/**/*.spec.js\"",
|
|
34
34
|
"test:profiler:ci": "npm run test:profiler -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/profiling/**/*.js\"",
|
|
35
35
|
"test:integration": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/*.spec.js\"",
|
|
36
|
+
"test:integration:appsec": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/appsec/*.spec.js\"",
|
|
36
37
|
"test:integration:cucumber": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cucumber/*.spec.js\"",
|
|
37
38
|
"test:integration:cypress": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/cypress/*.spec.js\"",
|
|
38
39
|
"test:integration:jest": "mocha --timeout 60000 -r \"packages/dd-trace/test/setup/core.js\" \"integration-tests/jest/*.spec.js\"",
|
|
@@ -72,8 +73,8 @@
|
|
|
72
73
|
},
|
|
73
74
|
"dependencies": {
|
|
74
75
|
"@datadog/native-appsec": "8.0.1",
|
|
75
|
-
"@datadog/native-iast-rewriter": "2.
|
|
76
|
-
"@datadog/native-iast-taint-tracking": "3.
|
|
76
|
+
"@datadog/native-iast-rewriter": "2.4.1",
|
|
77
|
+
"@datadog/native-iast-taint-tracking": "3.1.0",
|
|
77
78
|
"@datadog/native-metrics": "^2.0.0",
|
|
78
79
|
"@datadog/pprof": "5.3.0",
|
|
79
80
|
"@datadog/sketches-js": "^2.1.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { channel, addHook } = require('./helpers/instrument')
|
|
4
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const bodyParserReadCh = channel('datadog:body-parser:read:finish')
|
|
7
7
|
|
|
@@ -23,7 +23,19 @@ function publishRequestBodyAndNext (req, res, next) {
|
|
|
23
23
|
addHook({
|
|
24
24
|
name: 'body-parser',
|
|
25
25
|
file: 'lib/read.js',
|
|
26
|
-
versions: ['>=1.4.0']
|
|
26
|
+
versions: ['>=1.4.0 <1.20.0']
|
|
27
|
+
}, read => {
|
|
28
|
+
return shimmer.wrap(read, function (req, res, next) {
|
|
29
|
+
const nextResource = new AsyncResource('bound-anonymous-fn')
|
|
30
|
+
arguments[2] = nextResource.bind(publishRequestBodyAndNext(req, res, next))
|
|
31
|
+
return read.apply(this, arguments)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
addHook({
|
|
36
|
+
name: 'body-parser',
|
|
37
|
+
file: 'lib/read.js',
|
|
38
|
+
versions: ['>=1.20.0']
|
|
27
39
|
}, read => {
|
|
28
40
|
return shimmer.wrap(read, function (req, res, next) {
|
|
29
41
|
arguments[2] = publishRequestBodyAndNext(req, res, next)
|
|
@@ -28,6 +28,8 @@ const workerReportTraceCh = channel('ci:cucumber:worker-report:trace')
|
|
|
28
28
|
|
|
29
29
|
const itrSkippedSuitesCh = channel('ci:cucumber:itr:skipped-suites')
|
|
30
30
|
|
|
31
|
+
const getCodeCoverageCh = channel('ci:nyc:get-coverage')
|
|
32
|
+
|
|
31
33
|
const {
|
|
32
34
|
getCoveredFilenamesFromCoverage,
|
|
33
35
|
resetCoverage,
|
|
@@ -356,10 +358,18 @@ function getWrappedStart (start, frameworkVersion, isParallel = false) {
|
|
|
356
358
|
|
|
357
359
|
const success = await start.apply(this, arguments)
|
|
358
360
|
|
|
361
|
+
let untestedCoverage
|
|
362
|
+
if (getCodeCoverageCh.hasSubscribers) {
|
|
363
|
+
untestedCoverage = await getChannelPromise(getCodeCoverageCh)
|
|
364
|
+
}
|
|
365
|
+
|
|
359
366
|
let testCodeCoverageLinesTotal
|
|
360
367
|
|
|
361
368
|
if (global.__coverage__) {
|
|
362
369
|
try {
|
|
370
|
+
if (untestedCoverage) {
|
|
371
|
+
originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
|
|
372
|
+
}
|
|
363
373
|
testCodeCoverageLinesTotal = originalCoverageMap.getCoverageSummary().lines.pct
|
|
364
374
|
} catch (e) {
|
|
365
375
|
// ignore errors
|
|
@@ -72,7 +72,6 @@ module.exports = {
|
|
|
72
72
|
'microgateway-core': () => require('../microgateway-core'),
|
|
73
73
|
mocha: () => require('../mocha'),
|
|
74
74
|
'mocha-each': () => require('../mocha'),
|
|
75
|
-
workerpool: () => require('../mocha'),
|
|
76
75
|
moleculer: () => require('../moleculer'),
|
|
77
76
|
mongodb: () => require('../mongodb'),
|
|
78
77
|
'mongodb-core': () => require('../mongodb-core'),
|
|
@@ -89,6 +88,7 @@ module.exports = {
|
|
|
89
88
|
'node:http2': () => require('../http2'),
|
|
90
89
|
'node:https': () => require('../http'),
|
|
91
90
|
'node:net': () => require('../net'),
|
|
91
|
+
nyc: () => require('../nyc'),
|
|
92
92
|
oracledb: () => require('../oracledb'),
|
|
93
93
|
openai: () => require('../openai'),
|
|
94
94
|
paperplane: () => require('../paperplane'),
|
|
@@ -113,5 +113,6 @@ module.exports = {
|
|
|
113
113
|
undici: () => require('../undici'),
|
|
114
114
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
115
115
|
when: () => require('../when'),
|
|
116
|
-
winston: () => require('../winston')
|
|
116
|
+
winston: () => require('../winston'),
|
|
117
|
+
workerpool: () => require('../mocha')
|
|
117
118
|
}
|
|
@@ -29,6 +29,10 @@ if (!disabledInstrumentations.has('fetch')) {
|
|
|
29
29
|
require('../fetch')
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
if (!disabledInstrumentations.has('process')) {
|
|
33
|
+
require('../process')
|
|
34
|
+
}
|
|
35
|
+
|
|
32
36
|
const HOOK_SYMBOL = Symbol('hookExportsMap')
|
|
33
37
|
|
|
34
38
|
if (DD_TRACE_DEBUG && DD_TRACE_DEBUG.toLowerCase() !== 'false') {
|
|
@@ -86,18 +90,22 @@ for (const packageName of names) {
|
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
if (matchesFile) {
|
|
89
|
-
|
|
93
|
+
let version = moduleVersion
|
|
94
|
+
try {
|
|
95
|
+
version = version || getVersion(moduleBaseDir)
|
|
96
|
+
} catch (e) {
|
|
97
|
+
log.error(`Error getting version for "${name}": ${e.message}`)
|
|
98
|
+
log.error(e)
|
|
99
|
+
continue
|
|
100
|
+
}
|
|
90
101
|
if (!Object.hasOwnProperty(namesAndSuccesses, name)) {
|
|
91
|
-
namesAndSuccesses[name] =
|
|
92
|
-
success: false,
|
|
93
|
-
version
|
|
94
|
-
}
|
|
102
|
+
namesAndSuccesses[`${name}@${version}`] = false
|
|
95
103
|
}
|
|
96
104
|
|
|
97
105
|
if (matchVersion(version, versions)) {
|
|
98
106
|
// Check if the hook already has a set moduleExport
|
|
99
107
|
if (hook[HOOK_SYMBOL].has(moduleExports)) {
|
|
100
|
-
namesAndSuccesses[name]
|
|
108
|
+
namesAndSuccesses[`${name}@${version}`] = true
|
|
101
109
|
return moduleExports
|
|
102
110
|
}
|
|
103
111
|
|
|
@@ -117,19 +125,20 @@ for (const packageName of names) {
|
|
|
117
125
|
`integration_version:${version}`
|
|
118
126
|
])
|
|
119
127
|
}
|
|
120
|
-
namesAndSuccesses[name]
|
|
128
|
+
namesAndSuccesses[`${name}@${version}`] = true
|
|
121
129
|
}
|
|
122
130
|
}
|
|
123
131
|
}
|
|
124
|
-
for (const
|
|
125
|
-
const
|
|
126
|
-
|
|
132
|
+
for (const nameVersion of Object.keys(namesAndSuccesses)) {
|
|
133
|
+
const [name, version] = nameVersion.split('@')
|
|
134
|
+
const success = namesAndSuccesses[nameVersion]
|
|
135
|
+
if (!success && !seenCombo.has(nameVersion)) {
|
|
127
136
|
telemetry('abort.integration', [
|
|
128
137
|
`integration:${name}`,
|
|
129
138
|
`integration_version:${version}`
|
|
130
139
|
])
|
|
131
|
-
log.info(`Found incompatible integration version: ${
|
|
132
|
-
seenCombo.add(
|
|
140
|
+
log.info(`Found incompatible integration version: ${nameVersion}`)
|
|
141
|
+
seenCombo.add(nameVersion)
|
|
133
142
|
}
|
|
134
143
|
}
|
|
135
144
|
|
|
@@ -43,7 +43,9 @@ function patch (http, methodName) {
|
|
|
43
43
|
return request.apply(this, arguments)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const abortController = new AbortController()
|
|
47
|
+
|
|
48
|
+
const ctx = { args, http, abortController }
|
|
47
49
|
|
|
48
50
|
return startChannel.runStores(ctx, () => {
|
|
49
51
|
let finished = false
|
|
@@ -107,6 +109,10 @@ function patch (http, methodName) {
|
|
|
107
109
|
return emit.apply(this, arguments)
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
if (abortController.signal.aborted) {
|
|
113
|
+
req.destroy(abortController.signal.reason || new Error('Aborted'))
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
return req
|
|
111
117
|
} catch (e) {
|
|
112
118
|
ctx.error = e
|
|
@@ -12,6 +12,7 @@ const errorServerCh = channel('apm:http:server:request:error')
|
|
|
12
12
|
const finishServerCh = channel('apm:http:server:request:finish')
|
|
13
13
|
const startWriteHeadCh = channel('apm:http:server:response:writeHead:start')
|
|
14
14
|
const finishSetHeaderCh = channel('datadog:http:server:response:set-header:finish')
|
|
15
|
+
const startSetHeaderCh = channel('datadog:http:server:response:set-header:start')
|
|
15
16
|
|
|
16
17
|
const requestFinishedSet = new WeakSet()
|
|
17
18
|
|
|
@@ -24,6 +25,12 @@ addHook({ name: httpNames }, http => {
|
|
|
24
25
|
shimmer.wrap(http.ServerResponse.prototype, 'writeHead', wrapWriteHead)
|
|
25
26
|
shimmer.wrap(http.ServerResponse.prototype, 'write', wrapWrite)
|
|
26
27
|
shimmer.wrap(http.ServerResponse.prototype, 'end', wrapEnd)
|
|
28
|
+
shimmer.wrap(http.ServerResponse.prototype, 'setHeader', wrapSetHeader)
|
|
29
|
+
shimmer.wrap(http.ServerResponse.prototype, 'removeHeader', wrapAppendOrRemoveHeader)
|
|
30
|
+
// Added in node v16.17.0
|
|
31
|
+
if (http.ServerResponse.prototype.appendHeader) {
|
|
32
|
+
shimmer.wrap(http.ServerResponse.prototype, 'appendHeader', wrapAppendOrRemoveHeader)
|
|
33
|
+
}
|
|
27
34
|
return http
|
|
28
35
|
})
|
|
29
36
|
|
|
@@ -65,9 +72,7 @@ function wrapEmit (emit) {
|
|
|
65
72
|
// TODO: should this always return true ?
|
|
66
73
|
return this.listenerCount(eventName) > 0
|
|
67
74
|
}
|
|
68
|
-
|
|
69
|
-
wrapSetHeader(res)
|
|
70
|
-
}
|
|
75
|
+
|
|
71
76
|
return emit.apply(this, arguments)
|
|
72
77
|
} catch (err) {
|
|
73
78
|
errorServerCh.publish(err)
|
|
@@ -81,16 +86,6 @@ function wrapEmit (emit) {
|
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
function wrapSetHeader (res) {
|
|
85
|
-
shimmer.wrap(res, 'setHeader', setHeader => {
|
|
86
|
-
return function (name, value) {
|
|
87
|
-
const setHeaderResult = setHeader.apply(this, arguments)
|
|
88
|
-
finishSetHeaderCh.publish({ name, value, res })
|
|
89
|
-
return setHeaderResult
|
|
90
|
-
}
|
|
91
|
-
})
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
function wrapWriteHead (writeHead) {
|
|
95
90
|
return function wrappedWriteHead (statusCode, reason, obj) {
|
|
96
91
|
if (!startWriteHeadCh.hasSubscribers) {
|
|
@@ -159,6 +154,48 @@ function wrapWrite (write) {
|
|
|
159
154
|
}
|
|
160
155
|
}
|
|
161
156
|
|
|
157
|
+
function wrapSetHeader (setHeader) {
|
|
158
|
+
return function wrappedSetHeader (name, value) {
|
|
159
|
+
if (!startSetHeaderCh.hasSubscribers && !finishSetHeaderCh.hasSubscribers) {
|
|
160
|
+
return setHeader.apply(this, arguments)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (startSetHeaderCh.hasSubscribers) {
|
|
164
|
+
const abortController = new AbortController()
|
|
165
|
+
startSetHeaderCh.publish({ res: this, abortController })
|
|
166
|
+
|
|
167
|
+
if (abortController.signal.aborted) {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const setHeaderResult = setHeader.apply(this, arguments)
|
|
173
|
+
|
|
174
|
+
if (finishSetHeaderCh.hasSubscribers) {
|
|
175
|
+
finishSetHeaderCh.publish({ name, value, res: this })
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return setHeaderResult
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function wrapAppendOrRemoveHeader (originalMethod) {
|
|
183
|
+
return function wrappedAppendOrRemoveHeader () {
|
|
184
|
+
if (!startSetHeaderCh.hasSubscribers) {
|
|
185
|
+
return originalMethod.apply(this, arguments)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const abortController = new AbortController()
|
|
189
|
+
startSetHeaderCh.publish({ res: this, abortController })
|
|
190
|
+
|
|
191
|
+
if (abortController.signal.aborted) {
|
|
192
|
+
return this
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return originalMethod.apply(this, arguments)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
162
199
|
function wrapEnd (end) {
|
|
163
200
|
return function wrappedEnd () {
|
|
164
201
|
if (!startWriteHeadCh.hasSubscribers) {
|
|
@@ -47,6 +47,7 @@ const config = {}
|
|
|
47
47
|
|
|
48
48
|
// We'll preserve the original coverage here
|
|
49
49
|
const originalCoverageMap = createCoverageMap()
|
|
50
|
+
let untestedCoverage
|
|
50
51
|
|
|
51
52
|
// test channels
|
|
52
53
|
const testStartCh = channel('ci:mocha:test:start')
|
|
@@ -66,6 +67,8 @@ const testSessionStartCh = channel('ci:mocha:session:start')
|
|
|
66
67
|
const testSessionFinishCh = channel('ci:mocha:session:finish')
|
|
67
68
|
const itrSkippedSuitesCh = channel('ci:mocha:itr:skipped-suites')
|
|
68
69
|
|
|
70
|
+
const getCodeCoverageCh = channel('ci:nyc:get-coverage')
|
|
71
|
+
|
|
69
72
|
function getFilteredSuites (originalSuites) {
|
|
70
73
|
return originalSuites.reduce((acc, suite) => {
|
|
71
74
|
const testPath = getTestSuitePath(suite.file, process.cwd())
|
|
@@ -131,6 +134,9 @@ function getOnEndHandler (isParallel) {
|
|
|
131
134
|
let testCodeCoverageLinesTotal
|
|
132
135
|
if (global.__coverage__) {
|
|
133
136
|
try {
|
|
137
|
+
if (untestedCoverage) {
|
|
138
|
+
originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
|
|
139
|
+
}
|
|
134
140
|
testCodeCoverageLinesTotal = originalCoverageMap.getCoverageSummary().lines.pct
|
|
135
141
|
} catch (e) {
|
|
136
142
|
// ignore errors
|
|
@@ -153,6 +159,83 @@ function getOnEndHandler (isParallel) {
|
|
|
153
159
|
})
|
|
154
160
|
}
|
|
155
161
|
|
|
162
|
+
function getExecutionConfiguration (runner, onFinishRequest) {
|
|
163
|
+
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
164
|
+
|
|
165
|
+
const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
|
|
166
|
+
if (err) {
|
|
167
|
+
suitesToSkip = []
|
|
168
|
+
} else {
|
|
169
|
+
suitesToSkip = skippableSuites
|
|
170
|
+
itrCorrelationId = responseItrCorrelationId
|
|
171
|
+
}
|
|
172
|
+
// We remove the suites that we skip through ITR
|
|
173
|
+
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
174
|
+
const { suitesToRun } = filteredSuites
|
|
175
|
+
|
|
176
|
+
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
177
|
+
|
|
178
|
+
log.debug(
|
|
179
|
+
() => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
runner.suite.suites = suitesToRun
|
|
183
|
+
|
|
184
|
+
skippedSuites = Array.from(filteredSuites.skippedSuites)
|
|
185
|
+
|
|
186
|
+
onFinishRequest()
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const onReceivedKnownTests = ({ err, knownTests: receivedKnownTests }) => {
|
|
190
|
+
if (err) {
|
|
191
|
+
knownTests = []
|
|
192
|
+
isEarlyFlakeDetectionEnabled = false
|
|
193
|
+
} else {
|
|
194
|
+
knownTests = receivedKnownTests
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (isSuitesSkippingEnabled) {
|
|
198
|
+
skippableSuitesCh.publish({
|
|
199
|
+
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
200
|
+
})
|
|
201
|
+
} else {
|
|
202
|
+
onFinishRequest()
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const onReceivedConfiguration = ({ err, libraryConfig }) => {
|
|
207
|
+
if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
|
|
208
|
+
return onFinishRequest()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
212
|
+
isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
|
|
213
|
+
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
214
|
+
isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
215
|
+
|
|
216
|
+
config.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
217
|
+
config.isSuitesSkippingEnabled = isSuitesSkippingEnabled
|
|
218
|
+
config.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
219
|
+
config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
|
|
220
|
+
|
|
221
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
222
|
+
knownTestsCh.publish({
|
|
223
|
+
onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
|
|
224
|
+
})
|
|
225
|
+
} else if (isSuitesSkippingEnabled) {
|
|
226
|
+
skippableSuitesCh.publish({
|
|
227
|
+
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
228
|
+
})
|
|
229
|
+
} else {
|
|
230
|
+
onFinishRequest()
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
libraryConfigurationCh.publish({
|
|
235
|
+
onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
156
239
|
// In this hook we delay the execution with options.delay to grab library configuration,
|
|
157
240
|
// skippable and known tests.
|
|
158
241
|
// It is called but skipped in parallel mode.
|
|
@@ -161,7 +244,6 @@ addHook({
|
|
|
161
244
|
versions: ['>=5.2.0'],
|
|
162
245
|
file: 'lib/mocha.js'
|
|
163
246
|
}, (Mocha) => {
|
|
164
|
-
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
165
247
|
shimmer.wrap(Mocha.prototype, 'run', run => function () {
|
|
166
248
|
// Workers do not need to request any data, just run the tests
|
|
167
249
|
if (!testStartCh.hasSubscribers || process.env.MOCHA_WORKER_ID || this.options.parallel) {
|
|
@@ -181,79 +263,17 @@ addHook({
|
|
|
181
263
|
}
|
|
182
264
|
})
|
|
183
265
|
|
|
184
|
-
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
// We remove the suites that we skip through ITR
|
|
192
|
-
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
193
|
-
const { suitesToRun } = filteredSuites
|
|
194
|
-
|
|
195
|
-
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
196
|
-
|
|
197
|
-
log.debug(
|
|
198
|
-
() => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
runner.suite.suites = suitesToRun
|
|
202
|
-
|
|
203
|
-
skippedSuites = Array.from(filteredSuites.skippedSuites)
|
|
204
|
-
|
|
205
|
-
global.run()
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const onReceivedKnownTests = ({ err, knownTests: receivedKnownTests }) => {
|
|
209
|
-
if (err) {
|
|
210
|
-
knownTests = []
|
|
211
|
-
isEarlyFlakeDetectionEnabled = false
|
|
212
|
-
} else {
|
|
213
|
-
knownTests = receivedKnownTests
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (isSuitesSkippingEnabled) {
|
|
217
|
-
skippableSuitesCh.publish({
|
|
218
|
-
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
219
|
-
})
|
|
220
|
-
} else {
|
|
221
|
-
global.run()
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const onReceivedConfiguration = ({ err, libraryConfig }) => {
|
|
226
|
-
if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
|
|
227
|
-
return global.run()
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
231
|
-
isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
|
|
232
|
-
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
233
|
-
isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
234
|
-
|
|
235
|
-
config.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
236
|
-
config.isSuitesSkippingEnabled = isSuitesSkippingEnabled
|
|
237
|
-
config.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
238
|
-
config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
|
|
239
|
-
|
|
240
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
241
|
-
knownTestsCh.publish({
|
|
242
|
-
onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
|
|
243
|
-
})
|
|
244
|
-
} else if (isSuitesSkippingEnabled) {
|
|
245
|
-
skippableSuitesCh.publish({
|
|
246
|
-
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
266
|
+
getExecutionConfiguration(runner, () => {
|
|
267
|
+
if (getCodeCoverageCh.hasSubscribers) {
|
|
268
|
+
getCodeCoverageCh.publish({
|
|
269
|
+
onDone: (receivedCodeCoverage) => {
|
|
270
|
+
untestedCoverage = receivedCodeCoverage
|
|
271
|
+
global.run()
|
|
272
|
+
}
|
|
247
273
|
})
|
|
248
274
|
} else {
|
|
249
275
|
global.run()
|
|
250
276
|
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
mochaRunAsyncResource.runInAsyncScope(() => {
|
|
254
|
-
libraryConfigurationCh.publish({
|
|
255
|
-
onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
|
|
256
|
-
})
|
|
257
277
|
})
|
|
258
278
|
|
|
259
279
|
return runner
|
|
@@ -395,9 +415,13 @@ addHook({
|
|
|
395
415
|
}
|
|
396
416
|
|
|
397
417
|
const asyncResource = testFileToSuiteAr.get(suite.file)
|
|
398
|
-
asyncResource
|
|
399
|
-
|
|
400
|
-
|
|
418
|
+
if (asyncResource) {
|
|
419
|
+
asyncResource.runInAsyncScope(() => {
|
|
420
|
+
testSuiteFinishCh.publish(status)
|
|
421
|
+
})
|
|
422
|
+
} else {
|
|
423
|
+
log.warn(() => `No AsyncResource found for suite ${suite.file}`)
|
|
424
|
+
}
|
|
401
425
|
})
|
|
402
426
|
|
|
403
427
|
return run.apply(this, arguments)
|
|
@@ -424,23 +448,29 @@ addHook({
|
|
|
424
448
|
versions: ['>=6.0.0'],
|
|
425
449
|
file: 'src/WorkerHandler.js'
|
|
426
450
|
}, (workerHandlerPackage) => {
|
|
427
|
-
shimmer.wrap(workerHandlerPackage.prototype, 'exec', exec => function (
|
|
451
|
+
shimmer.wrap(workerHandlerPackage.prototype, 'exec', exec => function (_, path) {
|
|
428
452
|
if (!testStartCh.hasSubscribers) {
|
|
429
453
|
return exec.apply(this, arguments)
|
|
430
454
|
}
|
|
455
|
+
if (!path?.length) {
|
|
456
|
+
return exec.apply(this, arguments)
|
|
457
|
+
}
|
|
458
|
+
const [testSuiteAbsolutePath] = path
|
|
459
|
+
const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
431
460
|
|
|
432
|
-
|
|
461
|
+
function onMessage (message) {
|
|
433
462
|
if (Array.isArray(message)) {
|
|
434
463
|
const [messageCode, payload] = message
|
|
435
464
|
if (messageCode === MOCHA_WORKER_TRACE_PAYLOAD_CODE) {
|
|
436
|
-
|
|
465
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
437
466
|
workerReportTraceCh.publish(payload)
|
|
438
467
|
})
|
|
439
468
|
}
|
|
440
469
|
}
|
|
441
|
-
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
this.worker.on('message', onMessage)
|
|
442
473
|
|
|
443
|
-
const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
444
474
|
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
445
475
|
testSuiteStartCh.publish({
|
|
446
476
|
testSuiteAbsolutePath
|
|
@@ -455,12 +485,14 @@ addHook({
|
|
|
455
485
|
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
456
486
|
testSuiteFinishCh.publish(status)
|
|
457
487
|
})
|
|
488
|
+
this.worker.off('message', onMessage)
|
|
458
489
|
},
|
|
459
490
|
(err) => {
|
|
460
491
|
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
461
492
|
testSuiteErrorCh.publish(err)
|
|
462
493
|
testSuiteFinishCh.publish('fail')
|
|
463
494
|
})
|
|
495
|
+
this.worker.off('message', onMessage)
|
|
464
496
|
}
|
|
465
497
|
)
|
|
466
498
|
return promise
|
|
@@ -469,6 +501,7 @@ addHook({
|
|
|
469
501
|
testSuiteErrorCh.publish(err)
|
|
470
502
|
testSuiteFinishCh.publish('fail')
|
|
471
503
|
})
|
|
504
|
+
this.worker.off('message', onMessage)
|
|
472
505
|
throw err
|
|
473
506
|
}
|
|
474
507
|
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
2
|
+
const shimmer = require('../../datadog-shimmer')
|
|
3
|
+
|
|
4
|
+
const codeCoverageWrapCh = channel('ci:nyc:wrap')
|
|
5
|
+
|
|
6
|
+
addHook({
|
|
7
|
+
name: 'nyc',
|
|
8
|
+
versions: ['>=17']
|
|
9
|
+
}, (nycPackage) => {
|
|
10
|
+
shimmer.wrap(nycPackage.prototype, 'wrap', wrap => async function () {
|
|
11
|
+
// Only relevant if the config `all` is set to true
|
|
12
|
+
try {
|
|
13
|
+
if (JSON.parse(process.env.NYC_CONFIG).all) {
|
|
14
|
+
codeCoverageWrapCh.publish(this)
|
|
15
|
+
}
|
|
16
|
+
} catch (e) {
|
|
17
|
+
// ignore errors
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return wrap.apply(this, arguments)
|
|
21
|
+
})
|
|
22
|
+
return nycPackage
|
|
23
|
+
})
|