dd-trace 5.31.0 → 5.33.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 +1 -0
- package/README.md +17 -14
- package/index.d.ts +11 -1
- package/package.json +6 -5
- package/packages/datadog-instrumentations/src/aws-sdk.js +4 -1
- package/packages/datadog-instrumentations/src/cucumber.js +31 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +105 -56
- package/packages/datadog-instrumentations/src/mocha/main.js +9 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +27 -9
- package/packages/datadog-instrumentations/src/mocha/worker.js +4 -2
- package/packages/datadog-instrumentations/src/node-serialize.js +22 -0
- package/packages/datadog-instrumentations/src/openai.js +2 -0
- package/packages/datadog-instrumentations/src/playwright.js +8 -3
- package/packages/datadog-instrumentations/src/vitest.js +134 -62
- package/packages/datadog-instrumentations/src/vm.js +49 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +16 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +63 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +287 -0
- package/packages/datadog-plugin-aws-sdk/src/services/index.js +1 -0
- package/packages/datadog-plugin-cucumber/src/index.js +31 -31
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -8
- package/packages/datadog-plugin-cypress/src/support.js +6 -2
- package/packages/datadog-plugin-fetch/src/index.js +3 -3
- package/packages/datadog-plugin-http/src/client.js +5 -33
- package/packages/datadog-plugin-jest/src/index.js +37 -37
- package/packages/datadog-plugin-langchain/src/index.js +12 -80
- package/packages/datadog-plugin-langchain/src/tracing.js +89 -0
- package/packages/datadog-plugin-mocha/src/index.js +19 -35
- package/packages/datadog-plugin-playwright/src/index.js +3 -1
- package/packages/datadog-plugin-vitest/src/index.js +33 -35
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +3 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +16 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -24
- package/packages/dd-trace/src/appsec/iast/iast-context.js +12 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +19 -23
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +9 -8
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +75 -24
- package/packages/dd-trace/src/appsec/rasp/utils.js +10 -5
- package/packages/dd-trace/src/appsec/stack_trace.js +38 -28
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +37 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +65 -28
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +57 -17
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -4
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +18 -3
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -3
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +20 -3
- package/packages/dd-trace/src/config.js +43 -3
- package/packages/dd-trace/src/crashtracking/crashtracker.js +9 -0
- package/packages/dd-trace/src/crashtracking/noop.js +3 -0
- package/packages/dd-trace/src/datastreams/fnv.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +30 -13
- package/packages/dd-trace/src/debugger/devtools_client/send.js +4 -8
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +35 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +112 -0
- package/packages/dd-trace/src/debugger/devtools_client/status.js +12 -10
- package/packages/dd-trace/src/debugger/index.js +2 -13
- package/packages/dd-trace/src/llmobs/plugins/base.js +40 -11
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +59 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +24 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +111 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +42 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +102 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +32 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +131 -0
- package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +11 -3
- package/packages/dd-trace/src/llmobs/util.js +7 -1
- package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +3 -3
- package/packages/dd-trace/src/opentelemetry/context_manager.js +43 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +58 -27
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +0 -2
- package/packages/dd-trace/src/plugins/util/test.js +44 -12
- package/packages/dd-trace/src/priority_sampler.js +4 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +21 -0
- package/packages/dd-trace/src/profiling/profiler.js +11 -8
- package/packages/dd-trace/src/profiling/profilers/events.js +17 -1
- package/packages/dd-trace/src/proxy.js +6 -3
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -30,6 +30,7 @@ require,rfdc,MIT,Copyright 2019 David Mark Clements
|
|
|
30
30
|
require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
|
|
31
31
|
require,shell-quote,mit,Copyright (c) 2013 James Halliday
|
|
32
32
|
require,source-map,BSD-3-Clause,Copyright (c) 2009-2011, Mozilla Foundation and contributors
|
|
33
|
+
require,ttl-set,MIT,Copyright (c) 2024 Thomas Watson
|
|
33
34
|
dev,@apollo/server,MIT,Copyright (c) 2016-2020 Apollo Graph, Inc. (Formerly Meteor Development Group, Inc.)
|
|
34
35
|
dev,@types/node,MIT,Copyright Authors
|
|
35
36
|
dev,@eslint/eslintrc,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
|
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# `dd-trace`: Node.js APM Tracer Library
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/dd-trace)
|
|
4
|
-
[](https://www.npmjs.com/package/dd-trace/v/latest-node16)
|
|
5
4
|
[](https://codecov.io/gh/DataDog/dd-trace-js)
|
|
6
5
|
|
|
7
6
|
<img align="right" src="https://user-images.githubusercontent.com/551402/208212084-1d0c07e2-4135-4c61-b2da-8f2fddbc66ed.png" alt="Bits the dog JavaScript" width="200px"/>
|
|
@@ -23,16 +22,18 @@ Most of the documentation for `dd-trace` is available on these webpages:
|
|
|
23
22
|
|
|
24
23
|
## Version Release Lines and Maintenance
|
|
25
24
|
|
|
26
|
-
| Release Line | Latest Version | Node.js | Status |Initial Release | End of Life |
|
|
27
|
-
| :---: | :---: | :---: | :---: | :---: | :---: |
|
|
28
|
-
| [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) |  | `>= v12` |
|
|
29
|
-
| [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) |  | `>= v12` |
|
|
30
|
-
| [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) |  | `>= v14` |
|
|
31
|
-
| [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) | 
|
|
32
|
-
| [`v5`](https://github.com/DataDog/dd-trace-js/tree/v5.x) |  | `>= v18` | **Current** | 2024-01-11 | Unknown |
|
|
25
|
+
| Release Line | Latest Version | Node.js | [SSI](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/single-step-apm/?tab=linuxhostorvm) | [K8s Injection](https://docs.datadoghq.com/tracing/trace_collection/library_injection_local/?tab=kubernetes) |Status |Initial Release | End of Life |
|
|
26
|
+
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
27
|
+
| [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) |  | `>= v12` | NO | NO | **EOL** | 2021-07-13 | 2022-02-25 |
|
|
28
|
+
| [`v2`](https://github.com/DataDog/dd-trace-js/tree/v2.x) |  | `>= v12` | NO | NO | **EOL** | 2022-01-28 | 2023-08-15 |
|
|
29
|
+
| [`v3`](https://github.com/DataDog/dd-trace-js/tree/v3.x) |  | `>= v14` | NO | YES | **EOL** | 2022-08-15 | 2024-05-15 |
|
|
30
|
+
| [`v4`](https://github.com/DataDog/dd-trace-js/tree/v4.x) |  | `>= v16` | YES | YES | **EOL** | 2023-05-12 | 2025-01-11 |
|
|
31
|
+
| [`v5`](https://github.com/DataDog/dd-trace-js/tree/v5.x) |  | `>= v18` | YES | YES | **Current** | 2024-01-11 | Unknown |
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
* EOL = End-of-life
|
|
34
|
+
* SSI = Single-Step Install
|
|
35
|
+
|
|
36
|
+
We currently maintain one release line, namely `v5`.
|
|
36
37
|
|
|
37
38
|
For any new projects it is recommended to use the `v5` release line:
|
|
38
39
|
|
|
@@ -41,20 +42,22 @@ $ npm install dd-trace
|
|
|
41
42
|
$ yarn add dd-trace
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
Existing projects that need to use EOL versions of Node.js may continue to use these older release lines.
|
|
45
46
|
This is done by specifying the version when installing the package.
|
|
46
47
|
|
|
47
48
|
```sh
|
|
48
|
-
$ npm install dd-trace@4
|
|
49
|
-
$ yarn add dd-trace@4
|
|
49
|
+
$ npm install dd-trace@4 # or whatever version you need
|
|
50
|
+
$ yarn add dd-trace@4 # or whatever version you need
|
|
50
51
|
```
|
|
51
52
|
|
|
53
|
+
Note, however, that the end-of-life release lines are no longer maintained and will not receive updates.
|
|
54
|
+
|
|
52
55
|
Any backwards-breaking functionality that is introduced into the library will result in an increase of the major version of the library and therefore a new release line.
|
|
53
56
|
Such releases are kept to a minimum to reduce the pain of upgrading the library.
|
|
54
57
|
|
|
55
58
|
When a new release line is introduced the previous release line then enters maintenance mode where it will receive updates for the next year.
|
|
56
59
|
Once that year is up the release line enters End of Life and will not receive new updates.
|
|
57
|
-
The library also follows the Node.js LTS lifecycle wherein new release lines drop compatibility with Node.js versions that reach end
|
|
60
|
+
The library also follows the Node.js LTS lifecycle wherein new release lines drop compatibility with Node.js versions that reach end-of-life (with the maintenance release line still receiving updates for a year).
|
|
58
61
|
|
|
59
62
|
For more information about library versioning and compatibility, see the [NodeJS Compatibility Requirements](https://docs.datadoghq.com/tracing/trace_collection/compatibility/nodejs/#releases) page.
|
|
60
63
|
|
package/index.d.ts
CHANGED
|
@@ -2233,7 +2233,17 @@ declare namespace tracer {
|
|
|
2233
2233
|
/**
|
|
2234
2234
|
* Specifies the verbosity of the sent telemetry. Default 'INFORMATION'
|
|
2235
2235
|
*/
|
|
2236
|
-
telemetryVerbosity?: string
|
|
2236
|
+
telemetryVerbosity?: string,
|
|
2237
|
+
|
|
2238
|
+
/**
|
|
2239
|
+
* Configuration for stack trace reporting
|
|
2240
|
+
*/
|
|
2241
|
+
stackTrace?: {
|
|
2242
|
+
/** Whether to enable stack trace reporting.
|
|
2243
|
+
* @default true
|
|
2244
|
+
*/
|
|
2245
|
+
enabled?: boolean,
|
|
2246
|
+
}
|
|
2237
2247
|
}
|
|
2238
2248
|
|
|
2239
2249
|
export namespace llmobs {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.33.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test:lambda:ci": "nyc --no-clean --include \"packages/dd-trace/src/lambda/**/*.js\" -- npm run test:lambda",
|
|
34
34
|
"test:llmobs:sdk": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" --exclude \"packages/dd-trace/test/llmobs/plugins/**/*.spec.js\" \"packages/dd-trace/test/llmobs/**/*.spec.js\" ",
|
|
35
35
|
"test:llmobs:sdk:ci": "nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:sdk",
|
|
36
|
-
"test:llmobs:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/llmobs/plugins
|
|
36
|
+
"test:llmobs:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/dd-trace/test/llmobs/plugins/@($(echo $PLUGINS))/*.spec.js\"",
|
|
37
37
|
"test:llmobs:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/llmobs/**/*.js\" -- npm run test:llmobs:plugins",
|
|
38
38
|
"test:plugins": "mocha -r \"packages/dd-trace/test/setup/mocha.js\" \"packages/datadog-instrumentations/test/@($(echo $PLUGINS)).spec.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
|
|
39
39
|
"test:plugins:ci": "yarn services && nyc --no-clean --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS)).js\" --include \"packages/datadog-instrumentations/src/@($(echo $PLUGINS))/**/*.js\" --include \"packages/datadog-plugin-@($(echo $PLUGINS))/src/**/*.js\" -- npm run test:plugins",
|
|
@@ -81,12 +81,12 @@
|
|
|
81
81
|
"node": ">=18"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@datadog/libdatadog": "^0.
|
|
84
|
+
"@datadog/libdatadog": "^0.4.0",
|
|
85
85
|
"@datadog/native-appsec": "8.4.0",
|
|
86
86
|
"@datadog/native-iast-rewriter": "2.6.1",
|
|
87
87
|
"@datadog/native-iast-taint-tracking": "3.2.0",
|
|
88
88
|
"@datadog/native-metrics": "^3.1.0",
|
|
89
|
-
"@datadog/pprof": "5.
|
|
89
|
+
"@datadog/pprof": "5.5.0",
|
|
90
90
|
"@datadog/sketches-js": "^2.1.0",
|
|
91
91
|
"@isaacs/ttlcache": "^1.4.1",
|
|
92
92
|
"@opentelemetry/api": ">=1.0.0 <1.9.0",
|
|
@@ -111,7 +111,8 @@
|
|
|
111
111
|
"semver": "^7.5.4",
|
|
112
112
|
"shell-quote": "^1.8.1",
|
|
113
113
|
"source-map": "^0.7.4",
|
|
114
|
-
"tlhunter-sorted-set": "^0.1.0"
|
|
114
|
+
"tlhunter-sorted-set": "^0.1.0",
|
|
115
|
+
"ttl-set": "^1.0.0"
|
|
115
116
|
},
|
|
116
117
|
"devDependencies": {
|
|
117
118
|
"@apollo/server": "^4.11.0",
|
|
@@ -155,6 +155,8 @@ function getMessage (request, error, result) {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
function getChannelSuffix (name) {
|
|
158
|
+
// some resource identifiers have spaces between ex: bedrock runtime
|
|
159
|
+
name = name.replaceAll(' ', '')
|
|
158
160
|
return [
|
|
159
161
|
'cloudwatchlogs',
|
|
160
162
|
'dynamodb',
|
|
@@ -167,7 +169,8 @@ function getChannelSuffix (name) {
|
|
|
167
169
|
'sns',
|
|
168
170
|
'sqs',
|
|
169
171
|
'states',
|
|
170
|
-
'stepfunctions'
|
|
172
|
+
'stepfunctions',
|
|
173
|
+
'bedrockruntime'
|
|
171
174
|
].includes(name)
|
|
172
175
|
? name
|
|
173
176
|
: 'default'
|
|
@@ -70,6 +70,7 @@ let earlyFlakeDetectionNumRetries = 0
|
|
|
70
70
|
let earlyFlakeDetectionFaultyThreshold = 0
|
|
71
71
|
let isEarlyFlakeDetectionFaulty = false
|
|
72
72
|
let isFlakyTestRetriesEnabled = false
|
|
73
|
+
let isKnownTestsEnabled = false
|
|
73
74
|
let numTestRetries = 0
|
|
74
75
|
let knownTests = []
|
|
75
76
|
let skippedSuites = []
|
|
@@ -238,8 +239,9 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
238
239
|
asyncResource.runInAsyncScope(() => {
|
|
239
240
|
testStartCh.publish(testStartPayload)
|
|
240
241
|
})
|
|
242
|
+
const promises = {}
|
|
241
243
|
try {
|
|
242
|
-
this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => (testCase) => {
|
|
244
|
+
this.eventBroadcaster.on('envelope', shimmer.wrapFunction(null, () => async (testCase) => {
|
|
243
245
|
// Only supported from >=8.0.0
|
|
244
246
|
if (testCase?.testCaseFinished) {
|
|
245
247
|
const { testCaseFinished: { willBeRetried } } = testCase
|
|
@@ -253,17 +255,22 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
253
255
|
}
|
|
254
256
|
|
|
255
257
|
const failedAttemptAsyncResource = numAttemptToAsyncResource.get(numAttempt)
|
|
256
|
-
const
|
|
258
|
+
const isFirstAttempt = numAttempt++ === 0
|
|
259
|
+
|
|
260
|
+
if (promises.hitBreakpointPromise) {
|
|
261
|
+
await promises.hitBreakpointPromise
|
|
262
|
+
}
|
|
263
|
+
|
|
257
264
|
failedAttemptAsyncResource.runInAsyncScope(() => {
|
|
258
265
|
// the current span will be finished and a new one will be created
|
|
259
|
-
testRetryCh.publish({
|
|
266
|
+
testRetryCh.publish({ isFirstAttempt, error })
|
|
260
267
|
})
|
|
261
268
|
|
|
262
269
|
const newAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
263
270
|
numAttemptToAsyncResource.set(numAttempt, newAsyncResource)
|
|
264
271
|
|
|
265
272
|
newAsyncResource.runInAsyncScope(() => {
|
|
266
|
-
testStartCh.publish(testStartPayload) // a new span will be created
|
|
273
|
+
testStartCh.publish({ ...testStartPayload, promises }) // a new span will be created
|
|
267
274
|
})
|
|
268
275
|
}
|
|
269
276
|
}
|
|
@@ -273,7 +280,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
273
280
|
asyncResource.runInAsyncScope(() => {
|
|
274
281
|
promise = run.apply(this, arguments)
|
|
275
282
|
})
|
|
276
|
-
promise.finally(() => {
|
|
283
|
+
promise.finally(async () => {
|
|
277
284
|
const result = this.getWorstStepResult()
|
|
278
285
|
const { status, skipReason } = isLatestVersion
|
|
279
286
|
? getStatusFromResultLatest(result)
|
|
@@ -286,7 +293,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
286
293
|
}
|
|
287
294
|
let isNew = false
|
|
288
295
|
let isEfdRetry = false
|
|
289
|
-
if (
|
|
296
|
+
if (isKnownTestsEnabled && status !== 'skip') {
|
|
290
297
|
const numRetries = numRetriesByPickleId.get(this.pickle.id)
|
|
291
298
|
|
|
292
299
|
isNew = numRetries !== undefined
|
|
@@ -296,6 +303,9 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
296
303
|
|
|
297
304
|
const error = getErrorFromCucumberResult(result)
|
|
298
305
|
|
|
306
|
+
if (promises.hitBreakpointPromise) {
|
|
307
|
+
await promises.hitBreakpointPromise
|
|
308
|
+
}
|
|
299
309
|
attemptAsyncResource.runInAsyncScope(() => {
|
|
300
310
|
testFinishCh.publish({ status, skipReason, error, isNew, isEfdRetry, isFlakyRetry: numAttempt > 0 })
|
|
301
311
|
})
|
|
@@ -385,13 +395,15 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
385
395
|
isSuitesSkippingEnabled = configurationResponse.libraryConfig?.isSuitesSkippingEnabled
|
|
386
396
|
isFlakyTestRetriesEnabled = configurationResponse.libraryConfig?.isFlakyTestRetriesEnabled
|
|
387
397
|
numTestRetries = configurationResponse.libraryConfig?.flakyTestRetriesCount
|
|
398
|
+
isKnownTestsEnabled = configurationResponse.libraryConfig?.isKnownTestsEnabled
|
|
388
399
|
|
|
389
|
-
if (
|
|
400
|
+
if (isKnownTestsEnabled) {
|
|
390
401
|
const knownTestsResponse = await getChannelPromise(knownTestsCh)
|
|
391
402
|
if (!knownTestsResponse.err) {
|
|
392
403
|
knownTests = knownTestsResponse.knownTests
|
|
393
404
|
} else {
|
|
394
405
|
isEarlyFlakeDetectionEnabled = false
|
|
406
|
+
isKnownTestsEnabled = false
|
|
395
407
|
}
|
|
396
408
|
}
|
|
397
409
|
|
|
@@ -428,7 +440,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
428
440
|
|
|
429
441
|
pickleByFile = isCoordinator ? getPickleByFileNew(this) : getPickleByFile(this)
|
|
430
442
|
|
|
431
|
-
if (
|
|
443
|
+
if (isKnownTestsEnabled) {
|
|
432
444
|
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
433
445
|
Object.keys(pickleByFile),
|
|
434
446
|
knownTests.cucumber || {},
|
|
@@ -436,6 +448,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
|
|
|
436
448
|
)
|
|
437
449
|
if (isFaulty) {
|
|
438
450
|
isEarlyFlakeDetectionEnabled = false
|
|
451
|
+
isKnownTestsEnabled = false
|
|
439
452
|
isEarlyFlakeDetectionFaulty = true
|
|
440
453
|
}
|
|
441
454
|
}
|
|
@@ -524,7 +537,7 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
|
|
|
524
537
|
|
|
525
538
|
let isNew = false
|
|
526
539
|
|
|
527
|
-
if (
|
|
540
|
+
if (isKnownTestsEnabled) {
|
|
528
541
|
isNew = isNewTest(testSuitePath, pickle.name)
|
|
529
542
|
if (isNew) {
|
|
530
543
|
numRetriesByPickleId.set(pickle.id, 0)
|
|
@@ -669,14 +682,14 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
|
|
|
669
682
|
const { status } = getStatusFromResultLatest(worstTestStepResult)
|
|
670
683
|
let isNew = false
|
|
671
684
|
|
|
672
|
-
if (
|
|
685
|
+
if (isKnownTestsEnabled) {
|
|
673
686
|
isNew = isNewTest(pickle.uri, pickle.name)
|
|
674
687
|
}
|
|
675
688
|
|
|
676
689
|
const testFileAbsolutePath = pickle.uri
|
|
677
690
|
const finished = pickleResultByFile[testFileAbsolutePath]
|
|
678
691
|
|
|
679
|
-
if (isNew) {
|
|
692
|
+
if (isEarlyFlakeDetectionEnabled && isNew) {
|
|
680
693
|
const testFullname = `${pickle.uri}:${pickle.name}`
|
|
681
694
|
let testStatuses = newTestsByTestFullname.get(testFullname)
|
|
682
695
|
if (!testStatuses) {
|
|
@@ -830,7 +843,8 @@ addHook({
|
|
|
830
843
|
)
|
|
831
844
|
// EFD in parallel mode only supported in >=11.0.0
|
|
832
845
|
shimmer.wrap(adapterPackage.ChildProcessAdapter.prototype, 'startWorker', startWorker => function () {
|
|
833
|
-
if (
|
|
846
|
+
if (isKnownTestsEnabled) {
|
|
847
|
+
this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
|
|
834
848
|
this.options.worldParameters._ddKnownTests = knownTests
|
|
835
849
|
this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
836
850
|
}
|
|
@@ -853,9 +867,12 @@ addHook({
|
|
|
853
867
|
'initialize',
|
|
854
868
|
initialize => async function () {
|
|
855
869
|
await initialize.apply(this, arguments)
|
|
856
|
-
|
|
857
|
-
if (
|
|
870
|
+
isKnownTestsEnabled = !!this.options.worldParameters._ddKnownTests
|
|
871
|
+
if (isKnownTestsEnabled) {
|
|
858
872
|
knownTests = this.options.worldParameters._ddKnownTests
|
|
873
|
+
}
|
|
874
|
+
isEarlyFlakeDetectionEnabled = !!this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled
|
|
875
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
859
876
|
earlyFlakeDetectionNumRetries = this.options.worldParameters._ddEarlyFlakeDetectionNumRetries
|
|
860
877
|
}
|
|
861
878
|
}
|
|
@@ -88,6 +88,7 @@ module.exports = {
|
|
|
88
88
|
mysql2: () => require('../mysql2'),
|
|
89
89
|
net: () => require('../net'),
|
|
90
90
|
next: () => require('../next'),
|
|
91
|
+
'node-serialize': () => require('../node-serialize'),
|
|
91
92
|
'node:child_process': () => require('../child_process'),
|
|
92
93
|
'node:crypto': () => require('../crypto'),
|
|
93
94
|
'node:dns': () => require('../dns'),
|
|
@@ -96,6 +97,7 @@ module.exports = {
|
|
|
96
97
|
'node:https': () => require('../http'),
|
|
97
98
|
'node:net': () => require('../net'),
|
|
98
99
|
'node:url': () => require('../url'),
|
|
100
|
+
'node:vm': () => require('../vm'),
|
|
99
101
|
nyc: () => require('../nyc'),
|
|
100
102
|
oracledb: () => require('../oracledb'),
|
|
101
103
|
openai: () => require('../openai'),
|
|
@@ -122,6 +124,7 @@ module.exports = {
|
|
|
122
124
|
undici: () => require('../undici'),
|
|
123
125
|
url: () => require('../url'),
|
|
124
126
|
vitest: { esmFirst: true, fn: () => require('../vitest') },
|
|
127
|
+
vm: () => require('../vm'),
|
|
125
128
|
when: () => require('../when'),
|
|
126
129
|
winston: () => require('../winston'),
|
|
127
130
|
workerpool: () => require('../mocha')
|
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
getTestParametersString,
|
|
13
13
|
addEfdStringToTestName,
|
|
14
14
|
removeEfdStringFromTestName,
|
|
15
|
-
getIsFaultyEarlyFlakeDetection
|
|
15
|
+
getIsFaultyEarlyFlakeDetection,
|
|
16
|
+
JEST_WORKER_LOGS_PAYLOAD_CODE
|
|
16
17
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
17
18
|
const {
|
|
18
19
|
getFormattedJestTestParameters,
|
|
@@ -30,12 +31,13 @@ const testSuiteFinishCh = channel('ci:jest:test-suite:finish')
|
|
|
30
31
|
|
|
31
32
|
const workerReportTraceCh = channel('ci:jest:worker-report:trace')
|
|
32
33
|
const workerReportCoverageCh = channel('ci:jest:worker-report:coverage')
|
|
34
|
+
const workerReportLogsCh = channel('ci:jest:worker-report:logs')
|
|
33
35
|
|
|
34
36
|
const testSuiteCodeCoverageCh = channel('ci:jest:test-suite:code-coverage')
|
|
35
37
|
|
|
36
38
|
const testStartCh = channel('ci:jest:test:start')
|
|
37
39
|
const testSkippedCh = channel('ci:jest:test:skip')
|
|
38
|
-
const
|
|
40
|
+
const testFinishCh = channel('ci:jest:test:finish')
|
|
39
41
|
const testErrCh = channel('ci:jest:test:err')
|
|
40
42
|
|
|
41
43
|
const skippableSuitesCh = channel('ci:jest:test-suite:skippable')
|
|
@@ -67,6 +69,7 @@ let earlyFlakeDetectionNumRetries = 0
|
|
|
67
69
|
let earlyFlakeDetectionFaultyThreshold = 30
|
|
68
70
|
let isEarlyFlakeDetectionFaulty = false
|
|
69
71
|
let hasFilteredSkippableSuites = false
|
|
72
|
+
let isKnownTestsEnabled = false
|
|
70
73
|
|
|
71
74
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
72
75
|
|
|
@@ -75,6 +78,8 @@ const originalTestFns = new WeakMap()
|
|
|
75
78
|
const retriedTestsToNumAttempts = new Map()
|
|
76
79
|
const newTestsTestStatuses = new Map()
|
|
77
80
|
|
|
81
|
+
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
82
|
+
|
|
78
83
|
// based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
|
|
79
84
|
function formatJestError (errors) {
|
|
80
85
|
let error
|
|
@@ -134,17 +139,19 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
134
139
|
this.isFlakyTestRetriesEnabled = this.testEnvironmentOptions._ddIsFlakyTestRetriesEnabled
|
|
135
140
|
this.flakyTestRetriesCount = this.testEnvironmentOptions._ddFlakyTestRetriesCount
|
|
136
141
|
this.isDiEnabled = this.testEnvironmentOptions._ddIsDiEnabled
|
|
142
|
+
this.isKnownTestsEnabled = this.testEnvironmentOptions._ddIsKnownTestsEnabled
|
|
137
143
|
|
|
138
|
-
if (this.
|
|
139
|
-
const hasKnownTests = !!knownTests.jest
|
|
140
|
-
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
|
|
144
|
+
if (this.isKnownTestsEnabled) {
|
|
141
145
|
try {
|
|
146
|
+
const hasKnownTests = !!knownTests.jest
|
|
147
|
+
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
|
|
142
148
|
this.knownTestsForThisSuite = hasKnownTests
|
|
143
149
|
? (knownTests.jest[this.testSuite] || [])
|
|
144
150
|
: this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
|
|
145
151
|
} catch (e) {
|
|
146
152
|
// If there has been an error parsing the tests, we'll disable Early Flake Deteciton
|
|
147
153
|
this.isEarlyFlakeDetectionEnabled = false
|
|
154
|
+
this.isKnownTestsEnabled = false
|
|
148
155
|
}
|
|
149
156
|
}
|
|
150
157
|
|
|
@@ -224,7 +231,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
224
231
|
asyncResources.set(event.test, asyncResource)
|
|
225
232
|
const testName = getJestTestName(event.test)
|
|
226
233
|
|
|
227
|
-
if (this.
|
|
234
|
+
if (this.isKnownTestsEnabled) {
|
|
228
235
|
const originalTestName = removeEfdStringFromTestName(testName)
|
|
229
236
|
isNewTest = retriedTestsToNumAttempts.has(originalTestName)
|
|
230
237
|
if (isNewTest) {
|
|
@@ -250,70 +257,96 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
250
257
|
})
|
|
251
258
|
}
|
|
252
259
|
if (event.name === 'add_test') {
|
|
253
|
-
if (this.
|
|
260
|
+
if (this.isKnownTestsEnabled) {
|
|
254
261
|
const testName = this.getTestNameFromAddTestEvent(event, state)
|
|
255
262
|
const isNew = !this.knownTestsForThisSuite?.includes(testName)
|
|
256
263
|
const isSkipped = event.mode === 'todo' || event.mode === 'skip'
|
|
257
264
|
if (isNew && !isSkipped && !retriedTestsToNumAttempts.has(testName)) {
|
|
258
265
|
retriedTestsToNumAttempts.set(testName, 0)
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
this.global.test
|
|
269
|
-
|
|
270
|
-
|
|
266
|
+
if (this.isEarlyFlakeDetectionEnabled) {
|
|
267
|
+
// Retrying snapshots has proven to be problematic, so we'll skip them for now
|
|
268
|
+
// We'll still detect new tests, but we won't retry them.
|
|
269
|
+
// TODO: do not bail out of EFD with the whole test suite
|
|
270
|
+
if (this.getHasSnapshotTests()) {
|
|
271
|
+
log.warn('Early flake detection is disabled for suites with snapshots')
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
for (let retryIndex = 0; retryIndex < earlyFlakeDetectionNumRetries; retryIndex++) {
|
|
275
|
+
if (this.global.test) {
|
|
276
|
+
this.global.test(addEfdStringToTestName(event.testName, retryIndex), event.fn, event.timeout)
|
|
277
|
+
} else {
|
|
278
|
+
log.error('Early flake detection could not retry test because global.test is undefined')
|
|
279
|
+
}
|
|
271
280
|
}
|
|
272
281
|
}
|
|
273
282
|
}
|
|
274
283
|
}
|
|
275
284
|
}
|
|
276
285
|
if (event.name === 'test_done') {
|
|
277
|
-
|
|
286
|
+
let status = 'pass'
|
|
287
|
+
if (event.test.errors && event.test.errors.length) {
|
|
288
|
+
status = 'fail'
|
|
289
|
+
}
|
|
290
|
+
// restore in case it is retried
|
|
291
|
+
event.test.fn = originalTestFns.get(event.test)
|
|
292
|
+
|
|
293
|
+
// We'll store the test statuses of the retries
|
|
294
|
+
if (this.isKnownTestsEnabled) {
|
|
295
|
+
const testName = getJestTestName(event.test)
|
|
296
|
+
const originalTestName = removeEfdStringFromTestName(testName)
|
|
297
|
+
const isNewTest = retriedTestsToNumAttempts.has(originalTestName)
|
|
298
|
+
if (isNewTest) {
|
|
299
|
+
if (newTestsTestStatuses.has(originalTestName)) {
|
|
300
|
+
newTestsTestStatuses.get(originalTestName).push(status)
|
|
301
|
+
} else {
|
|
302
|
+
newTestsTestStatuses.set(originalTestName, [status])
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const promises = {}
|
|
308
|
+
const numRetries = this.global[RETRY_TIMES]
|
|
309
|
+
const numTestExecutions = event.test?.invocations
|
|
310
|
+
const willBeRetried = numRetries > 0 && numTestExecutions - 1 < numRetries
|
|
311
|
+
const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 2
|
|
312
|
+
|
|
278
313
|
const asyncResource = asyncResources.get(event.test)
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
status = 'fail'
|
|
283
|
-
const numRetries = this.global[RETRY_TIMES]
|
|
284
|
-
const numTestExecutions = event.test?.invocations
|
|
285
|
-
const willBeRetried = numRetries > 0 && numTestExecutions - 1 < numRetries
|
|
286
|
-
|
|
287
|
-
const error = formatJestError(event.test.errors[0])
|
|
314
|
+
|
|
315
|
+
if (status === 'fail') {
|
|
316
|
+
asyncResource.runInAsyncScope(() => {
|
|
288
317
|
testErrCh.publish({
|
|
289
|
-
error,
|
|
290
|
-
willBeRetried,
|
|
291
|
-
|
|
292
|
-
isDiEnabled: this.isDiEnabled
|
|
318
|
+
error: formatJestError(event.test.errors[0]),
|
|
319
|
+
shouldSetProbe: this.isDiEnabled && willBeRetried && numTestExecutions === 1,
|
|
320
|
+
promises
|
|
293
321
|
})
|
|
294
|
-
}
|
|
295
|
-
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// After finishing it might take a bit for the snapshot to be handled.
|
|
326
|
+
// This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
|
|
327
|
+
if (status === 'fail' && mightHitBreakpoint) {
|
|
328
|
+
await new Promise(resolve => {
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
resolve()
|
|
331
|
+
}, BREAKPOINT_HIT_GRACE_PERIOD_MS)
|
|
332
|
+
})
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
asyncResource.runInAsyncScope(() => {
|
|
336
|
+
testFinishCh.publish({
|
|
296
337
|
status,
|
|
297
|
-
testStartLine: getTestLineStart(event.test.asyncError, this.testSuite)
|
|
338
|
+
testStartLine: getTestLineStart(event.test.asyncError, this.testSuite),
|
|
339
|
+
promises,
|
|
340
|
+
shouldRemoveProbe: this.isDiEnabled && !willBeRetried
|
|
298
341
|
})
|
|
299
|
-
// restore in case it is retried
|
|
300
|
-
event.test.fn = originalTestFns.get(event.test)
|
|
301
|
-
// We'll store the test statuses of the retries
|
|
302
|
-
if (this.isEarlyFlakeDetectionEnabled) {
|
|
303
|
-
const testName = getJestTestName(event.test)
|
|
304
|
-
const originalTestName = removeEfdStringFromTestName(testName)
|
|
305
|
-
const isNewTest = retriedTestsToNumAttempts.has(originalTestName)
|
|
306
|
-
if (isNewTest) {
|
|
307
|
-
if (newTestsTestStatuses.has(originalTestName)) {
|
|
308
|
-
newTestsTestStatuses.get(originalTestName).push(status)
|
|
309
|
-
} else {
|
|
310
|
-
newTestsTestStatuses.set(originalTestName, [status])
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
342
|
})
|
|
315
|
-
|
|
316
|
-
|
|
343
|
+
|
|
344
|
+
if (promises.isProbeReady) {
|
|
345
|
+
await promises.isProbeReady
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (promises.isProbeRemoved) {
|
|
349
|
+
await promises.isProbeRemoved
|
|
317
350
|
}
|
|
318
351
|
}
|
|
319
352
|
if (event.name === 'test_skip' || event.name === 'test_todo') {
|
|
@@ -455,12 +488,13 @@ function cliWrapper (cli, jestVersion) {
|
|
|
455
488
|
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
456
489
|
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
457
490
|
earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
491
|
+
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
458
492
|
}
|
|
459
493
|
} catch (err) {
|
|
460
494
|
log.error('Jest library configuration error', err)
|
|
461
495
|
}
|
|
462
496
|
|
|
463
|
-
if (
|
|
497
|
+
if (isKnownTestsEnabled) {
|
|
464
498
|
const knownTestsPromise = new Promise((resolve) => {
|
|
465
499
|
onDone = resolve
|
|
466
500
|
})
|
|
@@ -476,6 +510,7 @@ function cliWrapper (cli, jestVersion) {
|
|
|
476
510
|
} else {
|
|
477
511
|
// We disable EFD if there has been an error in the known tests request
|
|
478
512
|
isEarlyFlakeDetectionEnabled = false
|
|
513
|
+
isKnownTestsEnabled = false
|
|
479
514
|
}
|
|
480
515
|
} catch (err) {
|
|
481
516
|
log.error('Jest known tests error', err)
|
|
@@ -793,6 +828,7 @@ addHook({
|
|
|
793
828
|
_ddIsFlakyTestRetriesEnabled,
|
|
794
829
|
_ddFlakyTestRetriesCount,
|
|
795
830
|
_ddIsDiEnabled,
|
|
831
|
+
_ddIsKnownTestsEnabled,
|
|
796
832
|
...restOfTestEnvironmentOptions
|
|
797
833
|
} = testEnvironmentOptions
|
|
798
834
|
|
|
@@ -820,17 +856,19 @@ addHook({
|
|
|
820
856
|
const testPaths = await getTestPaths.apply(this, arguments)
|
|
821
857
|
const [{ rootDir, shard }] = arguments
|
|
822
858
|
|
|
823
|
-
if (
|
|
859
|
+
if (isKnownTestsEnabled) {
|
|
824
860
|
const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
|
|
825
861
|
const isFaulty =
|
|
826
862
|
getIsFaultyEarlyFlakeDetection(projectSuites, knownTests.jest || {}, earlyFlakeDetectionFaultyThreshold)
|
|
827
863
|
if (isFaulty) {
|
|
828
864
|
log.error('Early flake detection is disabled because the number of new suites is too high.')
|
|
829
865
|
isEarlyFlakeDetectionEnabled = false
|
|
866
|
+
isKnownTestsEnabled = false
|
|
830
867
|
const testEnvironmentOptions = testPaths.tests[0]?.context?.config?.testEnvironmentOptions
|
|
831
868
|
// Project config is shared among all tests, so we can modify it here
|
|
832
869
|
if (testEnvironmentOptions) {
|
|
833
870
|
testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled = false
|
|
871
|
+
testEnvironmentOptions._ddIsKnownTestsEnabled = false
|
|
834
872
|
}
|
|
835
873
|
isEarlyFlakeDetectionFaulty = true
|
|
836
874
|
}
|
|
@@ -901,6 +939,11 @@ addHook({
|
|
|
901
939
|
return runtimePackage
|
|
902
940
|
})
|
|
903
941
|
|
|
942
|
+
/*
|
|
943
|
+
* This hook does two things:
|
|
944
|
+
* - Pass known tests to the workers.
|
|
945
|
+
* - Receive trace, coverage and logs payloads from the workers.
|
|
946
|
+
*/
|
|
904
947
|
addHook({
|
|
905
948
|
name: 'jest-worker',
|
|
906
949
|
versions: ['>=24.9.0'],
|
|
@@ -908,7 +951,7 @@ addHook({
|
|
|
908
951
|
}, (childProcessWorker) => {
|
|
909
952
|
const ChildProcessWorker = childProcessWorker.default
|
|
910
953
|
shimmer.wrap(ChildProcessWorker.prototype, 'send', send => function (request) {
|
|
911
|
-
if (!
|
|
954
|
+
if (!isKnownTestsEnabled) {
|
|
912
955
|
return send.apply(this, arguments)
|
|
913
956
|
}
|
|
914
957
|
const [type] = request
|
|
@@ -953,6 +996,12 @@ addHook({
|
|
|
953
996
|
})
|
|
954
997
|
return
|
|
955
998
|
}
|
|
999
|
+
if (code === JEST_WORKER_LOGS_PAYLOAD_CODE) { // datadog logs payload
|
|
1000
|
+
sessionAsyncResource.runInAsyncScope(() => {
|
|
1001
|
+
workerReportLogsCh.publish(data)
|
|
1002
|
+
})
|
|
1003
|
+
return
|
|
1004
|
+
}
|
|
956
1005
|
return _onMessage.apply(this, arguments)
|
|
957
1006
|
})
|
|
958
1007
|
return childProcessWorker
|