dd-trace 5.12.0 → 5.14.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/README.md +8 -1
- package/ci/init.js +7 -0
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +21 -6
- package/init.js +27 -3
- package/package.json +6 -6
- package/packages/datadog-esbuild/index.js +8 -2
- package/packages/datadog-instrumentations/src/aws-sdk.js +4 -1
- package/packages/datadog-instrumentations/src/cucumber.js +182 -105
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/lodash.js +31 -0
- package/packages/datadog-instrumentations/src/playwright.js +6 -1
- package/packages/datadog-plugin-aws-sdk/src/services/index.js +3 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sfn.js +7 -0
- package/packages/datadog-plugin-aws-sdk/src/services/states.js +7 -0
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +64 -0
- package/packages/datadog-plugin-cucumber/src/index.js +83 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +4 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +2 -33
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +3 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +55 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/hardcoded-password-analyzer.js +13 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +8 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +6 -6
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +56 -0
- package/packages/dd-trace/src/ci-visibility/exporters/{jest-worker → test-worker}/writer.js +7 -0
- package/packages/dd-trace/src/config.js +25 -8
- package/packages/dd-trace/src/encode/0.4.js +50 -3
- package/packages/dd-trace/src/exporter.js +2 -1
- package/packages/dd-trace/src/plugins/database.js +20 -5
- package/packages/dd-trace/src/plugins/util/test.js +7 -0
- package/packages/dd-trace/src/profiling/profiler.js +23 -7
- package/packages/dd-trace/src/proxy.js +7 -1
- package/packages/dd-trace/src/serverless.js +3 -5
- package/packages/dd-trace/src/telemetry/index.js +9 -3
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +42 -1
- package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/index.js +0 -33
package/README.md
CHANGED
|
@@ -108,4 +108,11 @@ If you would like to trace your bundled application then please read this page o
|
|
|
108
108
|
|
|
109
109
|
## Security Vulnerabilities
|
|
110
110
|
|
|
111
|
-
Please refer to the [SECURITY.md](https://github.com/DataDog/dd-trace-js/blob/master/SECURITY.md) document if you have found a security issue.
|
|
111
|
+
Please refer to the [SECURITY.md](https://github.com/DataDog/dd-trace-js/blob/master/SECURITY.md) document if you have found a security issue.
|
|
112
|
+
|
|
113
|
+
## Datadog With OpenTelemetery
|
|
114
|
+
|
|
115
|
+
Please refer to the [Node.js Custom Instrumentation using OpenTelemetry API](https://docs.datadoghq.com/tracing/trace_collection/custom_instrumentation/nodejs/otel/) document. It includes information on how to use the OpenTelemetry API with dd-trace-js
|
|
116
|
+
|
|
117
|
+
Note that our internal implementation of the OpenTelemetry API is currently set within the version range `>=1.0.0 <1.9.0`. This range will be updated at a regular cadence therefore, we recommend updating your tracer to the latest release to ensure up to date support.
|
|
118
|
+
|
package/ci/init.js
CHANGED
|
@@ -3,6 +3,7 @@ const tracer = require('../packages/dd-trace')
|
|
|
3
3
|
const { isTrue } = require('../packages/dd-trace/src/util')
|
|
4
4
|
|
|
5
5
|
const isJestWorker = !!process.env.JEST_WORKER_ID
|
|
6
|
+
const isCucumberWorker = !!process.env.CUCUMBER_WORKER_ID
|
|
6
7
|
|
|
7
8
|
const options = {
|
|
8
9
|
startupLogs: false,
|
|
@@ -37,6 +38,12 @@ if (isJestWorker) {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
if (isCucumberWorker) {
|
|
42
|
+
options.experimental = {
|
|
43
|
+
exporter: 'cucumber_worker'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
if (shouldInit) {
|
|
41
48
|
tracer.init(options)
|
|
42
49
|
tracer.use('fs', false)
|
package/ext/exporters.d.ts
CHANGED
package/ext/exporters.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -144,6 +144,7 @@ interface Plugins {
|
|
|
144
144
|
"aws-sdk": tracer.plugins.aws_sdk;
|
|
145
145
|
"bunyan": tracer.plugins.bunyan;
|
|
146
146
|
"cassandra-driver": tracer.plugins.cassandra_driver;
|
|
147
|
+
"child_process": tracer.plugins.child_process;
|
|
147
148
|
"connect": tracer.plugins.connect;
|
|
148
149
|
"couchbase": tracer.plugins.couchbase;
|
|
149
150
|
"cucumber": tracer.plugins.cucumber;
|
|
@@ -940,11 +941,15 @@ declare namespace tracer {
|
|
|
940
941
|
/** @hidden */
|
|
941
942
|
interface Http extends Instrumentation {
|
|
942
943
|
/**
|
|
943
|
-
* List of URLs that should be instrumented.
|
|
944
|
+
* List of URLs/paths that should be instrumented.
|
|
945
|
+
*
|
|
946
|
+
* Note that when used for an http client the entry represents a full
|
|
947
|
+
* outbound URL (`https://example.org/api/foo`) but when used as a
|
|
948
|
+
* server the entry represents an inbound path (`/api/foo`).
|
|
944
949
|
*
|
|
945
950
|
* @default /^.*$/
|
|
946
951
|
*/
|
|
947
|
-
allowlist?: string | RegExp | ((
|
|
952
|
+
allowlist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
948
953
|
|
|
949
954
|
/**
|
|
950
955
|
* Deprecated in favor of `allowlist`.
|
|
@@ -952,15 +957,19 @@ declare namespace tracer {
|
|
|
952
957
|
* @deprecated
|
|
953
958
|
* @hidden
|
|
954
959
|
*/
|
|
955
|
-
whitelist?: string | RegExp | ((
|
|
960
|
+
whitelist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
956
961
|
|
|
957
962
|
/**
|
|
958
|
-
* List of URLs that should not be instrumented. Takes precedence over
|
|
963
|
+
* List of URLs/paths that should not be instrumented. Takes precedence over
|
|
959
964
|
* allowlist if a URL matches an entry in both.
|
|
960
965
|
*
|
|
966
|
+
* Note that when used for an http client the entry represents a full
|
|
967
|
+
* outbound URL (`https://example.org/api/foo`) but when used as a
|
|
968
|
+
* server the entry represents an inbound path (`/api/foo`).
|
|
969
|
+
*
|
|
961
970
|
* @default []
|
|
962
971
|
*/
|
|
963
|
-
blocklist?: string | RegExp | ((
|
|
972
|
+
blocklist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
964
973
|
|
|
965
974
|
/**
|
|
966
975
|
* Deprecated in favor of `blocklist`.
|
|
@@ -968,7 +977,7 @@ declare namespace tracer {
|
|
|
968
977
|
* @deprecated
|
|
969
978
|
* @hidden
|
|
970
979
|
*/
|
|
971
|
-
blacklist?: string | RegExp | ((
|
|
980
|
+
blacklist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
972
981
|
|
|
973
982
|
/**
|
|
974
983
|
* An array of headers to include in the span metadata.
|
|
@@ -1199,6 +1208,12 @@ declare namespace tracer {
|
|
|
1199
1208
|
*/
|
|
1200
1209
|
interface cassandra_driver extends Instrumentation {}
|
|
1201
1210
|
|
|
1211
|
+
/**
|
|
1212
|
+
* This plugin automatically instruments the
|
|
1213
|
+
* [child_process](https://nodejs.org/api/child_process.html) module.
|
|
1214
|
+
*/
|
|
1215
|
+
interface child_process extends Instrumentation {}
|
|
1216
|
+
|
|
1202
1217
|
/**
|
|
1203
1218
|
* This plugin automatically instruments the
|
|
1204
1219
|
* [connect](https://github.com/senchalabs/connect) module.
|
package/init.js
CHANGED
|
@@ -1,7 +1,31 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const Module = require('module')
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
let initBailout = false
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
if (process.env.DD_INJECTION_ENABLED) {
|
|
9
|
+
// If we're running via single-step install, and we're not in the app's
|
|
10
|
+
// node_modules, then we should not initialize the tracer. This prevents
|
|
11
|
+
// single-step-installed tracer from clobbering the manually-installed tracer.
|
|
12
|
+
let resolvedInApp
|
|
13
|
+
const entrypoint = process.argv[1]
|
|
14
|
+
try {
|
|
15
|
+
resolvedInApp = Module.createRequire(entrypoint).resolve('dd-trace')
|
|
16
|
+
} catch (e) {
|
|
17
|
+
// Ignore. If we can't resolve the module, we assume it's not in the app.
|
|
18
|
+
}
|
|
19
|
+
if (resolvedInApp) {
|
|
20
|
+
const ourselves = path.join(__dirname, 'index.js')
|
|
21
|
+
if (ourselves !== resolvedInApp) {
|
|
22
|
+
initBailout = true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!initBailout) {
|
|
28
|
+
const tracer = require('.')
|
|
29
|
+
tracer.init()
|
|
30
|
+
module.exports = tracer
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.14.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -71,17 +71,17 @@
|
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"@datadog/native-appsec": "7.1.1",
|
|
74
|
-
"@datadog/native-iast-rewriter": "2.3.
|
|
75
|
-
"@datadog/native-iast-taint-tracking": "1.
|
|
74
|
+
"@datadog/native-iast-rewriter": "2.3.1",
|
|
75
|
+
"@datadog/native-iast-taint-tracking": "2.1.0",
|
|
76
76
|
"@datadog/native-metrics": "^2.0.0",
|
|
77
|
-
"@datadog/pprof": "5.
|
|
77
|
+
"@datadog/pprof": "5.3.0",
|
|
78
78
|
"@datadog/sketches-js": "^2.1.0",
|
|
79
|
-
"@opentelemetry/api": "
|
|
79
|
+
"@opentelemetry/api": ">=1.0.0 <1.9.0",
|
|
80
80
|
"@opentelemetry/core": "^1.14.0",
|
|
81
81
|
"crypto-randomuuid": "^1.0.0",
|
|
82
82
|
"dc-polyfill": "^0.1.4",
|
|
83
83
|
"ignore": "^5.2.4",
|
|
84
|
-
"import-in-the-middle": "^1.7.
|
|
84
|
+
"import-in-the-middle": "^1.7.4",
|
|
85
85
|
"int64-buffer": "^0.1.9",
|
|
86
86
|
"ipaddr.js": "^2.1.0",
|
|
87
87
|
"istanbul-lib-coverage": "3.2.0",
|
|
@@ -75,7 +75,10 @@ module.exports.setup = function (build) {
|
|
|
75
75
|
try {
|
|
76
76
|
fullPathToModule = dotFriendlyResolve(args.path, args.resolveDir)
|
|
77
77
|
} catch (err) {
|
|
78
|
-
|
|
78
|
+
if (DEBUG) {
|
|
79
|
+
console.warn(`Warning: Unable to find "${args.path}".` +
|
|
80
|
+
"Unless it's dead code this could cause a problem at runtime.")
|
|
81
|
+
}
|
|
79
82
|
return
|
|
80
83
|
}
|
|
81
84
|
const extracted = extractPackageAndModulePath(fullPathToModule)
|
|
@@ -93,7 +96,10 @@ module.exports.setup = function (build) {
|
|
|
93
96
|
} catch (err) {
|
|
94
97
|
if (err.code === 'MODULE_NOT_FOUND') {
|
|
95
98
|
if (!internal) {
|
|
96
|
-
|
|
99
|
+
if (DEBUG) {
|
|
100
|
+
console.warn(`Warning: Unable to find "${extracted.pkg}/package.json".` +
|
|
101
|
+
"Unless it's dead code this could cause a problem at runtime.")
|
|
102
|
+
}
|
|
97
103
|
}
|
|
98
104
|
return
|
|
99
105
|
} else {
|
|
@@ -22,6 +22,8 @@ const skippableSuitesCh = channel('ci:cucumber:test-suite:skippable')
|
|
|
22
22
|
const sessionStartCh = channel('ci:cucumber:session:start')
|
|
23
23
|
const sessionFinishCh = channel('ci:cucumber:session:finish')
|
|
24
24
|
|
|
25
|
+
const workerReportTraceCh = channel('ci:cucumber:worker-report:trace')
|
|
26
|
+
|
|
25
27
|
const itrSkippedSuitesCh = channel('ci:cucumber:itr:skipped-suites')
|
|
26
28
|
|
|
27
29
|
const {
|
|
@@ -29,7 +31,8 @@ const {
|
|
|
29
31
|
resetCoverage,
|
|
30
32
|
mergeCoverage,
|
|
31
33
|
fromCoverageMapToCoverage,
|
|
32
|
-
getTestSuitePath
|
|
34
|
+
getTestSuitePath,
|
|
35
|
+
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE
|
|
33
36
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
34
37
|
|
|
35
38
|
const isMarkedAsUnskippable = (pickle) => {
|
|
@@ -47,13 +50,19 @@ const numRetriesByPickleId = new Map()
|
|
|
47
50
|
|
|
48
51
|
let pickleByFile = {}
|
|
49
52
|
const pickleResultByFile = {}
|
|
53
|
+
|
|
54
|
+
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
55
|
+
|
|
50
56
|
let skippableSuites = []
|
|
51
57
|
let itrCorrelationId = ''
|
|
52
58
|
let isForcedToRun = false
|
|
53
59
|
let isUnskippable = false
|
|
60
|
+
let isSuitesSkippingEnabled = false
|
|
54
61
|
let isEarlyFlakeDetectionEnabled = false
|
|
55
62
|
let earlyFlakeDetectionNumRetries = 0
|
|
56
63
|
let knownTests = []
|
|
64
|
+
let skippedSuites = []
|
|
65
|
+
let isSuitesSkipped = false
|
|
57
66
|
|
|
58
67
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
59
68
|
if (testStatuses.some(status => status === 'fail')) {
|
|
@@ -106,6 +115,43 @@ function getTestStatusFromRetries (testStatuses) {
|
|
|
106
115
|
return 'pass'
|
|
107
116
|
}
|
|
108
117
|
|
|
118
|
+
function getChannelPromise (channelToPublishTo) {
|
|
119
|
+
return new Promise(resolve => {
|
|
120
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
121
|
+
channelToPublishTo.publish({ onDone: resolve })
|
|
122
|
+
})
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getFilteredPickles (runtime, suitesToSkip) {
|
|
127
|
+
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
128
|
+
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
129
|
+
const testSuitePath = getTestSuitePath(test.uri, process.cwd())
|
|
130
|
+
|
|
131
|
+
const isUnskippable = isMarkedAsUnskippable(test)
|
|
132
|
+
const isSkipped = suitesToSkip.includes(testSuitePath)
|
|
133
|
+
|
|
134
|
+
if (isSkipped && !isUnskippable) {
|
|
135
|
+
acc.skippedSuites.add(testSuitePath)
|
|
136
|
+
} else {
|
|
137
|
+
acc.picklesToRun.push(pickleId)
|
|
138
|
+
}
|
|
139
|
+
return acc
|
|
140
|
+
}, { skippedSuites: new Set(), picklesToRun: [] })
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getPickleByFile (runtime) {
|
|
144
|
+
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
145
|
+
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
146
|
+
if (acc[test.uri]) {
|
|
147
|
+
acc[test.uri].push(test)
|
|
148
|
+
} else {
|
|
149
|
+
acc[test.uri] = [test]
|
|
150
|
+
}
|
|
151
|
+
return acc
|
|
152
|
+
}, {})
|
|
153
|
+
}
|
|
154
|
+
|
|
109
155
|
function wrapRun (pl, isLatestVersion) {
|
|
110
156
|
if (patched.has(pl)) return
|
|
111
157
|
|
|
@@ -125,7 +171,8 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
125
171
|
testStartCh.publish({
|
|
126
172
|
testName: this.pickle.name,
|
|
127
173
|
testFileAbsolutePath,
|
|
128
|
-
testSourceLine
|
|
174
|
+
testSourceLine,
|
|
175
|
+
isParallel: !!process.env.CUCUMBER_WORKER_ID
|
|
129
176
|
})
|
|
130
177
|
try {
|
|
131
178
|
const promise = run.apply(this, arguments)
|
|
@@ -193,12 +240,6 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
193
240
|
}
|
|
194
241
|
|
|
195
242
|
function pickleHook (PickleRunner) {
|
|
196
|
-
if (process.env.CUCUMBER_WORKER_ID) {
|
|
197
|
-
// Parallel mode is not supported
|
|
198
|
-
log.warn('Unable to initialize CI Visibility because Cucumber is running in parallel mode.')
|
|
199
|
-
return PickleRunner
|
|
200
|
-
}
|
|
201
|
-
|
|
202
243
|
const pl = PickleRunner.default
|
|
203
244
|
|
|
204
245
|
wrapRun(pl, false)
|
|
@@ -207,12 +248,6 @@ function pickleHook (PickleRunner) {
|
|
|
207
248
|
}
|
|
208
249
|
|
|
209
250
|
function testCaseHook (TestCaseRunner) {
|
|
210
|
-
if (process.env.CUCUMBER_WORKER_ID) {
|
|
211
|
-
// Parallel mode is not supported
|
|
212
|
-
log.warn('Unable to initialize CI Visibility because Cucumber is running in parallel mode.')
|
|
213
|
-
return TestCaseRunner
|
|
214
|
-
}
|
|
215
|
-
|
|
216
251
|
const pl = TestCaseRunner.default
|
|
217
252
|
|
|
218
253
|
wrapRun(pl, true)
|
|
@@ -220,76 +255,21 @@ function testCaseHook (TestCaseRunner) {
|
|
|
220
255
|
return TestCaseRunner
|
|
221
256
|
}
|
|
222
257
|
|
|
223
|
-
|
|
224
|
-
name: '@cucumber/cucumber',
|
|
225
|
-
versions: ['7.0.0 - 7.2.1'],
|
|
226
|
-
file: 'lib/runtime/pickle_runner.js'
|
|
227
|
-
}, pickleHook)
|
|
228
|
-
|
|
229
|
-
addHook({
|
|
230
|
-
name: '@cucumber/cucumber',
|
|
231
|
-
versions: ['>=7.3.0'],
|
|
232
|
-
file: 'lib/runtime/test_case_runner.js'
|
|
233
|
-
}, testCaseHook)
|
|
234
|
-
|
|
235
|
-
function getFilteredPickles (runtime, suitesToSkip) {
|
|
236
|
-
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
237
|
-
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
238
|
-
const testSuitePath = getTestSuitePath(test.uri, process.cwd())
|
|
239
|
-
|
|
240
|
-
const isUnskippable = isMarkedAsUnskippable(test)
|
|
241
|
-
const isSkipped = suitesToSkip.includes(testSuitePath)
|
|
242
|
-
|
|
243
|
-
if (isSkipped && !isUnskippable) {
|
|
244
|
-
acc.skippedSuites.add(testSuitePath)
|
|
245
|
-
} else {
|
|
246
|
-
acc.picklesToRun.push(pickleId)
|
|
247
|
-
}
|
|
248
|
-
return acc
|
|
249
|
-
}, { skippedSuites: new Set(), picklesToRun: [] })
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function getPickleByFile (runtime) {
|
|
253
|
-
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
254
|
-
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
255
|
-
if (acc[test.uri]) {
|
|
256
|
-
acc[test.uri].push(test)
|
|
257
|
-
} else {
|
|
258
|
-
acc[test.uri] = [test]
|
|
259
|
-
}
|
|
260
|
-
return acc
|
|
261
|
-
}, {})
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function getWrappedStart (start, frameworkVersion) {
|
|
258
|
+
function getWrappedStart (start, frameworkVersion, isParallel = false) {
|
|
265
259
|
return async function () {
|
|
266
260
|
if (!libraryConfigurationCh.hasSubscribers) {
|
|
267
261
|
return start.apply(this, arguments)
|
|
268
262
|
}
|
|
269
|
-
|
|
270
|
-
let onDone
|
|
271
|
-
|
|
272
|
-
const configPromise = new Promise(resolve => {
|
|
273
|
-
onDone = resolve
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
asyncResource.runInAsyncScope(() => {
|
|
277
|
-
libraryConfigurationCh.publish({ onDone })
|
|
278
|
-
})
|
|
263
|
+
let errorSkippableRequest
|
|
279
264
|
|
|
280
|
-
const configurationResponse = await
|
|
265
|
+
const configurationResponse = await getChannelPromise(libraryConfigurationCh)
|
|
281
266
|
|
|
282
267
|
isEarlyFlakeDetectionEnabled = configurationResponse.libraryConfig?.isEarlyFlakeDetectionEnabled
|
|
283
268
|
earlyFlakeDetectionNumRetries = configurationResponse.libraryConfig?.earlyFlakeDetectionNumRetries
|
|
269
|
+
isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
|
|
284
270
|
|
|
285
271
|
if (isEarlyFlakeDetectionEnabled) {
|
|
286
|
-
const
|
|
287
|
-
onDone = resolve
|
|
288
|
-
})
|
|
289
|
-
asyncResource.runInAsyncScope(() => {
|
|
290
|
-
knownTestsCh.publish({ onDone })
|
|
291
|
-
})
|
|
292
|
-
const knownTestsResponse = await knownTestsPromise
|
|
272
|
+
const knownTestsResponse = await getChannelPromise(knownTestsCh)
|
|
293
273
|
if (!knownTestsResponse.err) {
|
|
294
274
|
knownTests = knownTestsResponse.knownTests
|
|
295
275
|
} else {
|
|
@@ -297,35 +277,26 @@ function getWrappedStart (start, frameworkVersion) {
|
|
|
297
277
|
}
|
|
298
278
|
}
|
|
299
279
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
})
|
|
280
|
+
if (isSuitesSkippingEnabled) {
|
|
281
|
+
const skippableResponse = await getChannelPromise(skippableSuitesCh)
|
|
303
282
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
})
|
|
283
|
+
errorSkippableRequest = skippableResponse.err
|
|
284
|
+
skippableSuites = skippableResponse.skippableSuites
|
|
307
285
|
|
|
308
|
-
|
|
286
|
+
if (!errorSkippableRequest) {
|
|
287
|
+
const filteredPickles = getFilteredPickles(this, skippableSuites)
|
|
288
|
+
const { picklesToRun } = filteredPickles
|
|
289
|
+
isSuitesSkipped = picklesToRun.length !== this.pickleIds.length
|
|
309
290
|
|
|
310
|
-
|
|
311
|
-
|
|
291
|
+
log.debug(
|
|
292
|
+
() => `${picklesToRun.length} out of ${this.pickleIds.length} suites are going to run.`
|
|
293
|
+
)
|
|
312
294
|
|
|
313
|
-
|
|
314
|
-
let isSuitesSkipped = false
|
|
295
|
+
this.pickleIds = picklesToRun
|
|
315
296
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
isSuitesSkipped = picklesToRun.length !== this.pickleIds.length
|
|
320
|
-
|
|
321
|
-
log.debug(
|
|
322
|
-
() => `${picklesToRun.length} out of ${this.pickleIds.length} suites are going to run.`
|
|
323
|
-
)
|
|
324
|
-
|
|
325
|
-
this.pickleIds = picklesToRun
|
|
326
|
-
|
|
327
|
-
skippedSuites = Array.from(filteredPickles.skippedSuites)
|
|
328
|
-
itrCorrelationId = skippableResponse.itrCorrelationId
|
|
297
|
+
skippedSuites = Array.from(filteredPickles.skippedSuites)
|
|
298
|
+
itrCorrelationId = skippableResponse.itrCorrelationId
|
|
299
|
+
}
|
|
329
300
|
}
|
|
330
301
|
|
|
331
302
|
pickleByFile = getPickleByFile(this)
|
|
@@ -333,11 +304,11 @@ function getWrappedStart (start, frameworkVersion) {
|
|
|
333
304
|
const processArgv = process.argv.slice(2).join(' ')
|
|
334
305
|
const command = process.env.npm_lifecycle_script || `cucumber-js ${processArgv}`
|
|
335
306
|
|
|
336
|
-
|
|
307
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
337
308
|
sessionStartCh.publish({ command, frameworkVersion })
|
|
338
309
|
})
|
|
339
310
|
|
|
340
|
-
if (!
|
|
311
|
+
if (!errorSkippableRequest && skippedSuites.length) {
|
|
341
312
|
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
342
313
|
}
|
|
343
314
|
|
|
@@ -355,7 +326,7 @@ function getWrappedStart (start, frameworkVersion) {
|
|
|
355
326
|
global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
|
|
356
327
|
}
|
|
357
328
|
|
|
358
|
-
|
|
329
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
359
330
|
sessionFinishCh.publish({
|
|
360
331
|
status: success ? 'pass' : 'fail',
|
|
361
332
|
isSuitesSkipped,
|
|
@@ -363,7 +334,8 @@ function getWrappedStart (start, frameworkVersion) {
|
|
|
363
334
|
numSkippedSuites: skippedSuites.length,
|
|
364
335
|
hasUnskippableSuites: isUnskippable,
|
|
365
336
|
hasForcedToRunSuites: isForcedToRun,
|
|
366
|
-
isEarlyFlakeDetectionEnabled
|
|
337
|
+
isEarlyFlakeDetectionEnabled,
|
|
338
|
+
isParallel
|
|
367
339
|
})
|
|
368
340
|
})
|
|
369
341
|
return success
|
|
@@ -432,7 +404,8 @@ function getWrappedRunTest (runTestFunction) {
|
|
|
432
404
|
|
|
433
405
|
testSuiteCodeCoverageCh.publish({
|
|
434
406
|
coverageFiles,
|
|
435
|
-
suiteFile: testFileAbsolutePath
|
|
407
|
+
suiteFile: testFileAbsolutePath,
|
|
408
|
+
testSuitePath
|
|
436
409
|
})
|
|
437
410
|
// We need to reset coverage to get a code coverage per suite
|
|
438
411
|
// Before that, we preserve the original coverage
|
|
@@ -440,14 +413,97 @@ function getWrappedRunTest (runTestFunction) {
|
|
|
440
413
|
resetCoverage(global.__coverage__)
|
|
441
414
|
}
|
|
442
415
|
|
|
443
|
-
testSuiteFinishCh.publish(testSuiteStatus)
|
|
416
|
+
testSuiteFinishCh.publish({ status: testSuiteStatus, testSuitePath })
|
|
444
417
|
}
|
|
445
418
|
|
|
446
419
|
return runTestCaseResult
|
|
447
420
|
}
|
|
448
421
|
}
|
|
449
422
|
|
|
450
|
-
|
|
423
|
+
function getWrappedParseWorkerMessage (parseWorkerMessageFunction) {
|
|
424
|
+
return function (worker, message) {
|
|
425
|
+
// If the message is an array, it's a dd-trace message, so we need to stop cucumber processing,
|
|
426
|
+
// or cucumber will throw an error
|
|
427
|
+
// TODO: identify the message better
|
|
428
|
+
if (Array.isArray(message)) {
|
|
429
|
+
const [messageCode, payload] = message
|
|
430
|
+
if (messageCode === CUCUMBER_WORKER_TRACE_PAYLOAD_CODE) {
|
|
431
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
432
|
+
workerReportTraceCh.publish(payload)
|
|
433
|
+
})
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const { jsonEnvelope } = message
|
|
439
|
+
if (!jsonEnvelope) {
|
|
440
|
+
return parseWorkerMessageFunction.apply(this, arguments)
|
|
441
|
+
}
|
|
442
|
+
let parsed = jsonEnvelope
|
|
443
|
+
|
|
444
|
+
if (typeof parsed === 'string') {
|
|
445
|
+
try {
|
|
446
|
+
parsed = JSON.parse(jsonEnvelope)
|
|
447
|
+
} catch (e) {
|
|
448
|
+
// ignore errors and continue
|
|
449
|
+
return parseWorkerMessageFunction.apply(this, arguments)
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (parsed.testCaseStarted) {
|
|
453
|
+
const { pickleId } = this.eventDataCollector.testCaseMap[parsed.testCaseStarted.testCaseId]
|
|
454
|
+
const pickle = this.eventDataCollector.getPickle(pickleId)
|
|
455
|
+
const testFileAbsolutePath = pickle.uri
|
|
456
|
+
// First test in suite
|
|
457
|
+
if (!pickleResultByFile[testFileAbsolutePath]) {
|
|
458
|
+
pickleResultByFile[testFileAbsolutePath] = []
|
|
459
|
+
testSuiteStartCh.publish({
|
|
460
|
+
testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd())
|
|
461
|
+
})
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const parseWorkerResponse = parseWorkerMessageFunction.apply(this, arguments)
|
|
466
|
+
|
|
467
|
+
// after calling `parseWorkerMessageFunction`, the test status can already be read
|
|
468
|
+
if (parsed.testCaseFinished) {
|
|
469
|
+
const { pickle, worstTestStepResult } =
|
|
470
|
+
this.eventDataCollector.getTestCaseAttempt(parsed.testCaseFinished.testCaseStartedId)
|
|
471
|
+
|
|
472
|
+
const { status } = getStatusFromResultLatest(worstTestStepResult)
|
|
473
|
+
|
|
474
|
+
const testFileAbsolutePath = pickle.uri
|
|
475
|
+
const finished = pickleResultByFile[testFileAbsolutePath]
|
|
476
|
+
finished.push(status)
|
|
477
|
+
|
|
478
|
+
if (finished.length === pickleByFile[testFileAbsolutePath].length) {
|
|
479
|
+
testSuiteFinishCh.publish({
|
|
480
|
+
status: getSuiteStatusFromTestStatuses(finished),
|
|
481
|
+
testSuitePath: getTestSuitePath(testFileAbsolutePath, process.cwd())
|
|
482
|
+
})
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return parseWorkerResponse
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Test start / finish for older versions. The only hook executed in workers when in parallel mode
|
|
491
|
+
addHook({
|
|
492
|
+
name: '@cucumber/cucumber',
|
|
493
|
+
versions: ['7.0.0 - 7.2.1'],
|
|
494
|
+
file: 'lib/runtime/pickle_runner.js'
|
|
495
|
+
}, pickleHook)
|
|
496
|
+
|
|
497
|
+
// Test start / finish for newer versions. The only hook executed in workers when in parallel mode
|
|
498
|
+
addHook({
|
|
499
|
+
name: '@cucumber/cucumber',
|
|
500
|
+
versions: ['>=7.3.0'],
|
|
501
|
+
file: 'lib/runtime/test_case_runner.js'
|
|
502
|
+
}, testCaseHook)
|
|
503
|
+
|
|
504
|
+
// From 7.3.0 onwards, runPickle becomes runTestCase. Not executed in parallel mode.
|
|
505
|
+
// `getWrappedStart` generates session start and finish events
|
|
506
|
+
// `getWrappedRunTest` generates suite start and finish events
|
|
451
507
|
addHook({
|
|
452
508
|
name: '@cucumber/cucumber',
|
|
453
509
|
versions: ['>=7.3.0'],
|
|
@@ -459,6 +515,9 @@ addHook({
|
|
|
459
515
|
return runtimePackage
|
|
460
516
|
})
|
|
461
517
|
|
|
518
|
+
// Not executed in parallel mode.
|
|
519
|
+
// `getWrappedStart` generates session start and finish events
|
|
520
|
+
// `getWrappedRunTest` generates suite start and finish events
|
|
462
521
|
addHook({
|
|
463
522
|
name: '@cucumber/cucumber',
|
|
464
523
|
versions: ['>=7.0.0 <7.3.0'],
|
|
@@ -469,3 +528,21 @@ addHook({
|
|
|
469
528
|
|
|
470
529
|
return runtimePackage
|
|
471
530
|
})
|
|
531
|
+
|
|
532
|
+
// Only executed in parallel mode.
|
|
533
|
+
// `getWrappedStart` generates session start and finish events
|
|
534
|
+
// `getWrappedGiveWork` generates suite start events and sets pickleResultByFile (used by suite finish events)
|
|
535
|
+
// `getWrappedParseWorkerMessage` generates suite finish events
|
|
536
|
+
addHook({
|
|
537
|
+
name: '@cucumber/cucumber',
|
|
538
|
+
versions: ['>=8.0.0'],
|
|
539
|
+
file: 'lib/runtime/parallel/coordinator.js'
|
|
540
|
+
}, (coordinatorPackage, frameworkVersion) => {
|
|
541
|
+
shimmer.wrap(coordinatorPackage.default.prototype, 'start', start => getWrappedStart(start, frameworkVersion, true))
|
|
542
|
+
shimmer.wrap(
|
|
543
|
+
coordinatorPackage.default.prototype,
|
|
544
|
+
'parseWorkerMessage',
|
|
545
|
+
parseWorkerMessage => getWrappedParseWorkerMessage(parseWorkerMessage)
|
|
546
|
+
)
|
|
547
|
+
return coordinatorPackage
|
|
548
|
+
})
|
|
@@ -66,6 +66,7 @@ module.exports = {
|
|
|
66
66
|
kafkajs: () => require('../kafkajs'),
|
|
67
67
|
ldapjs: () => require('../ldapjs'),
|
|
68
68
|
'limitd-client': () => require('../limitd-client'),
|
|
69
|
+
lodash: () => require('../lodash'),
|
|
69
70
|
mariadb: () => require('../mariadb'),
|
|
70
71
|
memcached: () => require('../memcached'),
|
|
71
72
|
'microgateway-core': () => require('../microgateway-core'),
|