dd-trace 5.86.0 → 5.88.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 +60 -32
- package/ext/exporters.d.ts +1 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +243 -7
- package/package.json +9 -6
- package/packages/datadog-instrumentations/src/ai.js +54 -90
- package/packages/datadog-instrumentations/src/cucumber.js +14 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +17 -11
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +55 -14
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +15 -13
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/ai.js +103 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.js +108 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +21 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +138 -12
- package/packages/datadog-instrumentations/src/http/client.js +119 -1
- package/packages/datadog-instrumentations/src/jest.js +179 -15
- package/packages/datadog-instrumentations/src/kafkajs.js +20 -17
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
- package/packages/datadog-instrumentations/src/mysql2.js +131 -64
- package/packages/datadog-instrumentations/src/playwright.js +9 -1
- package/packages/datadog-instrumentations/src/stripe.js +92 -0
- package/packages/datadog-instrumentations/src/vitest.js +11 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +14 -10
- package/packages/datadog-plugin-amqplib/src/producer.js +23 -19
- package/packages/datadog-plugin-azure-functions/src/index.js +53 -37
- package/packages/datadog-plugin-bullmq/src/consumer.js +33 -11
- package/packages/datadog-plugin-bullmq/src/producer.js +60 -31
- package/packages/datadog-plugin-cucumber/src/index.js +9 -6
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +33 -0
- package/packages/datadog-plugin-cypress/src/support.js +48 -8
- package/packages/datadog-plugin-jest/src/index.js +12 -2
- package/packages/datadog-plugin-jest/src/util.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +22 -12
- package/packages/datadog-plugin-kafkajs/src/producer.js +33 -22
- package/packages/datadog-plugin-mocha/src/index.js +9 -6
- package/packages/datadog-plugin-playwright/src/index.js +10 -6
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/dd-trace/src/appsec/addresses.js +11 -0
- package/packages/dd-trace/src/appsec/channels.js +5 -1
- package/packages/dd-trace/src/appsec/downstream_requests.js +302 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +4 -5
- package/packages/dd-trace/src/appsec/iast/path-line.js +36 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +3 -2
- package/packages/dd-trace/src/appsec/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +66 -4
- package/packages/dd-trace/src/azure_metadata.js +0 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +14 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/ci-visibility/requests/request.js +236 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +148 -195
- package/packages/dd-trace/src/config/helper.js +43 -1
- package/packages/dd-trace/src/config/index.js +42 -14
- package/packages/dd-trace/src/config/supported-configurations.json +4115 -510
- package/packages/dd-trace/src/constants.js +0 -2
- package/packages/dd-trace/src/crashtracking/crashtracker.js +10 -3
- package/packages/dd-trace/src/datastreams/pathway.js +22 -3
- package/packages/dd-trace/src/datastreams/processor.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +47 -2
- package/packages/dd-trace/src/debugger/devtools_client/index.js +75 -23
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +23 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +3 -3
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +168 -36
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +18 -0
- package/packages/dd-trace/src/encode/agentless-json.js +141 -0
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/writer.js +22 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +89 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +184 -0
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +4 -4
- package/packages/dd-trace/src/llmobs/constants/writers.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -3
- package/packages/dd-trace/src/llmobs/sdk.js +34 -5
- package/packages/dd-trace/src/opentelemetry/context_manager.js +19 -46
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +3 -4
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -4
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -5
- package/packages/dd-trace/src/plugins/database.js +57 -45
- package/packages/dd-trace/src/plugins/outbound.js +27 -2
- package/packages/dd-trace/src/plugins/tracing.js +39 -4
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +7 -0
- package/packages/dd-trace/src/plugins/util/test.js +48 -0
- package/packages/dd-trace/src/plugins/util/web.js +8 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -0
- package/packages/dd-trace/src/propagation-hash/index.js +145 -0
- package/packages/dd-trace/src/proxy.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +1 -1
- package/packages/dd-trace/src/startup-log.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/bullmq.json +0 -106
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +0 -741
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +0 -11
- package/packages/dd-trace/src/plugins/util/serverless.js +0 -8
- package/packages/dd-trace/src/scope/noop/scope.js +0 -21
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
getFormattedJestTestParameters,
|
|
22
22
|
getJestTestName,
|
|
23
23
|
getJestSuitesToRun,
|
|
24
|
+
getEfdRetryCount,
|
|
24
25
|
} = require('../../datadog-plugin-jest/src/util')
|
|
25
26
|
const { addHook, channel } = require('./helpers/instrument')
|
|
26
27
|
|
|
@@ -76,6 +77,7 @@ let hasUnskippableSuites = false
|
|
|
76
77
|
let hasForcedToRunSuites = false
|
|
77
78
|
let isEarlyFlakeDetectionEnabled = false
|
|
78
79
|
let earlyFlakeDetectionNumRetries = 0
|
|
80
|
+
let earlyFlakeDetectionSlowTestRetries = {}
|
|
79
81
|
let earlyFlakeDetectionFaultyThreshold = 30
|
|
80
82
|
let isEarlyFlakeDetectionFaulty = false
|
|
81
83
|
let hasFilteredSkippableSuites = false
|
|
@@ -95,6 +97,12 @@ const attemptToFixRetriedTestsStatuses = new Map()
|
|
|
95
97
|
const wrappedWorkers = new WeakSet()
|
|
96
98
|
const testSuiteMockedFiles = new Map()
|
|
97
99
|
const testsToBeRetried = new Set()
|
|
100
|
+
// Per-test: how many EFD retries were determined after the first execution.
|
|
101
|
+
const efdDeterminedRetries = new Map()
|
|
102
|
+
// Tests whose first run exceeded the 5-min threshold — tagged "slow".
|
|
103
|
+
const efdSlowAbortedTests = new Set()
|
|
104
|
+
// Tests added as EFD new-test candidates (not ATF, not impacted).
|
|
105
|
+
const efdNewTestCandidates = new Set()
|
|
98
106
|
const testSuiteAbsolutePathsWithFastCheck = new Set()
|
|
99
107
|
const testSuiteJestObjects = new Map()
|
|
100
108
|
|
|
@@ -129,6 +137,8 @@ function getTestEnvironmentOptions (config) {
|
|
|
129
137
|
return {}
|
|
130
138
|
}
|
|
131
139
|
|
|
140
|
+
const MAX_IGNORED_TEST_NAMES = 10
|
|
141
|
+
|
|
132
142
|
function getTestStats (testStatuses) {
|
|
133
143
|
return testStatuses.reduce((acc, testStatus) => {
|
|
134
144
|
acc[testStatus]++
|
|
@@ -136,6 +146,32 @@ function getTestStats (testStatuses) {
|
|
|
136
146
|
}, { pass: 0, fail: 0 })
|
|
137
147
|
}
|
|
138
148
|
|
|
149
|
+
/**
|
|
150
|
+
* @param {string[]} efdNames
|
|
151
|
+
* @param {string[]} quarantineNames
|
|
152
|
+
* @param {number} totalCount
|
|
153
|
+
*/
|
|
154
|
+
function logIgnoredFailuresSummary (efdNames, quarantineNames, totalCount) {
|
|
155
|
+
const names = []
|
|
156
|
+
for (const n of efdNames) {
|
|
157
|
+
names.push({ name: n, reason: 'Early Flake Detection' })
|
|
158
|
+
}
|
|
159
|
+
for (const n of quarantineNames) {
|
|
160
|
+
names.push({ name: n, reason: 'Quarantine' })
|
|
161
|
+
}
|
|
162
|
+
const shown = names.slice(0, MAX_IGNORED_TEST_NAMES)
|
|
163
|
+
const more = names.length - shown.length
|
|
164
|
+
const moreSuffix = more > 0 ? `\n ... and ${more} more` : ''
|
|
165
|
+
const list = shown.map(({ name, reason }) => ` • ${name} (${reason})`).join('\n')
|
|
166
|
+
const line = '-'.repeat(50)
|
|
167
|
+
// eslint-disable-next-line no-console -- Intentional user-facing message when exit code is flipped
|
|
168
|
+
console.warn(
|
|
169
|
+
`\n${line}\nDatadog Test Optimization\n${line}\n` +
|
|
170
|
+
`${totalCount} test failure(s) were ignored. Exit code set to 0.\n\n` +
|
|
171
|
+
`${list}${moreSuffix}\n`
|
|
172
|
+
)
|
|
173
|
+
}
|
|
174
|
+
|
|
139
175
|
function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
140
176
|
return class DatadogEnvironment extends BaseEnvironment {
|
|
141
177
|
constructor (config, context) {
|
|
@@ -169,7 +205,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
169
205
|
this.isImpactedTestsEnabled = this.testEnvironmentOptions._ddIsImpactedTestsEnabled
|
|
170
206
|
|
|
171
207
|
if (this.isKnownTestsEnabled) {
|
|
172
|
-
|
|
208
|
+
earlyFlakeDetectionSlowTestRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionSlowTestRetries ?? {}
|
|
173
209
|
try {
|
|
174
210
|
this.knownTestsForThisSuite = this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
|
|
175
211
|
|
|
@@ -438,7 +474,13 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
438
474
|
testContexts.set(event.test, ctx)
|
|
439
475
|
|
|
440
476
|
testStartCh.runStores(ctx, () => {
|
|
441
|
-
|
|
477
|
+
let p = event.test.parent
|
|
478
|
+
const hooks = []
|
|
479
|
+
while (p != null) {
|
|
480
|
+
hooks.push(...p.hooks)
|
|
481
|
+
p = p.parent
|
|
482
|
+
}
|
|
483
|
+
for (const hook of hooks) {
|
|
442
484
|
let hookFn = hook.fn
|
|
443
485
|
if (originalHookFns.has(hook)) {
|
|
444
486
|
hookFn = originalHookFns.get(hook)
|
|
@@ -509,11 +551,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
509
551
|
retriedTestsToNumAttempts.set(testFullName, 0)
|
|
510
552
|
if (this.isEarlyFlakeDetectionEnabled) {
|
|
511
553
|
testsToBeRetried.add(testFullName)
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
retryType: 'Early flake detection',
|
|
516
|
-
})
|
|
554
|
+
efdNewTestCandidates.add(testFullName)
|
|
555
|
+
// Cloning is deferred to test_done after the first execution,
|
|
556
|
+
// when we know the duration and can choose the right retry count.
|
|
517
557
|
}
|
|
518
558
|
}
|
|
519
559
|
}
|
|
@@ -538,8 +578,8 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
538
578
|
let attemptToFixFailed = false
|
|
539
579
|
let failedAllTests = false
|
|
540
580
|
let isAttemptToFix = false
|
|
581
|
+
const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
|
|
541
582
|
if (this.isTestManagementTestsEnabled) {
|
|
542
|
-
const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
|
|
543
583
|
isAttemptToFix = this.testManagementTestsForThisSuite?.attemptToFix?.includes(testName)
|
|
544
584
|
if (isAttemptToFix) {
|
|
545
585
|
if (attemptToFixRetriedTestsStatuses.has(testName)) {
|
|
@@ -564,9 +604,53 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
564
604
|
}
|
|
565
605
|
}
|
|
566
606
|
|
|
607
|
+
// EFD dynamic cloning: on first execution of a new EFD candidate,
|
|
608
|
+
// determine the retry count from the test's duration.
|
|
609
|
+
if (
|
|
610
|
+
this.isEarlyFlakeDetectionEnabled &&
|
|
611
|
+
this.isKnownTestsEnabled &&
|
|
612
|
+
efdNewTestCandidates.has(testName) &&
|
|
613
|
+
event.test.invocations === 1 &&
|
|
614
|
+
!efdDeterminedRetries.has(testName)
|
|
615
|
+
) {
|
|
616
|
+
const durationMs = event.test.duration ?? 0
|
|
617
|
+
const retryCount = getEfdRetryCount(durationMs, earlyFlakeDetectionSlowTestRetries)
|
|
618
|
+
efdDeterminedRetries.set(testName, retryCount)
|
|
619
|
+
if (retryCount > 0) {
|
|
620
|
+
// Temporarily adjust jest-circus state so that retry tests are registered
|
|
621
|
+
// into the correct describe block and bypass the "tests have started" guard.
|
|
622
|
+
//
|
|
623
|
+
// Problem 1 (jest-circus ≤24): currentDescribeBlock points to ROOT during
|
|
624
|
+
// execution, and ROOT's tests loop already finished before children ran.
|
|
625
|
+
//
|
|
626
|
+
// Problem 2 (jest-circus ≥27): `hasStarted = true` causes `test()` to throw
|
|
627
|
+
// "Cannot add a test after tests have started running".
|
|
628
|
+
//
|
|
629
|
+
// Fix: temporarily point currentDescribeBlock to the test's parent (so retries
|
|
630
|
+
// land in the still-iterating children array) and set hasStarted = false (so the
|
|
631
|
+
// guard is bypassed). Both are restored immediately after scheduling the retries.
|
|
632
|
+
const originalDescribeBlock = state.currentDescribeBlock
|
|
633
|
+
const originalHasStarted = state.hasStarted
|
|
634
|
+
state.currentDescribeBlock = event.test.parent ?? originalDescribeBlock
|
|
635
|
+
state.hasStarted = false
|
|
636
|
+
this.retryTest({
|
|
637
|
+
jestEvent: {
|
|
638
|
+
testName: event.test.name,
|
|
639
|
+
fn: event.test.fn,
|
|
640
|
+
timeout: event.test.timeout,
|
|
641
|
+
},
|
|
642
|
+
retryCount,
|
|
643
|
+
retryType: 'Early flake detection',
|
|
644
|
+
})
|
|
645
|
+
state.currentDescribeBlock = originalDescribeBlock
|
|
646
|
+
state.hasStarted = originalHasStarted
|
|
647
|
+
} else {
|
|
648
|
+
efdSlowAbortedTests.add(testName)
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
567
652
|
let isEfdRetry = false
|
|
568
653
|
// We'll store the test statuses of the retries
|
|
569
|
-
const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
|
|
570
654
|
if (this.isKnownTestsEnabled) {
|
|
571
655
|
const isNewTest = retriedTestsToNumAttempts.has(testName)
|
|
572
656
|
if (isNewTest) {
|
|
@@ -576,6 +660,14 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
576
660
|
} else {
|
|
577
661
|
newTestsTestStatuses.set(testName, [status])
|
|
578
662
|
}
|
|
663
|
+
const testStatuses = newTestsTestStatuses.get(testName)
|
|
664
|
+
// Check if this is the last EFD retry.
|
|
665
|
+
// If it is, we'll set the failedAllTests flag to true if all the tests failed
|
|
666
|
+
const efdRetryCount = efdDeterminedRetries.get(testName) ?? 0
|
|
667
|
+
if (efdRetryCount > 0 && testStatuses.length === efdRetryCount + 1 &&
|
|
668
|
+
testStatuses.every(status => status === 'fail')) {
|
|
669
|
+
failedAllTests = true
|
|
670
|
+
}
|
|
579
671
|
}
|
|
580
672
|
}
|
|
581
673
|
|
|
@@ -630,6 +722,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
630
722
|
attemptToFixFailed,
|
|
631
723
|
isAtrRetry,
|
|
632
724
|
finalStatus,
|
|
725
|
+
earlyFlakeAbortReason: efdSlowAbortedTests.has(testName) ? 'slow' : undefined,
|
|
633
726
|
})
|
|
634
727
|
|
|
635
728
|
if (promises.isProbeReady) {
|
|
@@ -641,6 +734,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
641
734
|
test.errors = errors
|
|
642
735
|
}
|
|
643
736
|
atrSuppressedErrors.clear()
|
|
737
|
+
efdDeterminedRetries.clear()
|
|
738
|
+
efdSlowAbortedTests.clear()
|
|
739
|
+
efdNewTestCandidates.clear()
|
|
644
740
|
}
|
|
645
741
|
if (event.name === 'test_skip' || event.name === 'test_todo') {
|
|
646
742
|
const testName = getJestTestName(event.test, this.getShouldStripSeedFromTestName())
|
|
@@ -661,7 +757,9 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
661
757
|
getEfdResult ({ testName, isNewTest, isModifiedTest, isEfdRetry, numberOfExecutedRetries }) {
|
|
662
758
|
const isEfdEnabled = this.isEarlyFlakeDetectionEnabled
|
|
663
759
|
const isEfdActive = isEfdEnabled && (isNewTest || isModifiedTest)
|
|
664
|
-
const
|
|
760
|
+
const retryCount = efdDeterminedRetries.get(testName) ?? 0
|
|
761
|
+
const isSlowAbort = efdSlowAbortedTests.has(testName)
|
|
762
|
+
const isLastEfdRetry = (isEfdRetry && numberOfExecutedRetries >= (retryCount + 1)) || isSlowAbort
|
|
665
763
|
const isFinalEfdTestExecution = isEfdActive && isLastEfdRetry
|
|
666
764
|
|
|
667
765
|
let finalStatus
|
|
@@ -898,6 +996,7 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
898
996
|
isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
|
|
899
997
|
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
900
998
|
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
999
|
+
earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
|
|
901
1000
|
earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
902
1001
|
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
903
1002
|
isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
@@ -994,11 +1093,18 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
994
1093
|
coverageMap,
|
|
995
1094
|
numFailedTestSuites,
|
|
996
1095
|
numFailedTests,
|
|
1096
|
+
numRuntimeErrorTestSuites = 0,
|
|
997
1097
|
numTotalTests,
|
|
998
1098
|
numTotalTestSuites,
|
|
1099
|
+
runExecError,
|
|
1100
|
+
wasInterrupted,
|
|
999
1101
|
},
|
|
1000
1102
|
} = result
|
|
1001
1103
|
|
|
1104
|
+
const hasSuiteLevelFailures = numRuntimeErrorTestSuites > 0
|
|
1105
|
+
const hasRunLevelFailure = runExecError != null || wasInterrupted === true
|
|
1106
|
+
const mustNotFlipSuccess = hasSuiteLevelFailures || hasRunLevelFailure
|
|
1107
|
+
|
|
1002
1108
|
let testCodeCoverageLinesTotal
|
|
1003
1109
|
|
|
1004
1110
|
if (isUserCodeCoverageEnabled) {
|
|
@@ -1018,16 +1124,44 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
1018
1124
|
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
1019
1125
|
*/
|
|
1020
1126
|
let numEfdFailedTestsToIgnore = 0
|
|
1127
|
+
const efdIgnoredNames = []
|
|
1128
|
+
const quarantineIgnoredNames = []
|
|
1129
|
+
|
|
1130
|
+
// Build fullName -> suite map from results (for EFD display)
|
|
1131
|
+
const fullNameToSuite = new Map()
|
|
1132
|
+
for (const { testResults, testFilePath } of result.results.testResults) {
|
|
1133
|
+
const suite = getTestSuitePath(testFilePath, result.globalConfig.rootDir)
|
|
1134
|
+
for (const { fullName } of testResults) {
|
|
1135
|
+
const name = testSuiteAbsolutePathsWithFastCheck.has(testFilePath)
|
|
1136
|
+
? fullName.replace(SEED_SUFFIX_RE, '')
|
|
1137
|
+
: fullName
|
|
1138
|
+
fullNameToSuite.set(name, suite)
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/** @type {{ efdNames: string[], quarantineNames: string[], totalCount: number } | undefined} */
|
|
1143
|
+
let ignoredFailuresSummary
|
|
1021
1144
|
if (isEarlyFlakeDetectionEnabled) {
|
|
1022
|
-
for (const testStatuses of newTestsTestStatuses
|
|
1145
|
+
for (const [testName, testStatuses] of newTestsTestStatuses) {
|
|
1023
1146
|
const { pass, fail } = getTestStats(testStatuses)
|
|
1024
1147
|
if (pass > 0) { // as long as one passes, we'll consider the test passed
|
|
1025
1148
|
numEfdFailedTestsToIgnore += fail
|
|
1149
|
+
const suite = fullNameToSuite.get(testName)
|
|
1150
|
+
efdIgnoredNames.push(suite ? `${suite} › ${testName}` : testName)
|
|
1026
1151
|
}
|
|
1027
1152
|
}
|
|
1028
1153
|
// If every test that failed was an EFD retry, we'll consider the suite passed
|
|
1029
|
-
if (
|
|
1154
|
+
if (
|
|
1155
|
+
!mustNotFlipSuccess &&
|
|
1156
|
+
numEfdFailedTestsToIgnore !== 0 &&
|
|
1157
|
+
result.results.numFailedTests === numEfdFailedTestsToIgnore
|
|
1158
|
+
) {
|
|
1030
1159
|
result.results.success = true
|
|
1160
|
+
ignoredFailuresSummary = {
|
|
1161
|
+
efdNames: efdIgnoredNames,
|
|
1162
|
+
quarantineNames: [],
|
|
1163
|
+
totalCount: numEfdFailedTestsToIgnore,
|
|
1164
|
+
}
|
|
1031
1165
|
}
|
|
1032
1166
|
}
|
|
1033
1167
|
|
|
@@ -1062,8 +1196,10 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
1062
1196
|
// This uses `attempt_to_fix` because this is always the main process and it's not formatted in camelCase
|
|
1063
1197
|
if (testManagementTest?.attempt_to_fix && (testManagementTest?.quarantined || testManagementTest?.disabled)) {
|
|
1064
1198
|
numFailedQuarantinedOrDisabledAttemptedToFixTests++
|
|
1199
|
+
quarantineIgnoredNames.push(`${testSuite} › ${testName}`)
|
|
1065
1200
|
} else if (testManagementTest?.quarantined) {
|
|
1066
1201
|
numFailedQuarantinedTests++
|
|
1202
|
+
quarantineIgnoredNames.push(`${testSuite} › ${testName}`)
|
|
1067
1203
|
}
|
|
1068
1204
|
}
|
|
1069
1205
|
|
|
@@ -1071,22 +1207,42 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
1071
1207
|
// Note that if a test is attempted to fix,
|
|
1072
1208
|
// it's considered quarantined both if it's disabled and if it's quarantined
|
|
1073
1209
|
// (it'll run but its status is ignored)
|
|
1210
|
+
// Skip if EFD block already flipped (to avoid logging twice)
|
|
1074
1211
|
if (
|
|
1212
|
+
!result.results.success &&
|
|
1213
|
+
!mustNotFlipSuccess &&
|
|
1075
1214
|
(numFailedQuarantinedOrDisabledAttemptedToFixTests !== 0 || numFailedQuarantinedTests !== 0) &&
|
|
1076
1215
|
result.results.numFailedTests ===
|
|
1077
1216
|
numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
|
|
1078
1217
|
) {
|
|
1079
1218
|
result.results.success = true
|
|
1219
|
+
ignoredFailuresSummary = {
|
|
1220
|
+
efdNames: [],
|
|
1221
|
+
quarantineNames: quarantineIgnoredNames,
|
|
1222
|
+
totalCount: numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests,
|
|
1223
|
+
}
|
|
1080
1224
|
}
|
|
1081
1225
|
}
|
|
1082
1226
|
|
|
1083
1227
|
// Combined check: if all failed tests are accounted for by EFD (flaky retries) and/or quarantine,
|
|
1084
1228
|
// we should consider the suite passed even when neither check alone covers all failures.
|
|
1085
|
-
if (
|
|
1229
|
+
if (
|
|
1230
|
+
!result.results.success &&
|
|
1231
|
+
!mustNotFlipSuccess &&
|
|
1232
|
+
(isEarlyFlakeDetectionEnabled || isTestManagementTestsEnabled)
|
|
1233
|
+
) {
|
|
1086
1234
|
const totalIgnoredFailures =
|
|
1087
1235
|
numEfdFailedTestsToIgnore + numFailedQuarantinedTests + numFailedQuarantinedOrDisabledAttemptedToFixTests
|
|
1088
|
-
if (
|
|
1236
|
+
if (
|
|
1237
|
+
totalIgnoredFailures !== 0 &&
|
|
1238
|
+
result.results.numFailedTests === totalIgnoredFailures
|
|
1239
|
+
) {
|
|
1089
1240
|
result.results.success = true
|
|
1241
|
+
ignoredFailuresSummary = {
|
|
1242
|
+
efdNames: efdIgnoredNames,
|
|
1243
|
+
quarantineNames: quarantineIgnoredNames,
|
|
1244
|
+
totalCount: totalIgnoredFailures,
|
|
1245
|
+
}
|
|
1090
1246
|
}
|
|
1091
1247
|
}
|
|
1092
1248
|
|
|
@@ -1144,6 +1300,14 @@ function getCliWrapper (isNewJestVersion) {
|
|
|
1144
1300
|
})
|
|
1145
1301
|
}
|
|
1146
1302
|
|
|
1303
|
+
if (ignoredFailuresSummary) {
|
|
1304
|
+
logIgnoredFailuresSummary(
|
|
1305
|
+
ignoredFailuresSummary.efdNames,
|
|
1306
|
+
ignoredFailuresSummary.quarantineNames,
|
|
1307
|
+
ignoredFailuresSummary.totalCount
|
|
1308
|
+
)
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1147
1311
|
numSkippedSuites = 0
|
|
1148
1312
|
|
|
1149
1313
|
return result
|
|
@@ -1408,7 +1572,7 @@ addHook({
|
|
|
1408
1572
|
_ddItrCorrelationId,
|
|
1409
1573
|
_ddKnownTests,
|
|
1410
1574
|
_ddIsEarlyFlakeDetectionEnabled,
|
|
1411
|
-
|
|
1575
|
+
_ddEarlyFlakeDetectionSlowTestRetries,
|
|
1412
1576
|
_ddRepositoryRoot,
|
|
1413
1577
|
_ddIsFlakyTestRetriesEnabled,
|
|
1414
1578
|
_ddFlakyTestRetriesCount,
|
|
@@ -24,22 +24,6 @@ const batchConsumerErrorCh = channel('apm:kafkajs:consume-batch:error')
|
|
|
24
24
|
|
|
25
25
|
const disabledHeaderWeakSet = new WeakSet()
|
|
26
26
|
|
|
27
|
-
function commitsFromEvent (event) {
|
|
28
|
-
const { payload: { groupId, topics } } = event
|
|
29
|
-
const commitList = []
|
|
30
|
-
for (const { topic, partitions } of topics) {
|
|
31
|
-
for (const { partition, offset } of partitions) {
|
|
32
|
-
commitList.push({
|
|
33
|
-
groupId,
|
|
34
|
-
partition,
|
|
35
|
-
offset,
|
|
36
|
-
topic,
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
consumerCommitCh.publish(commitList)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
27
|
addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKafka) => {
|
|
44
28
|
class Kafka extends BaseKafka {
|
|
45
29
|
constructor (options) {
|
|
@@ -132,6 +116,7 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
132
116
|
}
|
|
133
117
|
|
|
134
118
|
const kafkaClusterIdPromise = getKafkaClusterId(this)
|
|
119
|
+
let resolvedClusterId = null
|
|
135
120
|
|
|
136
121
|
const eachMessageExtractor = (args, clusterId) => {
|
|
137
122
|
const { topic, partition, message } = args[0]
|
|
@@ -146,13 +131,31 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
146
131
|
|
|
147
132
|
const consumer = createConsumer.apply(this, arguments)
|
|
148
133
|
|
|
149
|
-
consumer.on(consumer.events.COMMIT_OFFSETS,
|
|
134
|
+
consumer.on(consumer.events.COMMIT_OFFSETS, (event) => {
|
|
135
|
+
const { payload: { groupId: commitGroupId, topics } } = event
|
|
136
|
+
const commitList = []
|
|
137
|
+
for (const { topic, partitions } of topics) {
|
|
138
|
+
for (const { partition, offset } of partitions) {
|
|
139
|
+
commitList.push({
|
|
140
|
+
groupId: commitGroupId,
|
|
141
|
+
partition,
|
|
142
|
+
offset,
|
|
143
|
+
topic,
|
|
144
|
+
clusterId: resolvedClusterId,
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
consumerCommitCh.publish(commitList)
|
|
149
|
+
})
|
|
150
150
|
|
|
151
151
|
const run = consumer.run
|
|
152
152
|
const groupId = arguments[0].groupId
|
|
153
153
|
|
|
154
154
|
consumer.run = function ({ eachMessage, eachBatch, ...runArgs }) {
|
|
155
155
|
const wrapConsume = (clusterId) => {
|
|
156
|
+
// In kafkajs COMMIT_OFFSETS always happens in the context of one synchronous run
|
|
157
|
+
// So this will always reference a correct cluster id
|
|
158
|
+
resolvedClusterId = clusterId
|
|
156
159
|
return run({
|
|
157
160
|
eachMessage: wrappedCallback(
|
|
158
161
|
eachMessage,
|
|
@@ -271,6 +271,7 @@ function getOnTestEndHandler (config) {
|
|
|
271
271
|
const testStatuses = testsStatuses.get(testName)
|
|
272
272
|
|
|
273
273
|
const isLastAttempt = testStatuses.length === config.testManagementAttemptToFixRetries + 1
|
|
274
|
+
const isLastEfdRetry = testStatuses.length === config.earlyFlakeDetectionNumRetries + 1
|
|
274
275
|
|
|
275
276
|
if (test._ddIsAttemptToFix && isLastAttempt) {
|
|
276
277
|
if (testStatuses.includes('fail')) {
|
|
@@ -283,6 +284,11 @@ function getOnTestEndHandler (config) {
|
|
|
283
284
|
}
|
|
284
285
|
}
|
|
285
286
|
|
|
287
|
+
if (test._ddIsEfdRetry && isLastEfdRetry &&
|
|
288
|
+
testStatuses.every(status => status === 'fail')) {
|
|
289
|
+
hasFailedAllRetries = true
|
|
290
|
+
}
|
|
291
|
+
|
|
286
292
|
const isAttemptToFixRetry = test._ddIsAttemptToFix && testStatuses.length > 1
|
|
287
293
|
const isAtrRetry = config.isFlakyTestRetriesEnabled &&
|
|
288
294
|
!test._ddIsAttemptToFix &&
|