dd-trace 6.8.0 → 6.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ci/diagnose.js +27 -25
- package/ci/init.js +6 -6
- package/ci/runbook.md +114 -20
- package/ci/test-optimization-validation/approval-artifacts.js +36 -3
- package/ci/test-optimization-validation/approval.js +78 -22
- package/ci/test-optimization-validation/blocker-category.js +24 -0
- package/ci/test-optimization-validation/ci-discovery.js +23 -17
- package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
- package/ci/test-optimization-validation/ci-remediation.js +1 -1
- package/ci/test-optimization-validation/cli.js +280 -52
- package/ci/test-optimization-validation/command-blocker.js +159 -20
- package/ci/test-optimization-validation/command-output-policy.js +9 -3
- package/ci/test-optimization-validation/command-runner.js +9 -7
- package/ci/test-optimization-validation/environment.js +4 -2
- package/ci/test-optimization-validation/executable.js +15 -13
- package/ci/test-optimization-validation/execution-lock.js +70 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
- package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +38 -28
- package/ci/test-optimization-validation/generated-test-contract.js +8 -4
- package/ci/test-optimization-validation/generated-verifier.js +24 -17
- package/ci/test-optimization-validation/literal-glob.js +52 -0
- package/ci/test-optimization-validation/manifest-loader.js +3 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +300 -50
- package/ci/test-optimization-validation/manifest-schema.js +80 -17
- package/ci/test-optimization-validation/offline-fixtures.js +13 -4
- package/ci/test-optimization-validation/package-check.js +94 -0
- package/ci/test-optimization-validation/plan-writer.js +183 -10
- package/ci/test-optimization-validation/preflight-runner.js +110 -31
- package/ci/test-optimization-validation/project-build-artifact.js +31 -0
- package/ci/test-optimization-validation/redaction.js +18 -27
- package/ci/test-optimization-validation/report-writer.js +182 -48
- package/ci/test-optimization-validation/result-semantics.js +20 -3
- package/ci/test-optimization-validation/runner-command.js +40 -20
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +59 -5
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
- package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
- package/ci/test-optimization-validation/static-diagnosis.js +10 -3
- package/ci/test-optimization-validation/test-output.js +2 -1
- package/ci/test-optimization-validation/validation-blocker.js +21 -0
- package/ci/vitest-no-worker-init-setup.mjs +30 -34
- package/index.d.ts +98 -1
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +5 -3
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/src/utils.js +16 -1
- package/packages/datadog-instrumentations/src/ai.js +61 -34
- package/packages/datadog-instrumentations/src/bluebird.js +6 -6
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +81 -5
- package/packages/datadog-instrumentations/src/cucumber.js +124 -47
- package/packages/datadog-instrumentations/src/dns.js +21 -2
- package/packages/datadog-instrumentations/src/electron.js +1 -0
- package/packages/datadog-instrumentations/src/fastify.js +3 -1
- package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +33 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +118 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +37 -6
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +979 -233
- package/packages/datadog-instrumentations/src/mocha/main.js +107 -9
- package/packages/datadog-instrumentations/src/mocha/utils.js +64 -42
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +25 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +12 -18
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/pg.js +180 -6
- package/packages/datadog-instrumentations/src/playwright.js +173 -79
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -10
- package/packages/datadog-instrumentations/src/vitest-main.js +360 -56
- package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
- package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
- package/packages/datadog-instrumentations/src/webdriverio.js +194 -18
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -3
- package/packages/datadog-plugin-cucumber/src/index.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +1 -18
- package/packages/datadog-plugin-jest/src/util.js +2 -0
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-mocha/src/index.js +318 -1
- package/packages/datadog-plugin-next/src/index.js +57 -9
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-pg/src/index.js +65 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +95 -7
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/dd-trace/src/aiguard/sdk.js +3 -0
- package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
- package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
- package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
- package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
- package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +9 -0
- package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
- package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +27 -13
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +21 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/generated-config-types.d.ts +2 -0
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +16 -5
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +8 -0
- package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
- package/packages/dd-trace/src/guardrails/log.js +1 -10
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +33 -25
- package/packages/dd-trace/src/llmobs/experiments/util.js +4 -2
- package/packages/dd-trace/src/llmobs/noop.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +149 -68
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
- package/packages/dd-trace/src/log/channels.js +1 -9
- package/packages/dd-trace/src/log/levels.js +12 -0
- package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +21 -5
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +6 -0
- package/packages/dd-trace/src/plugins/util/git.js +6 -4
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +2 -2
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/test.js +319 -75
- package/packages/dd-trace/src/plugins/util/url.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +23 -1
- package/packages/dd-trace/src/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +5 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
- package/packages/dd-trace/src/sampling_rule.js +4 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const fs = require('fs')
|
|
5
5
|
const { URL } = require('url')
|
|
6
|
+
const { stripVTControlCharacters } = require('node:util')
|
|
6
7
|
const { getLageTestSessionName } = require('../../ci-visibility/lage')
|
|
7
8
|
const log = require('../../log')
|
|
8
|
-
const { getEnvironmentVariable } = require('../../config/helper')
|
|
9
|
+
const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
|
|
9
10
|
const { getSegment } = require('../../util')
|
|
10
11
|
const satisfies = require('../../../../../vendor/dist/semifies')
|
|
11
12
|
|
|
@@ -123,13 +124,10 @@ const TEST_RETRY_REASON = 'test.retry_reason'
|
|
|
123
124
|
const TEST_HAS_FAILED_ALL_RETRIES = 'test.has_failed_all_retries'
|
|
124
125
|
const TEST_IS_MODIFIED = 'test.is_modified'
|
|
125
126
|
const TEST_HAS_DYNAMIC_NAME = '_dd.has_dynamic_name'
|
|
126
|
-
const EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS = [
|
|
127
|
-
{ limitMs: 5 * 1000, key: '5s' },
|
|
128
|
-
{ limitMs: 10 * 1000, key: '10s' },
|
|
129
|
-
{ limitMs: 30 * 1000, key: '30s' },
|
|
130
|
-
{ limitMs: 5 * 60 * 1000, key: '5m' },
|
|
131
|
-
]
|
|
132
127
|
const CI_APP_ORIGIN = 'ciapp-test'
|
|
128
|
+
// eslint-disable-next-line no-control-regex
|
|
129
|
+
const TEST_OPTIMIZATION_NAME_CONTROL_RE = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g
|
|
130
|
+
const TEST_OPTIMIZATION_NAME_WHITESPACE_RE = /\s+/g
|
|
133
131
|
|
|
134
132
|
// Matches patterns that are almost certainly runtime-generated values in test names:
|
|
135
133
|
// - Unix timestamps in ms (13 digits, years ~2020-2090) or s (10 digits)
|
|
@@ -162,6 +160,7 @@ const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
|
|
|
162
160
|
const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
|
|
163
161
|
const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
|
|
164
162
|
const ITR_CORRELATION_ID = 'itr_correlation_id'
|
|
163
|
+
const TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE = 'Test Impact Analysis skipped all tests.'
|
|
165
164
|
|
|
166
165
|
const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
|
|
167
166
|
|
|
@@ -180,17 +179,22 @@ const JEST_WORKER_QUARANTINE_PAYLOAD_CODE = 64
|
|
|
180
179
|
|
|
181
180
|
// cucumber worker variables
|
|
182
181
|
const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
|
|
182
|
+
const CUCUMBER_WORKER_TELEMETRY_PAYLOAD_CODE = 71
|
|
183
183
|
|
|
184
184
|
// mocha worker variables
|
|
185
185
|
const MOCHA_WORKER_TRACE_PAYLOAD_CODE = 80
|
|
186
186
|
const MOCHA_WORKER_LOGS_PAYLOAD_CODE = 81
|
|
187
|
+
const MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE = 82
|
|
187
188
|
|
|
188
189
|
// playwright worker variables
|
|
189
190
|
const PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE = 90
|
|
191
|
+
const PLAYWRIGHT_WORKER_TELEMETRY_PAYLOAD_CODE = 91
|
|
190
192
|
|
|
191
193
|
// vitest worker variables
|
|
192
194
|
const VITEST_WORKER_TRACE_PAYLOAD_CODE = 100
|
|
195
|
+
const VITEST_WORKER_COVERAGE_PAYLOAD_CODE = 101
|
|
193
196
|
const VITEST_WORKER_LOGS_PAYLOAD_CODE = 102
|
|
197
|
+
const VITEST_WORKER_TELEMETRY_PAYLOAD_CODE = 103
|
|
194
198
|
|
|
195
199
|
const TEST_IS_TEST_FRAMEWORK_WORKER = 'test.is_test_framework_worker'
|
|
196
200
|
|
|
@@ -211,7 +215,7 @@ const DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS = '_dd.ci.library_configurat
|
|
|
211
215
|
const DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS =
|
|
212
216
|
'_dd.ci.library_configuration_error.test_management_tests'
|
|
213
217
|
|
|
214
|
-
const UNSUPPORTED_TIA_FRAMEWORKS = new Set(['playwright', '
|
|
218
|
+
const UNSUPPORTED_TIA_FRAMEWORKS = new Set(['playwright', 'webdriverio'])
|
|
215
219
|
const MINIMUM_FRAMEWORK_VERSION_FOR_EFD = {
|
|
216
220
|
playwright: '>=1.38.0',
|
|
217
221
|
}
|
|
@@ -300,7 +304,10 @@ const TEST_MANAGEMENT_IS_QUARANTINED = 'test.test_management.is_quarantined'
|
|
|
300
304
|
const TEST_MANAGEMENT_ENABLED = 'test.test_management.enabled'
|
|
301
305
|
const TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED = 'test.test_management.attempt_to_fix_passed'
|
|
302
306
|
|
|
307
|
+
const MAX_TEST_MANAGEMENT_REPORT_ITEMS = 5
|
|
308
|
+
const MAX_TEST_OPTIMIZATION_NAME_LENGTH = 160
|
|
303
309
|
const MAX_TEST_OPTIMIZATION_SUMMARY_ITEMS = 10
|
|
310
|
+
const testManagementExecutions = new Map()
|
|
304
311
|
|
|
305
312
|
// Impacted tests
|
|
306
313
|
const POSSIBLE_BASE_BRANCHES = ['main', 'master', 'preprod', 'prod', 'dev', 'development', 'trunk']
|
|
@@ -472,11 +479,16 @@ module.exports = {
|
|
|
472
479
|
JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
473
480
|
JEST_WORKER_QUARANTINE_PAYLOAD_CODE,
|
|
474
481
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
482
|
+
CUCUMBER_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
475
483
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
476
484
|
MOCHA_WORKER_LOGS_PAYLOAD_CODE,
|
|
485
|
+
MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
477
486
|
PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE,
|
|
487
|
+
PLAYWRIGHT_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
478
488
|
VITEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
489
|
+
VITEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
479
490
|
VITEST_WORKER_LOGS_PAYLOAD_CODE,
|
|
491
|
+
VITEST_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
480
492
|
TEST_IS_TEST_FRAMEWORK_WORKER,
|
|
481
493
|
TEST_SOURCE_START,
|
|
482
494
|
TEST_SKIPPED_BY_ITR,
|
|
@@ -515,6 +527,7 @@ module.exports = {
|
|
|
515
527
|
TEST_ITR_UNSKIPPABLE,
|
|
516
528
|
TEST_ITR_FORCED_RUN,
|
|
517
529
|
ITR_CORRELATION_ID,
|
|
530
|
+
TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE,
|
|
518
531
|
addIntelligentTestRunnerSpanTags,
|
|
519
532
|
getCoveredFilenamesFromCoverage,
|
|
520
533
|
getCoveredFilesFromCoverage,
|
|
@@ -531,9 +544,6 @@ module.exports = {
|
|
|
531
544
|
removeInvalidMetadata,
|
|
532
545
|
parseAnnotations,
|
|
533
546
|
getIsFaultyEarlyFlakeDetection,
|
|
534
|
-
EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS,
|
|
535
|
-
getEfdRetryCount,
|
|
536
|
-
getMaxEfdRetryCount,
|
|
537
547
|
TEST_BROWSER_DRIVER,
|
|
538
548
|
TEST_BROWSER_DRIVER_VERSION,
|
|
539
549
|
TEST_BROWSER_NAME,
|
|
@@ -584,8 +594,10 @@ module.exports = {
|
|
|
584
594
|
collectDynamicNamesFromTraces,
|
|
585
595
|
collectTestOptimizationSummariesFromTraces,
|
|
586
596
|
logDynamicNamesWarning,
|
|
597
|
+
recordTestManagementExecution,
|
|
587
598
|
recordAttemptToFixExecution,
|
|
588
599
|
collectAttemptToFixExecutionsFromTraces,
|
|
600
|
+
formatTestManagementSummary,
|
|
589
601
|
formatAttemptToFixSummary,
|
|
590
602
|
logAttemptToFixTestExecution,
|
|
591
603
|
formatDynamicNamesSummary,
|
|
@@ -732,6 +744,7 @@ function checkShaDiscrepancies (ciMetadata, userProvidedGitMetadata) {
|
|
|
732
744
|
*
|
|
733
745
|
* @param {string=} testFramework
|
|
734
746
|
* @param {TestEnvironmentConfig=} config
|
|
747
|
+
* @param {boolean=} shouldSkipGitMetadataExtraction
|
|
735
748
|
* @returns {TestEnvironmentMetadata}
|
|
736
749
|
*/
|
|
737
750
|
function getTestEnvironmentMetadata (testFramework, config, shouldSkipGitMetadataExtraction = false) {
|
|
@@ -912,6 +925,10 @@ function getTestCommonTags (name, suite, version, testFramework) {
|
|
|
912
925
|
/**
|
|
913
926
|
* We want to make sure that test suites are reported the same way for
|
|
914
927
|
* every OS, so we replace `path.sep` by `/`
|
|
928
|
+
*
|
|
929
|
+
* @param {string | undefined} testSuiteAbsolutePath
|
|
930
|
+
* @param {string} sourceRoot
|
|
931
|
+
* @returns {string}
|
|
915
932
|
*/
|
|
916
933
|
function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
|
|
917
934
|
if (!testSuiteAbsolutePath) {
|
|
@@ -1525,46 +1542,6 @@ function parseAnnotations (annotations) {
|
|
|
1525
1542
|
}, {})
|
|
1526
1543
|
}
|
|
1527
1544
|
|
|
1528
|
-
/**
|
|
1529
|
-
* Given a test's first-execution duration (ms) and the slow_test_retries map
|
|
1530
|
-
* from the backend, return how many EFD retries to run.
|
|
1531
|
-
*
|
|
1532
|
-
* Returns 0 when the test is too slow to retry (≥ 5 min).
|
|
1533
|
-
*
|
|
1534
|
-
* @param {number} durationMs
|
|
1535
|
-
* @param {Record<string, number>} slowTestRetries e.g. { '5s': 10, '10s': 5, '30s': 3, '5m': 2 }
|
|
1536
|
-
* @returns {number}
|
|
1537
|
-
*/
|
|
1538
|
-
function getEfdRetryCount (durationMs, slowTestRetries) {
|
|
1539
|
-
for (const { limitMs, key } of EARLY_FLAKE_DETECTION_RETRY_THRESHOLDS) {
|
|
1540
|
-
if (durationMs < limitMs) {
|
|
1541
|
-
return slowTestRetries[key] ?? 0
|
|
1542
|
-
}
|
|
1543
|
-
}
|
|
1544
|
-
return 0 // ≥ 5 min — abort
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
/**
|
|
1548
|
-
* Returns the maximum retry count configured by the backend for EFD.
|
|
1549
|
-
*
|
|
1550
|
-
* @param {Record<string, number> | undefined} slowTestRetries
|
|
1551
|
-
* @returns {number | undefined}
|
|
1552
|
-
*/
|
|
1553
|
-
function getMaxEfdRetryCount (slowTestRetries) {
|
|
1554
|
-
if (slowTestRetries === undefined) return
|
|
1555
|
-
|
|
1556
|
-
const retryCounts = Object.values(slowTestRetries)
|
|
1557
|
-
if (retryCounts.length === 0) return
|
|
1558
|
-
|
|
1559
|
-
let maxRetries = 0
|
|
1560
|
-
for (const retryCount of retryCounts) {
|
|
1561
|
-
if (retryCount > maxRetries) {
|
|
1562
|
-
maxRetries = retryCount
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
return maxRetries
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
1545
|
function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faultyThresholdPercentage) {
|
|
1569
1546
|
let newSuites = 0
|
|
1570
1547
|
for (const suite of projectSuites) {
|
|
@@ -1706,7 +1683,8 @@ function isFailedTestReplaySupported (testFramework, frameworkVersion) {
|
|
|
1706
1683
|
|
|
1707
1684
|
function getLibraryCapabilitiesTags (testFramework, frameworkVersion, options = {}) {
|
|
1708
1685
|
return {
|
|
1709
|
-
[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS]:
|
|
1686
|
+
[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS]: !options.omitTestImpactAnalysis &&
|
|
1687
|
+
isTiaSupported(testFramework)
|
|
1710
1688
|
? '1'
|
|
1711
1689
|
: undefined,
|
|
1712
1690
|
[DD_CAPABILITIES_EARLY_FLAKE_DETECTION]: isEarlyFlakeDetectionSupported(testFramework, frameworkVersion)
|
|
@@ -1866,6 +1844,17 @@ function getModifiedFilesFromDiff (diff) {
|
|
|
1866
1844
|
* @typedef {Map<string, AttemptToFixExecutionResult>} AttemptToFixExecutions
|
|
1867
1845
|
*/
|
|
1868
1846
|
|
|
1847
|
+
/**
|
|
1848
|
+
* Returns a collision-free identity for a test's suite and name.
|
|
1849
|
+
*
|
|
1850
|
+
* @param {string | undefined} testSuite
|
|
1851
|
+
* @param {string} testName
|
|
1852
|
+
* @returns {string}
|
|
1853
|
+
*/
|
|
1854
|
+
function getTestOptimizationIdentity (testSuite, testName) {
|
|
1855
|
+
return JSON.stringify([testSuite, testName])
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1869
1858
|
/**
|
|
1870
1859
|
* Formats a test name for user-facing Test Optimization summaries.
|
|
1871
1860
|
*
|
|
@@ -1877,6 +1866,79 @@ function formatTestOptimizationName (testSuite, testName) {
|
|
|
1877
1866
|
return testSuite ? `${testSuite} › ${testName}` : testName
|
|
1878
1867
|
}
|
|
1879
1868
|
|
|
1869
|
+
/**
|
|
1870
|
+
* Replaces characters that could make one test occupy multiple CI log lines.
|
|
1871
|
+
*
|
|
1872
|
+
* @param {string} value
|
|
1873
|
+
* @returns {string}
|
|
1874
|
+
*/
|
|
1875
|
+
function sanitizeTestOptimizationName (value) {
|
|
1876
|
+
return stripVTControlCharacters(value)
|
|
1877
|
+
.replaceAll(TEST_OPTIMIZATION_NAME_CONTROL_RE, '')
|
|
1878
|
+
.replaceAll(TEST_OPTIMIZATION_NAME_WHITESPACE_RE, ' ')
|
|
1879
|
+
.trim()
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
/**
|
|
1883
|
+
* Truncates the beginning of a value while preserving its distinguishing suffix.
|
|
1884
|
+
*
|
|
1885
|
+
* @param {string} value
|
|
1886
|
+
* @param {number} maxLength
|
|
1887
|
+
* @returns {string}
|
|
1888
|
+
*/
|
|
1889
|
+
function truncateTestOptimizationNameStart (value, maxLength) {
|
|
1890
|
+
if (value.length <= maxLength) return value
|
|
1891
|
+
|
|
1892
|
+
let start = value.length - maxLength + 1
|
|
1893
|
+
const code = value.charCodeAt(start)
|
|
1894
|
+
if (code >= 0xDC_00 && code <= 0xDF_FF) start++
|
|
1895
|
+
return `…${value.slice(start)}`
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* Truncates the middle of a value while preserving both its context and suffix.
|
|
1900
|
+
*
|
|
1901
|
+
* @param {string} value
|
|
1902
|
+
* @param {number} maxLength
|
|
1903
|
+
* @returns {string}
|
|
1904
|
+
*/
|
|
1905
|
+
function truncateTestOptimizationNameMiddle (value, maxLength) {
|
|
1906
|
+
if (value.length <= maxLength) return value
|
|
1907
|
+
|
|
1908
|
+
let prefixLength = Math.ceil((maxLength - 1) / 2)
|
|
1909
|
+
let suffixLength = maxLength - prefixLength - 1
|
|
1910
|
+
const prefixCode = value.charCodeAt(prefixLength - 1)
|
|
1911
|
+
if (prefixCode >= 0xD8_00 && prefixCode <= 0xDB_FF) prefixLength--
|
|
1912
|
+
const suffixCode = value.charCodeAt(value.length - suffixLength)
|
|
1913
|
+
if (suffixCode >= 0xDC_00 && suffixCode <= 0xDF_FF) suffixLength--
|
|
1914
|
+
return `${value.slice(0, prefixLength)}…${value.slice(-suffixLength)}`
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
/**
|
|
1918
|
+
* Formats a bounded, single-line test name for CI output.
|
|
1919
|
+
*
|
|
1920
|
+
* @param {string | undefined} testSuite
|
|
1921
|
+
* @param {string} testName
|
|
1922
|
+
* @returns {string}
|
|
1923
|
+
*/
|
|
1924
|
+
function formatTestOptimizationDisplayName (testSuite, testName) {
|
|
1925
|
+
const sanitizedSuite = testSuite ? sanitizeTestOptimizationName(testSuite) : ''
|
|
1926
|
+
const sanitizedName = sanitizeTestOptimizationName(testName)
|
|
1927
|
+
if (!sanitizedSuite) {
|
|
1928
|
+
return truncateTestOptimizationNameMiddle(sanitizedName, MAX_TEST_OPTIMIZATION_NAME_LENGTH)
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
const separator = ' › '
|
|
1932
|
+
if (sanitizedSuite.length + separator.length + sanitizedName.length <= MAX_TEST_OPTIMIZATION_NAME_LENGTH) {
|
|
1933
|
+
return `${sanitizedSuite}${separator}${sanitizedName}`
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
const suiteLength = Math.min(60, sanitizedSuite.length)
|
|
1937
|
+
const testNameLength = MAX_TEST_OPTIMIZATION_NAME_LENGTH - separator.length - suiteLength
|
|
1938
|
+
return truncateTestOptimizationNameStart(sanitizedSuite, suiteLength) +
|
|
1939
|
+
`${separator}${truncateTestOptimizationNameMiddle(sanitizedName, testNameLength)}`
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1880
1942
|
/**
|
|
1881
1943
|
* Renders a bounded bullet list for Test Optimization summaries.
|
|
1882
1944
|
*
|
|
@@ -1888,7 +1950,12 @@ function formatTestOptimizationList (items) {
|
|
|
1888
1950
|
const more = items.length - shown.length
|
|
1889
1951
|
const moreSuffix = more > 0 ? `\n ... and ${more} more` : ''
|
|
1890
1952
|
|
|
1891
|
-
return shown
|
|
1953
|
+
return shown
|
|
1954
|
+
.map(({ text, suffix }) => ` • ${truncateTestOptimizationNameMiddle(
|
|
1955
|
+
sanitizeTestOptimizationName(text),
|
|
1956
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
1957
|
+
)}${suffix ? ` (${suffix})` : ''}`)
|
|
1958
|
+
.join('\n') + moreSuffix
|
|
1892
1959
|
}
|
|
1893
1960
|
|
|
1894
1961
|
/**
|
|
@@ -1901,15 +1968,67 @@ function formatTestOptimizationList (items) {
|
|
|
1901
1968
|
function logAttemptToFixTestExecution (testSuite, testName, loggedAttemptToFixTests) {
|
|
1902
1969
|
if (!testName) return
|
|
1903
1970
|
|
|
1904
|
-
const name = formatTestOptimizationName(testSuite, testName)
|
|
1905
1971
|
if (loggedAttemptToFixTests) {
|
|
1906
|
-
|
|
1972
|
+
const identity = getTestOptimizationIdentity(testSuite, testName)
|
|
1973
|
+
if (loggedAttemptToFixTests.has(identity)) return
|
|
1907
1974
|
|
|
1908
|
-
loggedAttemptToFixTests.add(
|
|
1975
|
+
loggedAttemptToFixTests.add(identity)
|
|
1909
1976
|
}
|
|
1910
1977
|
|
|
1911
1978
|
// eslint-disable-next-line no-console -- Intentional user-facing attempt-to-fix progress report
|
|
1912
|
-
console.warn(`Datadog Test Optimization: attempting to fix ${
|
|
1979
|
+
console.warn(`Datadog Test Optimization: attempting to fix ${formatTestOptimizationDisplayName(testSuite, testName)}`)
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* @typedef {object} TestManagementExecutionResult
|
|
1984
|
+
* @property {string} name
|
|
1985
|
+
* @property {'disabled'|'quarantined'} action
|
|
1986
|
+
* @property {boolean} failed
|
|
1987
|
+
*/
|
|
1988
|
+
|
|
1989
|
+
/**
|
|
1990
|
+
* @typedef {Map<string, TestManagementExecutionResult>} TestManagementExecutions
|
|
1991
|
+
*/
|
|
1992
|
+
|
|
1993
|
+
/**
|
|
1994
|
+
* Records the effective non-Attempt-to-Fix Test Management action for one execution.
|
|
1995
|
+
*
|
|
1996
|
+
* @param {{
|
|
1997
|
+
* testSuite?: string,
|
|
1998
|
+
* testName: string,
|
|
1999
|
+
* status?: string,
|
|
2000
|
+
* isAttemptToFix?: boolean,
|
|
2001
|
+
* isDisabled?: boolean,
|
|
2002
|
+
* isQuarantined?: boolean
|
|
2003
|
+
* }} execution
|
|
2004
|
+
* @param {TestManagementExecutions} [executions]
|
|
2005
|
+
*/
|
|
2006
|
+
function recordTestManagementExecution (execution, executions = testManagementExecutions) {
|
|
2007
|
+
if (!execution?.testName || execution.isAttemptToFix) return
|
|
2008
|
+
|
|
2009
|
+
const action = execution.isDisabled
|
|
2010
|
+
? 'disabled'
|
|
2011
|
+
: execution.isQuarantined ? 'quarantined' : undefined
|
|
2012
|
+
if (!action) return
|
|
2013
|
+
if (action === 'quarantined' && execution.status !== 'pass' && execution.status !== 'fail') return
|
|
2014
|
+
if (getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') === false) return
|
|
2015
|
+
|
|
2016
|
+
const identity = getTestOptimizationIdentity(execution.testSuite, execution.testName)
|
|
2017
|
+
const name = formatTestOptimizationName(execution.testSuite, execution.testName)
|
|
2018
|
+
let result = executions.get(identity)
|
|
2019
|
+
|
|
2020
|
+
if (!result) {
|
|
2021
|
+
result = {
|
|
2022
|
+
name,
|
|
2023
|
+
action,
|
|
2024
|
+
failed: false,
|
|
2025
|
+
}
|
|
2026
|
+
executions.set(identity, result)
|
|
2027
|
+
} else if (action === 'disabled') {
|
|
2028
|
+
result.action = action
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
result.failed ||= execution.status === 'fail'
|
|
1913
2032
|
}
|
|
1914
2033
|
|
|
1915
2034
|
/**
|
|
@@ -1926,10 +2045,12 @@ function logAttemptToFixTestExecution (testSuite, testName, loggedAttemptToFixTe
|
|
|
1926
2045
|
*/
|
|
1927
2046
|
function recordAttemptToFixExecution (attemptToFixExecutions, execution) {
|
|
1928
2047
|
if (!execution?.testName) return
|
|
2048
|
+
if (getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') === false) return
|
|
1929
2049
|
|
|
1930
2050
|
const { testSuite, testName, status, isDisabled, isQuarantined } = execution
|
|
2051
|
+
const identity = getTestOptimizationIdentity(testSuite, testName)
|
|
1931
2052
|
const name = formatTestOptimizationName(testSuite, testName)
|
|
1932
|
-
let result = attemptToFixExecutions.get(
|
|
2053
|
+
let result = attemptToFixExecutions.get(identity)
|
|
1933
2054
|
|
|
1934
2055
|
if (!result) {
|
|
1935
2056
|
result = {
|
|
@@ -1939,7 +2060,7 @@ function recordAttemptToFixExecution (attemptToFixExecutions, execution) {
|
|
|
1939
2060
|
isDisabled: false,
|
|
1940
2061
|
isQuarantined: false,
|
|
1941
2062
|
}
|
|
1942
|
-
attemptToFixExecutions.set(
|
|
2063
|
+
attemptToFixExecutions.set(identity, result)
|
|
1943
2064
|
}
|
|
1944
2065
|
|
|
1945
2066
|
result.executions++
|
|
@@ -1975,6 +2096,27 @@ function collectAttemptToFixExecutionFromTraceSpan (span, attemptToFixExecutions
|
|
|
1975
2096
|
})
|
|
1976
2097
|
}
|
|
1977
2098
|
|
|
2099
|
+
/**
|
|
2100
|
+
* Records a Test Management execution from a serialized worker trace span.
|
|
2101
|
+
*
|
|
2102
|
+
* @param {{ meta?: Record<string, string> }} span
|
|
2103
|
+
* @param {TestManagementExecutions} executions
|
|
2104
|
+
* @returns {void}
|
|
2105
|
+
*/
|
|
2106
|
+
function collectTestManagementExecutionFromTraceSpan (span, executions) {
|
|
2107
|
+
const meta = span.meta
|
|
2108
|
+
if (!meta) return
|
|
2109
|
+
|
|
2110
|
+
recordTestManagementExecution({
|
|
2111
|
+
testSuite: meta[TEST_SUITE],
|
|
2112
|
+
testName: meta[TEST_NAME],
|
|
2113
|
+
status: meta[TEST_STATUS],
|
|
2114
|
+
isAttemptToFix: meta[TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX] === 'true',
|
|
2115
|
+
isDisabled: meta[TEST_MANAGEMENT_IS_DISABLED] === 'true',
|
|
2116
|
+
isQuarantined: meta[TEST_MANAGEMENT_IS_QUARANTINED] === 'true',
|
|
2117
|
+
}, executions)
|
|
2118
|
+
}
|
|
2119
|
+
|
|
1978
2120
|
/**
|
|
1979
2121
|
* Scans serialized worker trace payloads and populates Test Optimization summary data.
|
|
1980
2122
|
* Silently ignores parse errors.
|
|
@@ -1982,11 +2124,16 @@ function collectAttemptToFixExecutionFromTraceSpan (span, attemptToFixExecutions
|
|
|
1982
2124
|
* @param {string} data - JSON-serialized traces from a worker
|
|
1983
2125
|
* @param {{
|
|
1984
2126
|
* newTestsWithDynamicNames?: Set<string>,
|
|
1985
|
-
* attemptToFixExecutions?: AttemptToFixExecutions
|
|
2127
|
+
* attemptToFixExecutions?: AttemptToFixExecutions,
|
|
2128
|
+
* testManagementExecutions?: TestManagementExecutions
|
|
1986
2129
|
* }} summaries
|
|
1987
2130
|
*/
|
|
1988
2131
|
function collectTestOptimizationSummariesFromTraces (data, summaries) {
|
|
1989
|
-
const {
|
|
2132
|
+
const {
|
|
2133
|
+
newTestsWithDynamicNames,
|
|
2134
|
+
attemptToFixExecutions,
|
|
2135
|
+
testManagementExecutions: executions = testManagementExecutions,
|
|
2136
|
+
} = summaries
|
|
1990
2137
|
|
|
1991
2138
|
try {
|
|
1992
2139
|
const traces = JSON.parse(data)
|
|
@@ -1998,6 +2145,7 @@ function collectTestOptimizationSummariesFromTraces (data, summaries) {
|
|
|
1998
2145
|
if (attemptToFixExecutions) {
|
|
1999
2146
|
collectAttemptToFixExecutionFromTraceSpan(span, attemptToFixExecutions)
|
|
2000
2147
|
}
|
|
2148
|
+
collectTestManagementExecutionFromTraceSpan(span, executions)
|
|
2001
2149
|
}
|
|
2002
2150
|
}
|
|
2003
2151
|
} catch {
|
|
@@ -2044,7 +2192,10 @@ function hasAttemptToFixManagementNotes (result) {
|
|
|
2044
2192
|
}
|
|
2045
2193
|
|
|
2046
2194
|
function addAttemptToFixResultLine (lines, result) {
|
|
2047
|
-
lines.push(` • ${
|
|
2195
|
+
lines.push(` • ${truncateTestOptimizationNameMiddle(
|
|
2196
|
+
sanitizeTestOptimizationName(result.name),
|
|
2197
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
2198
|
+
)}`)
|
|
2048
2199
|
|
|
2049
2200
|
for (const note of getAttemptToFixManagementNotes(result)) {
|
|
2050
2201
|
lines.push(` ${note}`)
|
|
@@ -2055,9 +2206,10 @@ function addAttemptToFixResultLine (lines, result) {
|
|
|
2055
2206
|
* Formats the attempt-to-fix end-of-session summary.
|
|
2056
2207
|
*
|
|
2057
2208
|
* @param {AttemptToFixExecutions} attemptToFixExecutions
|
|
2209
|
+
* @param {boolean} [includeTestNames]
|
|
2058
2210
|
* @returns {string}
|
|
2059
2211
|
*/
|
|
2060
|
-
function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
2212
|
+
function formatAttemptToFixSummary (attemptToFixExecutions, includeTestNames = true) {
|
|
2061
2213
|
if (attemptToFixExecutions.size === 0) return ''
|
|
2062
2214
|
|
|
2063
2215
|
const results = [...attemptToFixExecutions.values()]
|
|
@@ -2069,9 +2221,11 @@ function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
|
2069
2221
|
`Attempt to fix passed: all ${totalExecutions} execution(s) passed for ${results.length} test(s).`,
|
|
2070
2222
|
]
|
|
2071
2223
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2224
|
+
if (includeTestNames) {
|
|
2225
|
+
for (const result of results) {
|
|
2226
|
+
if (hasAttemptToFixManagementNotes(result)) {
|
|
2227
|
+
addAttemptToFixResultLine(lines, result)
|
|
2228
|
+
}
|
|
2075
2229
|
}
|
|
2076
2230
|
}
|
|
2077
2231
|
|
|
@@ -2087,13 +2241,67 @@ function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
|
2087
2241
|
`across ${failedResults.length} of ${results.length} test(s).`,
|
|
2088
2242
|
]
|
|
2089
2243
|
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
}
|
|
2093
|
-
for (const result of results) {
|
|
2094
|
-
if (result.failedCount === 0 && hasAttemptToFixManagementNotes(result)) {
|
|
2244
|
+
if (includeTestNames) {
|
|
2245
|
+
for (const result of failedResults) {
|
|
2095
2246
|
addAttemptToFixResultLine(lines, result)
|
|
2096
2247
|
}
|
|
2248
|
+
for (const result of results) {
|
|
2249
|
+
if (result.failedCount === 0 && hasAttemptToFixManagementNotes(result)) {
|
|
2250
|
+
addAttemptToFixResultLine(lines, result)
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
return lines.join('\n')
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
/**
|
|
2259
|
+
* Formats the disabled and quarantined Test Management summary.
|
|
2260
|
+
*
|
|
2261
|
+
* @param {TestManagementExecutions} executions
|
|
2262
|
+
* @param {boolean} [includeTestNames]
|
|
2263
|
+
* @returns {string}
|
|
2264
|
+
*/
|
|
2265
|
+
function formatTestManagementSummary (executions, includeTestNames = true) {
|
|
2266
|
+
if (executions.size === 0) return ''
|
|
2267
|
+
|
|
2268
|
+
const results = [...executions.values()]
|
|
2269
|
+
const disabledResults = results.filter(result => result.action === 'disabled')
|
|
2270
|
+
const quarantinedResults = results.filter(result => result.action === 'quarantined')
|
|
2271
|
+
const failedQuarantinedResults = quarantinedResults.filter(result => result.failed)
|
|
2272
|
+
const lines = ['Test Management']
|
|
2273
|
+
|
|
2274
|
+
if (disabledResults.length > 0) {
|
|
2275
|
+
const testLabel = disabledResults.length === 1 ? 'test' : 'tests'
|
|
2276
|
+
lines.push(` Disabled: ${disabledResults.length} ${testLabel} skipped.`)
|
|
2277
|
+
}
|
|
2278
|
+
if (quarantinedResults.length > 0) {
|
|
2279
|
+
const testLabel = quarantinedResults.length === 1 ? 'test' : 'tests'
|
|
2280
|
+
if (failedQuarantinedResults.length > 0) {
|
|
2281
|
+
const failureLabel = failedQuarantinedResults.length === 1 ? 'failure' : 'failures'
|
|
2282
|
+
lines.push(
|
|
2283
|
+
` Quarantined: ${quarantinedResults.length} ${testLabel} run; ` +
|
|
2284
|
+
`${failedQuarantinedResults.length} ${failureLabel} did not affect the test session.`
|
|
2285
|
+
)
|
|
2286
|
+
} else {
|
|
2287
|
+
lines.push(` Quarantined: ${quarantinedResults.length} ${testLabel} run; all passed.`)
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
if (includeTestNames) {
|
|
2292
|
+
lines.push('', ' Affected tests:')
|
|
2293
|
+
results.sort((a, b) => a.name.localeCompare(b.name))
|
|
2294
|
+
for (const result of results) {
|
|
2295
|
+
const status = result.action === 'disabled'
|
|
2296
|
+
? 'disabled'
|
|
2297
|
+
: result.failed ? 'quarantined, failed' : 'quarantined, passed'
|
|
2298
|
+
lines.push(
|
|
2299
|
+
` • [${status}] ${truncateTestOptimizationNameMiddle(
|
|
2300
|
+
sanitizeTestOptimizationName(result.name),
|
|
2301
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
2302
|
+
)}`
|
|
2303
|
+
)
|
|
2304
|
+
}
|
|
2097
2305
|
}
|
|
2098
2306
|
|
|
2099
2307
|
return lines.join('\n')
|
|
@@ -2124,25 +2332,57 @@ function formatDynamicNamesSummary (newTestsWithDynamicNames) {
|
|
|
2124
2332
|
*
|
|
2125
2333
|
* @param {{
|
|
2126
2334
|
* attemptToFixExecutions?: AttemptToFixExecutions,
|
|
2335
|
+
* testManagementExecutions?: TestManagementExecutions,
|
|
2127
2336
|
* newTestsWithDynamicNames?: Set<string>,
|
|
2128
2337
|
* extraSections?: string[]
|
|
2129
2338
|
* }} summary
|
|
2130
2339
|
*/
|
|
2131
2340
|
function logTestOptimizationSummary (summary) {
|
|
2132
|
-
const {
|
|
2341
|
+
const {
|
|
2342
|
+
attemptToFixExecutions,
|
|
2343
|
+
testManagementExecutions: executions = testManagementExecutions,
|
|
2344
|
+
newTestsWithDynamicNames,
|
|
2345
|
+
extraSections = [],
|
|
2346
|
+
} = summary
|
|
2133
2347
|
const sections = []
|
|
2134
|
-
const
|
|
2135
|
-
|
|
2348
|
+
const isTestManagementReportEnabled =
|
|
2349
|
+
getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') !== false
|
|
2350
|
+
const testManagementTestCount = (attemptToFixExecutions?.size || 0) + executions.size
|
|
2351
|
+
const includeTestNames = testManagementTestCount <= MAX_TEST_MANAGEMENT_REPORT_ITEMS
|
|
2352
|
+
const attemptToFixSummary = isTestManagementReportEnabled && attemptToFixExecutions
|
|
2353
|
+
? formatAttemptToFixSummary(attemptToFixExecutions, includeTestNames)
|
|
2354
|
+
: ''
|
|
2355
|
+
const testManagementSummary = isTestManagementReportEnabled
|
|
2356
|
+
? formatTestManagementSummary(executions, includeTestNames)
|
|
2136
2357
|
: ''
|
|
2137
2358
|
const dynamicNamesSummary = newTestsWithDynamicNames
|
|
2138
2359
|
? formatDynamicNamesSummary(newTestsWithDynamicNames)
|
|
2139
2360
|
: ''
|
|
2140
2361
|
|
|
2141
2362
|
if (attemptToFixSummary) sections.push(attemptToFixSummary)
|
|
2363
|
+
if (testManagementSummary) sections.push(testManagementSummary)
|
|
2364
|
+
if (attemptToFixSummary || testManagementSummary) {
|
|
2365
|
+
if (!includeTestNames) {
|
|
2366
|
+
sections.push(`Individual test names omitted because ${testManagementTestCount} tests were affected.`)
|
|
2367
|
+
}
|
|
2368
|
+
sections.push('Hide this report: DD_TEST_MANAGEMENT_REPORT_ENABLED=false')
|
|
2369
|
+
}
|
|
2142
2370
|
sections.push(...extraSections.filter(Boolean))
|
|
2143
2371
|
if (dynamicNamesSummary) sections.push(dynamicNamesSummary)
|
|
2144
2372
|
|
|
2145
|
-
if (sections.length === 0)
|
|
2373
|
+
if (sections.length === 0) {
|
|
2374
|
+
executions.clear()
|
|
2375
|
+
if (executions !== testManagementExecutions) {
|
|
2376
|
+
testManagementExecutions.clear()
|
|
2377
|
+
}
|
|
2378
|
+
if (attemptToFixExecutions) {
|
|
2379
|
+
attemptToFixExecutions.clear()
|
|
2380
|
+
}
|
|
2381
|
+
if (newTestsWithDynamicNames) {
|
|
2382
|
+
newTestsWithDynamicNames.clear()
|
|
2383
|
+
}
|
|
2384
|
+
return
|
|
2385
|
+
}
|
|
2146
2386
|
|
|
2147
2387
|
const line = '-'.repeat(50)
|
|
2148
2388
|
// eslint-disable-next-line no-console -- Intentional user-facing session summary
|
|
@@ -2151,6 +2391,10 @@ function logTestOptimizationSummary (summary) {
|
|
|
2151
2391
|
if (attemptToFixExecutions) {
|
|
2152
2392
|
attemptToFixExecutions.clear()
|
|
2153
2393
|
}
|
|
2394
|
+
executions.clear()
|
|
2395
|
+
if (executions !== testManagementExecutions) {
|
|
2396
|
+
testManagementExecutions.clear()
|
|
2397
|
+
}
|
|
2154
2398
|
if (newTestsWithDynamicNames) {
|
|
2155
2399
|
newTestsWithDynamicNames.clear()
|
|
2156
2400
|
}
|
|
@@ -14,7 +14,7 @@ const INT_SEGMENT = /^[1-9][0-9]+$/ // Integer of size at least 2 (>=10)
|
|
|
14
14
|
const INT_ID_SEGMENT = /^(?=.*[0-9])[0-9._-]{3,}$/ // Mixed string with digits and delimiters
|
|
15
15
|
const HEX_SEGMENT = /^(?=.*[0-9])[A-Fa-f0-9]{6,}$/ // Hexadecimal digits of size at least 6 with at least one decimal digit
|
|
16
16
|
const HEX_ID_SEGMENT = /^(?=.*[0-9])[A-Fa-f0-9._-]{6,}$/ // Mixed string with hex digits and delimiters
|
|
17
|
-
const STRING_SEGMENT =
|
|
17
|
+
const STRING_SEGMENT = /(?:^.{20,}|[%&'()*+,:=@])/ // Long string or a string containing special characters
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Extract full URL from HTTP request
|