dd-trace 5.12.0 → 5.13.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/ci/init.js +7 -0
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +14 -6
- package/package.json +4 -4
- 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/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 +7 -0
- 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/telemetry/index.js +9 -3
- package/packages/dd-trace/src/ci-visibility/exporters/jest-worker/index.js +0 -33
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
|
@@ -940,11 +940,15 @@ declare namespace tracer {
|
|
|
940
940
|
/** @hidden */
|
|
941
941
|
interface Http extends Instrumentation {
|
|
942
942
|
/**
|
|
943
|
-
* List of URLs that should be instrumented.
|
|
943
|
+
* List of URLs/paths that should be instrumented.
|
|
944
|
+
*
|
|
945
|
+
* Note that when used for an http client the entry represents a full
|
|
946
|
+
* outbound URL (`https://example.org/api/foo`) but when used as a
|
|
947
|
+
* server the entry represents an inbound path (`/api/foo`).
|
|
944
948
|
*
|
|
945
949
|
* @default /^.*$/
|
|
946
950
|
*/
|
|
947
|
-
allowlist?: string | RegExp | ((
|
|
951
|
+
allowlist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
948
952
|
|
|
949
953
|
/**
|
|
950
954
|
* Deprecated in favor of `allowlist`.
|
|
@@ -952,15 +956,19 @@ declare namespace tracer {
|
|
|
952
956
|
* @deprecated
|
|
953
957
|
* @hidden
|
|
954
958
|
*/
|
|
955
|
-
whitelist?: string | RegExp | ((
|
|
959
|
+
whitelist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
956
960
|
|
|
957
961
|
/**
|
|
958
|
-
* List of URLs that should not be instrumented. Takes precedence over
|
|
962
|
+
* List of URLs/paths that should not be instrumented. Takes precedence over
|
|
959
963
|
* allowlist if a URL matches an entry in both.
|
|
960
964
|
*
|
|
965
|
+
* Note that when used for an http client the entry represents a full
|
|
966
|
+
* outbound URL (`https://example.org/api/foo`) but when used as a
|
|
967
|
+
* server the entry represents an inbound path (`/api/foo`).
|
|
968
|
+
*
|
|
961
969
|
* @default []
|
|
962
970
|
*/
|
|
963
|
-
blocklist?: string | RegExp | ((
|
|
971
|
+
blocklist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
964
972
|
|
|
965
973
|
/**
|
|
966
974
|
* Deprecated in favor of `blocklist`.
|
|
@@ -968,7 +976,7 @@ declare namespace tracer {
|
|
|
968
976
|
* @deprecated
|
|
969
977
|
* @hidden
|
|
970
978
|
*/
|
|
971
|
-
blacklist?: string | RegExp | ((
|
|
979
|
+
blacklist?: string | RegExp | ((urlOrPath: string) => boolean) | (string | RegExp | ((urlOrPath: string) => boolean))[];
|
|
972
980
|
|
|
973
981
|
/**
|
|
974
982
|
* An array of headers to include in the span metadata.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.13.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -71,8 +71,8 @@
|
|
|
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
77
|
"@datadog/pprof": "5.2.0",
|
|
78
78
|
"@datadog/sketches-js": "^2.1.0",
|
|
@@ -81,7 +81,7 @@
|
|
|
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'),
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel, addHook } = require('./helpers/instrument')
|
|
4
|
+
|
|
5
|
+
const shimmer = require('../../datadog-shimmer')
|
|
6
|
+
|
|
7
|
+
addHook({ name: 'lodash', versions: ['>=4'] }, lodash => {
|
|
8
|
+
const lodashOperationCh = channel('datadog:lodash:operation')
|
|
9
|
+
|
|
10
|
+
const instrumentedLodashFn = ['trim', 'trimStart', 'trimEnd', 'toLower', 'toUpper', 'join']
|
|
11
|
+
|
|
12
|
+
shimmer.massWrap(
|
|
13
|
+
lodash,
|
|
14
|
+
instrumentedLodashFn,
|
|
15
|
+
lodashFn => {
|
|
16
|
+
return function () {
|
|
17
|
+
if (!lodashOperationCh.hasSubscribers) {
|
|
18
|
+
return lodashFn.apply(this, arguments)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const result = lodashFn.apply(this, arguments)
|
|
22
|
+
const message = { operation: lodashFn.name, arguments, result }
|
|
23
|
+
lodashOperationCh.publish(message)
|
|
24
|
+
|
|
25
|
+
return message.result
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
return lodash
|
|
31
|
+
})
|
|
@@ -297,7 +297,12 @@ function dispatcherRunWrapper (run) {
|
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
function dispatcherRunWrapperNew (run) {
|
|
300
|
-
return function () {
|
|
300
|
+
return function (testGroups) {
|
|
301
|
+
if (!this._allTests) {
|
|
302
|
+
// Removed in https://github.com/microsoft/playwright/commit/1e52c37b254a441cccf332520f60225a5acc14c7
|
|
303
|
+
// Not available from >=1.44.0
|
|
304
|
+
this._allTests = testGroups.map(g => g.tests).flat()
|
|
305
|
+
}
|
|
301
306
|
remainingTestsByFile = getTestsBySuiteFromTestGroups(arguments[0])
|
|
302
307
|
return run.apply(this, arguments)
|
|
303
308
|
}
|
|
@@ -7,6 +7,9 @@ exports.kinesis = require('./kinesis')
|
|
|
7
7
|
exports.lambda = require('./lambda')
|
|
8
8
|
exports.redshift = require('./redshift')
|
|
9
9
|
exports.s3 = require('./s3')
|
|
10
|
+
exports.sfn = require('./sfn')
|
|
10
11
|
exports.sns = require('./sns')
|
|
11
12
|
exports.sqs = require('./sqs')
|
|
13
|
+
exports.states = require('./states')
|
|
14
|
+
exports.stepfunctions = require('./stepfunctions')
|
|
12
15
|
exports.default = require('./default')
|