dd-trace 5.89.0 → 5.91.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 +0 -3
- package/index.d.ts +38 -0
- package/package.json +12 -11
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +75 -0
- package/packages/datadog-instrumentations/src/cucumber.js +58 -4
- package/packages/datadog-instrumentations/src/elasticsearch.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +30 -0
- package/packages/datadog-instrumentations/src/jest.js +31 -2
- package/packages/datadog-instrumentations/src/langgraph.js +7 -0
- package/packages/datadog-instrumentations/src/mocha/main.js +41 -12
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -1
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -4
- package/packages/datadog-instrumentations/src/playwright.js +20 -2
- package/packages/datadog-instrumentations/src/prisma.js +4 -2
- package/packages/datadog-instrumentations/src/vitest.js +69 -24
- package/packages/datadog-plugin-apollo/src/gateway/execute.js +8 -0
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +5 -0
- package/packages/datadog-plugin-apollo/src/gateway/plan.js +8 -0
- package/packages/datadog-plugin-apollo/src/gateway/postprocessing.js +5 -0
- package/packages/datadog-plugin-apollo/src/gateway/request.js +4 -3
- package/packages/datadog-plugin-apollo/src/gateway/validate.js +4 -3
- package/packages/datadog-plugin-apollo/src/index.js +28 -0
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +49 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +12 -2
- package/packages/datadog-plugin-cypress/src/support.js +5 -7
- package/packages/datadog-plugin-jest/src/index.js +6 -0
- package/packages/datadog-plugin-langgraph/src/index.js +24 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +41 -0
- package/packages/datadog-plugin-playwright/src/index.js +35 -8
- package/packages/dd-trace/src/aiguard/noop.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +14 -5
- package/packages/dd-trace/src/appsec/api_security_sampler.js +22 -1
- package/packages/dd-trace/src/appsec/index.js +11 -1
- package/packages/dd-trace/src/appsec/reporter.js +28 -11
- package/packages/dd-trace/src/appsec/waf/index.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- package/packages/dd-trace/src/config/defaults.js +1 -0
- package/packages/dd-trace/src/config/index.js +9 -1
- package/packages/dd-trace/src/config/supported-configurations.json +14 -0
- package/packages/dd-trace/src/constants.js +2 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -0
- package/packages/dd-trace/src/dogstatsd.js +1 -0
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +1 -8
- package/packages/dd-trace/src/encode/agentless-json.js +67 -22
- package/packages/dd-trace/src/exporters/agentless/index.js +58 -15
- package/packages/dd-trace/src/exporters/agentless/writer.js +35 -18
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/anthropic.js +9 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +11 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +114 -0
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -0
- package/packages/dd-trace/src/plugins/apollo.js +7 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/ci.js +95 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +36 -2
- package/packages/dd-trace/src/plugins/util/test.js +7 -10
- package/packages/dd-trace/src/plugins/util/web.js +31 -11
- package/packages/dd-trace/src/priority_sampler.js +20 -2
- package/packages/dd-trace/src/process-tags/index.js +41 -34
- package/packages/dd-trace/src/profiling/profilers/wall.js +9 -1
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +4 -0
- package/packages/dd-trace/src/standalone/product.js +2 -1
|
@@ -140,7 +140,6 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
140
140
|
if (!testFinishCh.hasSubscribers) {
|
|
141
141
|
return run.apply(this, arguments)
|
|
142
142
|
}
|
|
143
|
-
// Flaky test retries does not work in parallel mode
|
|
144
143
|
if (libraryConfig?.isFlakyTestRetriesEnabled) {
|
|
145
144
|
this.retries(libraryConfig?.flakyTestRetriesCount)
|
|
146
145
|
}
|
|
@@ -289,6 +288,12 @@ function getOnTestEndHandler (config) {
|
|
|
289
288
|
hasFailedAllRetries = true
|
|
290
289
|
}
|
|
291
290
|
|
|
291
|
+
// ATR: set hasFailedAllRetries when all auto test retries were exhausted and every attempt failed
|
|
292
|
+
if (config.isFlakyTestRetriesEnabled && !test._ddIsAttemptToFix && !test._ddIsEfdRetry &&
|
|
293
|
+
getIsLastRetry(test) && testStatuses.every(status => status === 'fail')) {
|
|
294
|
+
hasFailedAllRetries = true
|
|
295
|
+
}
|
|
296
|
+
|
|
292
297
|
const isAttemptToFixRetry = test._ddIsAttemptToFix && testStatuses.length > 1
|
|
293
298
|
const isAtrRetry = config.isFlakyTestRetriesEnabled &&
|
|
294
299
|
!test._ddIsAttemptToFix &&
|
|
@@ -10,6 +10,7 @@ const {
|
|
|
10
10
|
getOnHookEndHandler,
|
|
11
11
|
getOnFailHandler,
|
|
12
12
|
getOnPendingHandler,
|
|
13
|
+
getOnTestRetryHandler,
|
|
13
14
|
getRunTestsWrapper,
|
|
14
15
|
} = require('./utils')
|
|
15
16
|
require('./common')
|
|
@@ -42,12 +43,18 @@ addHook({
|
|
|
42
43
|
}
|
|
43
44
|
if (this.options._ddIsTestManagementTestsEnabled) {
|
|
44
45
|
config.isTestManagementTestsEnabled = true
|
|
45
|
-
|
|
46
|
-
// config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries
|
|
46
|
+
config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries
|
|
47
47
|
config.testManagementTests = this.options._ddTestManagementTests
|
|
48
48
|
delete this.options._ddIsTestManagementTestsEnabled
|
|
49
|
+
delete this.options._ddTestManagementAttemptToFixRetries
|
|
49
50
|
delete this.options._ddTestManagementTests
|
|
50
51
|
}
|
|
52
|
+
if (this.options._ddIsFlakyTestRetriesEnabled) {
|
|
53
|
+
config.isFlakyTestRetriesEnabled = true
|
|
54
|
+
config.flakyTestRetriesCount = this.options._ddFlakyTestRetriesCount
|
|
55
|
+
delete this.options._ddIsFlakyTestRetriesEnabled
|
|
56
|
+
delete this.options._ddFlakyTestRetriesCount
|
|
57
|
+
}
|
|
51
58
|
return run.apply(this, arguments)
|
|
52
59
|
})
|
|
53
60
|
|
|
@@ -74,6 +81,8 @@ addHook({
|
|
|
74
81
|
|
|
75
82
|
this.on('test end', getOnTestEndHandler(config))
|
|
76
83
|
|
|
84
|
+
this.on('retry', getOnTestRetryHandler(config))
|
|
85
|
+
|
|
77
86
|
// If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
|
|
78
87
|
this.on('hook end', getOnHookEndHandler())
|
|
79
88
|
|
|
@@ -92,5 +101,4 @@ addHook({
|
|
|
92
101
|
name: 'mocha',
|
|
93
102
|
versions: ['>=5.2.0'],
|
|
94
103
|
file: 'lib/runnable.js',
|
|
95
|
-
}, runnableWrapper)
|
|
96
|
-
// TODO: parallel mode does not support flaky test retries, so no library config is passed.
|
|
104
|
+
}, (runnablePackage) => runnableWrapper(runnablePackage, config))
|
|
@@ -302,6 +302,7 @@ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
|
|
|
302
302
|
const {
|
|
303
303
|
_requireFile: testSuiteAbsolutePath,
|
|
304
304
|
location: {
|
|
305
|
+
file: testSourceFileAbsolutePath,
|
|
305
306
|
line: testSourceLine,
|
|
306
307
|
},
|
|
307
308
|
_type,
|
|
@@ -319,7 +320,7 @@ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
|
|
|
319
320
|
|
|
320
321
|
if (isNewTestSuite) {
|
|
321
322
|
startedSuites.push(testSuiteAbsolutePath)
|
|
322
|
-
const testSuiteCtx = { testSuiteAbsolutePath }
|
|
323
|
+
const testSuiteCtx = { testSuiteAbsolutePath, testSourceFileAbsolutePath }
|
|
323
324
|
testSuiteToCtx.set(testSuiteAbsolutePath, testSuiteCtx)
|
|
324
325
|
testSuiteStartCh.runStores(testSuiteCtx, () => {})
|
|
325
326
|
}
|
|
@@ -335,6 +336,7 @@ function testBeginHandler (test, browserName, shouldCreateTestSpan) {
|
|
|
335
336
|
const testCtx = {
|
|
336
337
|
testName,
|
|
337
338
|
testSuiteAbsolutePath,
|
|
339
|
+
testSourceFileAbsolutePath,
|
|
338
340
|
testSourceLine,
|
|
339
341
|
browserName,
|
|
340
342
|
isDisabled: test._ddIsDisabled,
|
|
@@ -404,6 +406,15 @@ function testEndHandler ({
|
|
|
404
406
|
test._ddHasFailedAllRetries = true
|
|
405
407
|
}
|
|
406
408
|
|
|
409
|
+
// ATR: set _ddHasFailedAllRetries when all auto test retries were exhausted and every attempt failed
|
|
410
|
+
if (isFlakyTestRetriesEnabled && !testProperties.attemptToFix && !test._ddIsEfdRetry &&
|
|
411
|
+
!(test._ddIsNew || test._ddIsModified) &&
|
|
412
|
+
flakyTestRetriesCount != null && flakyTestRetriesCount > 0 &&
|
|
413
|
+
testStatuses.length === flakyTestRetriesCount + 1 &&
|
|
414
|
+
testStatuses.every(status => status === 'fail')) {
|
|
415
|
+
test._ddHasFailedAllRetries = true
|
|
416
|
+
}
|
|
417
|
+
|
|
407
418
|
// this handles tests that do not go through the worker process (because they're skipped)
|
|
408
419
|
if (shouldCreateTestSpan) {
|
|
409
420
|
const testResult = results.at(-1)
|
|
@@ -459,6 +470,7 @@ function testEndHandler ({
|
|
|
459
470
|
testSkipCh.publish({
|
|
460
471
|
testName: getTestFullname(test),
|
|
461
472
|
testSuiteAbsolutePath,
|
|
473
|
+
testSourceFileAbsolutePath: test.location.file,
|
|
462
474
|
testSourceLine: test.location.line,
|
|
463
475
|
browserName,
|
|
464
476
|
isNew: test._ddIsNew,
|
|
@@ -1144,6 +1156,7 @@ addHook({
|
|
|
1144
1156
|
const {
|
|
1145
1157
|
_requireFile: testSuiteAbsolutePath,
|
|
1146
1158
|
location: {
|
|
1159
|
+
file: testSourceFileAbsolutePath,
|
|
1147
1160
|
line: testSourceLine,
|
|
1148
1161
|
},
|
|
1149
1162
|
} = test
|
|
@@ -1159,6 +1172,7 @@ addHook({
|
|
|
1159
1172
|
const testCtx = {
|
|
1160
1173
|
testName,
|
|
1161
1174
|
testSuiteAbsolutePath,
|
|
1175
|
+
testSourceFileAbsolutePath,
|
|
1162
1176
|
testSourceLine,
|
|
1163
1177
|
browserName,
|
|
1164
1178
|
}
|
|
@@ -1322,7 +1336,10 @@ function generateSummaryWrapper (generateSummary) {
|
|
|
1322
1336
|
if (didNotRun) {
|
|
1323
1337
|
const {
|
|
1324
1338
|
_requireFile: testSuiteAbsolutePath,
|
|
1325
|
-
location: {
|
|
1339
|
+
location: {
|
|
1340
|
+
file: testSourceFileAbsolutePath,
|
|
1341
|
+
line: testSourceLine,
|
|
1342
|
+
},
|
|
1326
1343
|
_ddIsNew: isNew,
|
|
1327
1344
|
_ddIsDisabled: isDisabled,
|
|
1328
1345
|
_ddIsModified: isModified,
|
|
@@ -1333,6 +1350,7 @@ function generateSummaryWrapper (generateSummary) {
|
|
|
1333
1350
|
testSkipCh.publish({
|
|
1334
1351
|
testName: getTestFullname(test),
|
|
1335
1352
|
testSuiteAbsolutePath,
|
|
1353
|
+
testSourceFileAbsolutePath,
|
|
1336
1354
|
testSourceLine,
|
|
1337
1355
|
browserName,
|
|
1338
1356
|
isNew,
|
|
@@ -172,8 +172,10 @@ const prismaHook = (runtime, versions, name, isIitm) => {
|
|
|
172
172
|
prismaHelperInit.publish(prismaHelperCtx)
|
|
173
173
|
|
|
174
174
|
const helper = prismaHelperCtx.helper
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
if (helper) {
|
|
176
|
+
this._tracingHelper = helper
|
|
177
|
+
this._engine.tracingHelper = helper
|
|
178
|
+
}
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
}
|
|
@@ -95,6 +95,7 @@ function getProvidedContext () {
|
|
|
95
95
|
_ddTestManagementAttemptToFixRetries: testManagementAttemptToFixRetries,
|
|
96
96
|
_ddTestManagementTests: testManagementTests,
|
|
97
97
|
_ddIsFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled,
|
|
98
|
+
_ddFlakyTestRetriesCount: flakyTestRetriesCount,
|
|
98
99
|
_ddIsImpactedTestsEnabled: isImpactedTestsEnabled,
|
|
99
100
|
_ddModifiedFiles: modifiedFiles,
|
|
100
101
|
} = globalThis.__vitest_worker__.providedContext
|
|
@@ -109,6 +110,7 @@ function getProvidedContext () {
|
|
|
109
110
|
testManagementAttemptToFixRetries,
|
|
110
111
|
testManagementTests,
|
|
111
112
|
isFlakyTestRetriesEnabled,
|
|
113
|
+
flakyTestRetriesCount: flakyTestRetriesCount ?? 0,
|
|
112
114
|
isImpactedTestsEnabled,
|
|
113
115
|
modifiedFiles,
|
|
114
116
|
}
|
|
@@ -124,6 +126,7 @@ function getProvidedContext () {
|
|
|
124
126
|
testManagementAttemptToFixRetries: 0,
|
|
125
127
|
testManagementTests: {},
|
|
126
128
|
isFlakyTestRetriesEnabled: false,
|
|
129
|
+
flakyTestRetriesCount: 0,
|
|
127
130
|
isImpactedTestsEnabled: false,
|
|
128
131
|
modifiedFiles: {},
|
|
129
132
|
}
|
|
@@ -143,8 +146,23 @@ function isReporterPackageNewest (vitestPackage) {
|
|
|
143
146
|
return vitestPackage.h?.name === 'BaseSequencer'
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Finds an export by its `.name` property in a minified vitest chunk.
|
|
151
|
+
* Minified export keys change across versions, so we search by function/class name.
|
|
152
|
+
* @param {object} pkg - The module exports object
|
|
153
|
+
* @param {string} name - The `.name` value to look for
|
|
154
|
+
* @returns {{ key: string, value: Function } | undefined}
|
|
155
|
+
*/
|
|
156
|
+
function findExportByName (pkg, name) {
|
|
157
|
+
for (const [key, value] of Object.entries(pkg)) {
|
|
158
|
+
if (value?.name === name) {
|
|
159
|
+
return { key, value }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getBaseSequencerExport (vitestPackage) {
|
|
165
|
+
return findExportByName(vitestPackage, 'BaseSequencer')
|
|
148
166
|
}
|
|
149
167
|
|
|
150
168
|
function getChannelPromise (channelToPublishTo, frameworkVersion) {
|
|
@@ -154,19 +172,19 @@ function getChannelPromise (channelToPublishTo, frameworkVersion) {
|
|
|
154
172
|
}
|
|
155
173
|
|
|
156
174
|
function isCliApiPackage (vitestPackage) {
|
|
157
|
-
return vitestPackage
|
|
175
|
+
return !!findExportByName(vitestPackage, 'startVitest')
|
|
158
176
|
}
|
|
159
177
|
|
|
160
|
-
function
|
|
161
|
-
return testPackage
|
|
178
|
+
function getTestRunnerExport (testPackage) {
|
|
179
|
+
return findExportByName(testPackage, 'VitestTestRunner') || findExportByName(testPackage, 'TestRunner')
|
|
162
180
|
}
|
|
163
181
|
|
|
164
|
-
function
|
|
165
|
-
return vitestPackage
|
|
182
|
+
function getForksPoolWorkerExport (vitestPackage) {
|
|
183
|
+
return findExportByName(vitestPackage, 'ForksPoolWorker')
|
|
166
184
|
}
|
|
167
185
|
|
|
168
|
-
function
|
|
169
|
-
return vitestPackage
|
|
186
|
+
function getThreadsPoolWorkerExport (vitestPackage) {
|
|
187
|
+
return findExportByName(vitestPackage, 'ThreadsPoolWorker')
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
function getSessionStatus (state) {
|
|
@@ -260,6 +278,7 @@ function getSortWrapper (sort, frameworkVersion) {
|
|
|
260
278
|
? this.ctx.getCoreWorkspaceProject()
|
|
261
279
|
: this.ctx.getRootProject()
|
|
262
280
|
workspaceProject._provided._ddIsFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
|
|
281
|
+
workspaceProject._provided._ddFlakyTestRetriesCount = flakyTestRetriesCount
|
|
263
282
|
} catch {
|
|
264
283
|
log.warn('Could not send library configuration to workers.')
|
|
265
284
|
}
|
|
@@ -443,7 +462,11 @@ function getCliOrStartVitestWrapper (frameworkVersion) {
|
|
|
443
462
|
}
|
|
444
463
|
|
|
445
464
|
function getCreateCliWrapper (vitestPackage, frameworkVersion) {
|
|
446
|
-
|
|
465
|
+
const createCliExport = findExportByName(vitestPackage, 'createCLI')
|
|
466
|
+
if (!createCliExport) {
|
|
467
|
+
return vitestPackage
|
|
468
|
+
}
|
|
469
|
+
shimmer.wrap(vitestPackage, createCliExport.key, getCliOrStartVitestWrapper(frameworkVersion))
|
|
447
470
|
|
|
448
471
|
return vitestPackage
|
|
449
472
|
}
|
|
@@ -530,27 +553,30 @@ function getStartVitestWrapper (cliApiPackage, frameworkVersion) {
|
|
|
530
553
|
if (!isCliApiPackage(cliApiPackage)) {
|
|
531
554
|
return cliApiPackage
|
|
532
555
|
}
|
|
533
|
-
|
|
556
|
+
const startVitestExport = findExportByName(cliApiPackage, 'startVitest')
|
|
557
|
+
shimmer.wrap(cliApiPackage, startVitestExport.key, getCliOrStartVitestWrapper(frameworkVersion))
|
|
534
558
|
|
|
535
|
-
|
|
559
|
+
const forksPoolWorker = getForksPoolWorkerExport(cliApiPackage)
|
|
560
|
+
if (forksPoolWorker) {
|
|
536
561
|
// function is async
|
|
537
|
-
shimmer.wrap(
|
|
562
|
+
shimmer.wrap(forksPoolWorker.value.prototype, 'start', start => function () {
|
|
538
563
|
vitestPool = 'child_process'
|
|
539
564
|
this.env.DD_VITEST_WORKER = '1'
|
|
540
565
|
|
|
541
566
|
return start.apply(this, arguments)
|
|
542
567
|
})
|
|
543
|
-
shimmer.wrap(
|
|
568
|
+
shimmer.wrap(forksPoolWorker.value.prototype, 'on', getWrappedOn)
|
|
544
569
|
}
|
|
545
570
|
|
|
546
|
-
|
|
571
|
+
const threadsPoolWorker = getThreadsPoolWorkerExport(cliApiPackage)
|
|
572
|
+
if (threadsPoolWorker) {
|
|
547
573
|
// function is async
|
|
548
|
-
shimmer.wrap(
|
|
574
|
+
shimmer.wrap(threadsPoolWorker.value.prototype, 'start', start => function () {
|
|
549
575
|
vitestPool = 'worker_threads'
|
|
550
576
|
this.env.DD_VITEST_WORKER = '1'
|
|
551
577
|
return start.apply(this, arguments)
|
|
552
578
|
})
|
|
553
|
-
shimmer.wrap(
|
|
579
|
+
shimmer.wrap(threadsPoolWorker.value.prototype, 'on', getWrappedOn)
|
|
554
580
|
}
|
|
555
581
|
return cliApiPackage
|
|
556
582
|
}
|
|
@@ -657,6 +683,9 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
657
683
|
}
|
|
658
684
|
task.result.state = 'pass'
|
|
659
685
|
} else if (isQuarantined) {
|
|
686
|
+
if (task.result.state === 'fail') {
|
|
687
|
+
switchedStatuses.add(task)
|
|
688
|
+
}
|
|
660
689
|
task.result.state = 'pass'
|
|
661
690
|
}
|
|
662
691
|
}
|
|
@@ -740,7 +769,10 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
740
769
|
}
|
|
741
770
|
|
|
742
771
|
const lastExecutionStatus = task.result.state
|
|
743
|
-
const
|
|
772
|
+
const isAtf = attemptToFixTasks.has(task)
|
|
773
|
+
const isQuarantinedOrDisabledAtf = isAtf && (quarantinedTasks.has(task) || disabledTasks.has(task))
|
|
774
|
+
const shouldTrackStatuses = isEarlyFlakeDetectionEnabled || isAtf
|
|
775
|
+
const shouldFlipStatus = isEarlyFlakeDetectionEnabled || isQuarantinedOrDisabledAtf
|
|
744
776
|
const statuses = taskToStatuses.get(task)
|
|
745
777
|
|
|
746
778
|
// These clauses handle task.repeats, whether EFD is enabled or not
|
|
@@ -758,8 +790,10 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
758
790
|
} else {
|
|
759
791
|
testPassCh.publish({ task, ...ctx.currentStore })
|
|
760
792
|
}
|
|
761
|
-
if (
|
|
793
|
+
if (shouldTrackStatuses) {
|
|
762
794
|
statuses.push(lastExecutionStatus)
|
|
795
|
+
}
|
|
796
|
+
if (shouldFlipStatus) {
|
|
763
797
|
// If we don't "reset" the result.state to "pass", once a repetition fails,
|
|
764
798
|
// vitest will always consider the test as failed, so we can't read the actual status
|
|
765
799
|
// This means that we change vitest's behavior:
|
|
@@ -769,7 +803,7 @@ function wrapVitestTestRunner (VitestTestRunner) {
|
|
|
769
803
|
}
|
|
770
804
|
}
|
|
771
805
|
} else if (numRepetition === task.repeats) {
|
|
772
|
-
if (
|
|
806
|
+
if (shouldTrackStatuses) {
|
|
773
807
|
statuses.push(lastExecutionStatus)
|
|
774
808
|
}
|
|
775
809
|
|
|
@@ -857,11 +891,12 @@ addHook({
|
|
|
857
891
|
versions: ['>=4.0.0'],
|
|
858
892
|
filePattern: 'dist/chunks/test.*',
|
|
859
893
|
}, (testPackage) => {
|
|
860
|
-
|
|
894
|
+
const testRunner = getTestRunnerExport(testPackage)
|
|
895
|
+
if (!testRunner) {
|
|
861
896
|
return testPackage
|
|
862
897
|
}
|
|
863
898
|
|
|
864
|
-
wrapVitestTestRunner(
|
|
899
|
+
wrapVitestTestRunner(testRunner.value)
|
|
865
900
|
|
|
866
901
|
return testPackage
|
|
867
902
|
})
|
|
@@ -930,8 +965,9 @@ addHook({
|
|
|
930
965
|
versions: ['>=3.0.9'],
|
|
931
966
|
filePattern: 'dist/chunks/coverage.*',
|
|
932
967
|
}, (coveragePackage) => {
|
|
933
|
-
|
|
934
|
-
|
|
968
|
+
const baseSequencer = getBaseSequencerExport(coveragePackage)
|
|
969
|
+
if (baseSequencer) {
|
|
970
|
+
shimmer.wrap(baseSequencer.value.prototype, 'sort', getSortWrapper)
|
|
935
971
|
}
|
|
936
972
|
return coveragePackage
|
|
937
973
|
})
|
|
@@ -1047,6 +1083,15 @@ addHook({
|
|
|
1047
1083
|
}
|
|
1048
1084
|
}
|
|
1049
1085
|
|
|
1086
|
+
// ATR: set hasFailedAllRetries when all auto test retries were exhausted and every attempt failed
|
|
1087
|
+
if (providedContext.isFlakyTestRetriesEnabled && !attemptToFixTasks.has(task) &&
|
|
1088
|
+
!newTasks.has(task) && !modifiedTasks.has(task)) {
|
|
1089
|
+
const maxRetries = providedContext.flakyTestRetriesCount ?? 0
|
|
1090
|
+
if (maxRetries > 0 && task.result?.retryCount === maxRetries) {
|
|
1091
|
+
hasFailedAllRetries = true
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1050
1095
|
if (testCtx) {
|
|
1051
1096
|
const isRetry = task.result?.retryCount > 0
|
|
1052
1097
|
// `duration` is the duration of all the retries, so it can't be used if there are retries
|
|
@@ -5,6 +5,14 @@ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
|
|
|
5
5
|
class ApolloGatewayExecutePlugin extends ApolloBasePlugin {
|
|
6
6
|
static operation = 'execute'
|
|
7
7
|
static prefix = 'tracing:apm:apollo:gateway:execute'
|
|
8
|
+
|
|
9
|
+
onAsyncStart (ctx) {
|
|
10
|
+
const span = ctx?.currentStore?.span
|
|
11
|
+
|
|
12
|
+
if (!span) return
|
|
13
|
+
|
|
14
|
+
this.config.hooks.execute(span, ctx)
|
|
15
|
+
}
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
module.exports = ApolloGatewayExecutePlugin
|
|
@@ -29,6 +29,11 @@ class ApolloGatewayFetchPlugin extends ApolloBasePlugin {
|
|
|
29
29
|
|
|
30
30
|
return ctx.currentStore
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
onAsyncStart (ctx) {
|
|
34
|
+
const span = ctx?.currentStore?.span
|
|
35
|
+
this.config.hooks.fetch(span, ctx)
|
|
36
|
+
}
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
module.exports = ApolloGatewayFetchPlugin
|
|
@@ -5,6 +5,14 @@ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
|
|
|
5
5
|
class ApolloGatewayPlanPlugin extends ApolloBasePlugin {
|
|
6
6
|
static operation = 'plan'
|
|
7
7
|
static prefix = 'tracing:apm:apollo:gateway:plan'
|
|
8
|
+
|
|
9
|
+
onEnd (ctx) {
|
|
10
|
+
const span = ctx?.currentStore?.span
|
|
11
|
+
|
|
12
|
+
if (!span) return
|
|
13
|
+
|
|
14
|
+
this.config.hooks.plan(span, ctx)
|
|
15
|
+
}
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
module.exports = ApolloGatewayPlanPlugin
|
|
@@ -5,6 +5,11 @@ const ApolloBasePlugin = require('../../../dd-trace/src/plugins/apollo')
|
|
|
5
5
|
class ApolloGatewayPostProcessingPlugin extends ApolloBasePlugin {
|
|
6
6
|
static operation = 'postprocessing'
|
|
7
7
|
static prefix = 'tracing:apm:apollo:gateway:postprocessing'
|
|
8
|
+
|
|
9
|
+
onAsyncStart (ctx) {
|
|
10
|
+
const span = ctx?.currentStore?.span
|
|
11
|
+
this.config.hooks.postprocessing(span, ctx)
|
|
12
|
+
}
|
|
8
13
|
}
|
|
9
14
|
|
|
10
15
|
module.exports = ApolloGatewayPostProcessingPlugin
|
|
@@ -52,15 +52,16 @@ class ApolloGatewayRequestPlugin extends ApolloBasePlugin {
|
|
|
52
52
|
return ctx.currentStore
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
onAsyncStart (ctx) {
|
|
56
56
|
const errors = ctx?.result?.errors
|
|
57
57
|
// apollo gateway catches certain errors and returns them in the result object
|
|
58
58
|
// we want to capture these errors as spans
|
|
59
59
|
if (Array.isArray(errors) && errors.at(-1)?.stack && errors.at(-1).message) {
|
|
60
60
|
ctx.currentStore.span.setTag('error', errors.at(-1))
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
|
|
63
|
+
const span = ctx?.currentStore?.span
|
|
64
|
+
this.config.hooks.request(span, ctx)
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -6,16 +6,17 @@ class ApolloGatewayValidatePlugin extends ApolloBasePlugin {
|
|
|
6
6
|
static operation = 'validate'
|
|
7
7
|
static prefix = 'tracing:apm:apollo:gateway:validate'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
onEnd (ctx) {
|
|
10
10
|
const result = ctx.result
|
|
11
|
-
const span = ctx
|
|
11
|
+
const span = ctx?.currentStore?.span
|
|
12
12
|
|
|
13
13
|
if (!span) return
|
|
14
14
|
|
|
15
15
|
if (Array.isArray(result) && result.at(-1)?.stack && result.at(-1).message) {
|
|
16
16
|
span.setTag('error', result.at(-1))
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
|
|
19
|
+
this.config.hooks.validate(span, ctx)
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
@@ -10,6 +10,34 @@ class ApolloPlugin extends CompositePlugin {
|
|
|
10
10
|
gateway: ApolloGatewayPlugin,
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @override
|
|
16
|
+
*/
|
|
17
|
+
configure (config) {
|
|
18
|
+
return super.configure(validateConfig(config))
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const noop = () => {}
|
|
23
|
+
|
|
24
|
+
function validateConfig (config) {
|
|
25
|
+
return {
|
|
26
|
+
...config,
|
|
27
|
+
hooks: getHooks(config),
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getHooks (config) {
|
|
32
|
+
const hooks = config?.hooks
|
|
33
|
+
const request = hooks?.request ?? noop
|
|
34
|
+
const validate = hooks?.validate ?? noop
|
|
35
|
+
const plan = hooks?.plan ?? noop
|
|
36
|
+
const execute = hooks?.execute ?? noop
|
|
37
|
+
const fetch = hooks?.fetch ?? noop
|
|
38
|
+
const postprocessing = hooks?.postprocessing ?? noop
|
|
39
|
+
|
|
40
|
+
return { request, validate, plan, execute, fetch, postprocessing }
|
|
13
41
|
}
|
|
14
42
|
|
|
15
43
|
module.exports = ApolloPlugin
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
|
|
5
|
+
class AzureDurableFunctionsPlugin extends TracingPlugin {
|
|
6
|
+
static get id () { return 'azure-durable-functions' }
|
|
7
|
+
static get operation () { return 'invoke' }
|
|
8
|
+
static get prefix () { return 'tracing:datadog:azure:durable-functions:invoke' }
|
|
9
|
+
static get type () { return 'serverless' }
|
|
10
|
+
static get kind () { return 'server' }
|
|
11
|
+
|
|
12
|
+
bindStart (ctx) {
|
|
13
|
+
const span = this.startSpan(this.operationName(), {
|
|
14
|
+
kind: 'internal',
|
|
15
|
+
type: 'serverless',
|
|
16
|
+
|
|
17
|
+
meta: {
|
|
18
|
+
component: 'azure-functions',
|
|
19
|
+
'aas.function.name': ctx.functionName,
|
|
20
|
+
'aas.function.trigger': ctx.trigger,
|
|
21
|
+
'resource.name': `${ctx.trigger} ${ctx.functionName}`,
|
|
22
|
+
},
|
|
23
|
+
}, ctx)
|
|
24
|
+
|
|
25
|
+
// in the case of entity functions, operationName should be available
|
|
26
|
+
if (ctx.operationName) {
|
|
27
|
+
span.setTag('aas.function.operation', ctx.operationName)
|
|
28
|
+
span.setTag('resource.name', `${ctx.trigger} ${ctx.functionName} ${ctx.operationName}`
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
ctx.span = span
|
|
33
|
+
return ctx.currentStore
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
end (ctx) {
|
|
37
|
+
// We only want to run finish here if this is a synchronous operation
|
|
38
|
+
// Only synchronous operations would have `result` or `error` on `end`
|
|
39
|
+
// So we skip operations that dont
|
|
40
|
+
if (!ctx.hasOwnProperty('result') && !ctx.hasOwnProperty('error')) return
|
|
41
|
+
super.finish(ctx)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
asyncStart (ctx) {
|
|
45
|
+
super.finish(ctx)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = AzureDurableFunctionsPlugin
|
|
@@ -247,6 +247,7 @@ class CypressPlugin {
|
|
|
247
247
|
isSuitesSkippingEnabled = false
|
|
248
248
|
isCodeCoverageEnabled = false
|
|
249
249
|
isFlakyTestRetriesEnabled = false
|
|
250
|
+
flakyTestRetriesCount = 0
|
|
250
251
|
isEarlyFlakeDetectionEnabled = false
|
|
251
252
|
isKnownTestsEnabled = false
|
|
252
253
|
earlyFlakeDetectionNumRetries = 0
|
|
@@ -354,7 +355,10 @@ class CypressPlugin {
|
|
|
354
355
|
this.isKnownTestsEnabled = isKnownTestsEnabled
|
|
355
356
|
if (isFlakyTestRetriesEnabled && this.isTestIsolationEnabled) {
|
|
356
357
|
this.isFlakyTestRetriesEnabled = true
|
|
357
|
-
this.
|
|
358
|
+
this.flakyTestRetriesCount = flakyTestRetriesCount ?? 0
|
|
359
|
+
this.cypressConfig.retries.runMode = this.flakyTestRetriesCount
|
|
360
|
+
} else {
|
|
361
|
+
this.flakyTestRetriesCount = 0
|
|
358
362
|
}
|
|
359
363
|
this.isTestManagementTestsEnabled = isTestManagementEnabled
|
|
360
364
|
this.testManagementAttemptToFixRetries = testManagementAttemptToFixRetries
|
|
@@ -603,7 +607,7 @@ class CypressPlugin {
|
|
|
603
607
|
[TEST_SESSION_NAME]: testSessionName,
|
|
604
608
|
}
|
|
605
609
|
}
|
|
606
|
-
const libraryCapabilitiesTags = getLibraryCapabilitiesTags(this.constructor.id,
|
|
610
|
+
const libraryCapabilitiesTags = getLibraryCapabilitiesTags(this.constructor.id, this.frameworkVersion)
|
|
607
611
|
metadataTags.test = {
|
|
608
612
|
...metadataTags.test,
|
|
609
613
|
...libraryCapabilitiesTags,
|
|
@@ -1019,6 +1023,12 @@ class CypressPlugin {
|
|
|
1019
1023
|
}
|
|
1020
1024
|
}
|
|
1021
1025
|
}
|
|
1026
|
+
// ATR: set TEST_HAS_FAILED_ALL_RETRIES when all auto test retries were exhausted and every attempt failed
|
|
1027
|
+
if (this.isFlakyTestRetriesEnabled && !isAttemptToFix && !isEfdRetry &&
|
|
1028
|
+
this.flakyTestRetriesCount > 0 && testStatuses.length === this.flakyTestRetriesCount + 1 &&
|
|
1029
|
+
testStatuses.every(status => status === 'fail')) {
|
|
1030
|
+
this.activeTestSpan.setTag(TEST_HAS_FAILED_ALL_RETRIES, 'true')
|
|
1031
|
+
}
|
|
1022
1032
|
|
|
1023
1033
|
// Ensure quarantined tests reported from support.js are tagged
|
|
1024
1034
|
// (This catches cases where the test ran but failed, but Cypress saw it as passed)
|
|
@@ -61,18 +61,16 @@ Cypress.on('fail', (err, runnable) => {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const testName = runnable.fullTitle()
|
|
64
|
-
const { isQuarantined,
|
|
64
|
+
const { isQuarantined, isDisabled } = getTestProperties(testName)
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
// This
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
// Suppress failures for quarantined or disabled tests so they don't affect the exit code.
|
|
67
|
+
// This applies regardless of attempt-to-fix status: per spec, quarantined/disabled test
|
|
68
|
+
// results are always ignored.
|
|
69
|
+
if (isQuarantined || isDisabled) {
|
|
70
70
|
quarantinedTestErrors.set(testName, err)
|
|
71
|
-
// Don't re-throw - this prevents Cypress from marking the test as failed
|
|
72
71
|
return
|
|
73
72
|
}
|
|
74
73
|
|
|
75
|
-
// For all other tests (including attemptToFix), let the error propagate normally
|
|
76
74
|
throw err
|
|
77
75
|
})
|
|
78
76
|
|
|
@@ -386,6 +386,12 @@ class JestPlugin extends CiPlugin {
|
|
|
386
386
|
return ctx.currentStore
|
|
387
387
|
})
|
|
388
388
|
|
|
389
|
+
this.addBind('ci:jest:test-suite:hook:fn', (ctx) => {
|
|
390
|
+
const testSuiteSpan = this.testSuiteSpanPerTestSuiteAbsolutePath.get(ctx.testSuiteAbsolutePath)
|
|
391
|
+
const store = storage('legacy').getStore()
|
|
392
|
+
return { ...store, span: testSuiteSpan }
|
|
393
|
+
})
|
|
394
|
+
|
|
389
395
|
this.addSub('ci:jest:test:finish', ({
|
|
390
396
|
span,
|
|
391
397
|
status,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const CompositePlugin = require('../../dd-trace/src/plugins/composite')
|
|
4
|
+
const langgraphLLMObsPlugins = require('../../dd-trace/src/llmobs/plugins/langgraph')
|
|
5
|
+
const streamPlugin = require('./stream')
|
|
6
|
+
|
|
7
|
+
const plugins = {}
|
|
8
|
+
|
|
9
|
+
// CRITICAL: LLMObs plugins MUST come first
|
|
10
|
+
for (const Plugin of langgraphLLMObsPlugins) {
|
|
11
|
+
plugins[Plugin.id] = Plugin
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Tracing plugins second
|
|
15
|
+
for (const Plugin of streamPlugin) {
|
|
16
|
+
plugins[Plugin.id] = Plugin
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class LanggraphPlugin extends CompositePlugin {
|
|
20
|
+
static id = 'langgraph'
|
|
21
|
+
static plugins = plugins
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = LanggraphPlugin
|