dd-trace 6.8.0 → 6.10.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 +140 -42
- package/index.d.ts +140 -1
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +8 -5
- 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/confluentinc-kafka-javascript.js +111 -6
- 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/pool-acquire.js +629 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +199 -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 +62 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- 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 +980 -234
- package/packages/datadog-instrumentations/src/mocha/main.js +108 -10
- package/packages/datadog-instrumentations/src/mocha/utils.js +66 -50
- 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 +46 -16
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/next.js +155 -23
- package/packages/datadog-instrumentations/src/openai.js +14 -0
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +209 -11
- 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 +85 -13
- package/packages/datadog-instrumentations/src/vitest-main.js +528 -72
- package/packages/datadog-instrumentations/src/vitest-util.js +106 -12
- package/packages/datadog-instrumentations/src/vitest-worker.js +382 -40
- package/packages/datadog-instrumentations/src/webdriverio.js +212 -22
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- 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 +51 -47
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- 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 +6 -22
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +5 -3
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +832 -4
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-next/src/index.js +51 -21
- package/packages/datadog-plugin-openai/src/tracing.js +4 -0
- package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +66 -1
- package/packages/datadog-plugin-playwright/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +103 -27
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- 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/api_security/normalized-route.js +453 -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 +228 -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/carrier.js +356 -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 +5 -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 +18 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/manager.js +5 -1
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +3 -2
- 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/constants/tags.js +5 -0
- 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/index.js +34 -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/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -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/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/plugin_manager.js +2 -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/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +3 -62
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/test.js +397 -74
- package/packages/dd-trace/src/plugins/util/url.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +76 -3
- 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,21 +3,23 @@
|
|
|
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')
|
|
11
|
+
const { parse } = require('../../../../../vendor/dist/jest-docblock')
|
|
10
12
|
const satisfies = require('../../../../../vendor/dist/semifies')
|
|
11
13
|
|
|
12
14
|
const istanbul = require('../../../../../vendor/dist/istanbul-lib-coverage')
|
|
13
15
|
|
|
16
|
+
const { writeDatadogParentId, writeDatadogTraceId } = require('../../carrier')
|
|
14
17
|
const id = require('../../id')
|
|
15
18
|
const {
|
|
16
19
|
incrementCountMetric,
|
|
17
20
|
TELEMETRY_GIT_COMMIT_SHA_DISCREPANCY,
|
|
18
21
|
TELEMETRY_GIT_SHA_MATCH,
|
|
19
22
|
} = require('../../ci-visibility/telemetry')
|
|
20
|
-
|
|
21
23
|
const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../../../ext/tags')
|
|
22
24
|
const { SAMPLING_RULE_DECISION } = require('../../constants')
|
|
23
25
|
const { AUTO_KEEP } = require('../../../../../ext/priority')
|
|
@@ -123,13 +125,10 @@ const TEST_RETRY_REASON = 'test.retry_reason'
|
|
|
123
125
|
const TEST_HAS_FAILED_ALL_RETRIES = 'test.has_failed_all_retries'
|
|
124
126
|
const TEST_IS_MODIFIED = 'test.is_modified'
|
|
125
127
|
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
128
|
const CI_APP_ORIGIN = 'ciapp-test'
|
|
129
|
+
// eslint-disable-next-line no-control-regex
|
|
130
|
+
const TEST_OPTIMIZATION_NAME_CONTROL_RE = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g
|
|
131
|
+
const TEST_OPTIMIZATION_NAME_WHITESPACE_RE = /\s+/g
|
|
133
132
|
|
|
134
133
|
// Matches patterns that are almost certainly runtime-generated values in test names:
|
|
135
134
|
// - Unix timestamps in ms (13 digits, years ~2020-2090) or s (10 digits)
|
|
@@ -162,6 +161,7 @@ const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
|
|
|
162
161
|
const TEST_ITR_UNSKIPPABLE = 'test.itr.unskippable'
|
|
163
162
|
const TEST_ITR_FORCED_RUN = 'test.itr.forced_run'
|
|
164
163
|
const ITR_CORRELATION_ID = 'itr_correlation_id'
|
|
164
|
+
const TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE = 'Test Impact Analysis skipped all tests.'
|
|
165
165
|
|
|
166
166
|
const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
|
|
167
167
|
|
|
@@ -180,17 +180,24 @@ const JEST_WORKER_QUARANTINE_PAYLOAD_CODE = 64
|
|
|
180
180
|
|
|
181
181
|
// cucumber worker variables
|
|
182
182
|
const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
|
|
183
|
+
const CUCUMBER_WORKER_TELEMETRY_PAYLOAD_CODE = 71
|
|
183
184
|
|
|
184
185
|
// mocha worker variables
|
|
185
186
|
const MOCHA_WORKER_TRACE_PAYLOAD_CODE = 80
|
|
186
187
|
const MOCHA_WORKER_LOGS_PAYLOAD_CODE = 81
|
|
188
|
+
const MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE = 82
|
|
187
189
|
|
|
188
190
|
// playwright worker variables
|
|
189
191
|
const PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE = 90
|
|
192
|
+
const PLAYWRIGHT_WORKER_TELEMETRY_PAYLOAD_CODE = 91
|
|
190
193
|
|
|
191
194
|
// vitest worker variables
|
|
192
195
|
const VITEST_WORKER_TRACE_PAYLOAD_CODE = 100
|
|
196
|
+
const VITEST_WORKER_COVERAGE_PAYLOAD_CODE = 101
|
|
193
197
|
const VITEST_WORKER_LOGS_PAYLOAD_CODE = 102
|
|
198
|
+
const VITEST_WORKER_TELEMETRY_PAYLOAD_CODE = 103
|
|
199
|
+
const VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE = 104
|
|
200
|
+
const VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE = 105
|
|
194
201
|
|
|
195
202
|
const TEST_IS_TEST_FRAMEWORK_WORKER = 'test.is_test_framework_worker'
|
|
196
203
|
|
|
@@ -211,7 +218,7 @@ const DD_CI_LIBRARY_CONFIGURATION_ERROR_KNOWN_TESTS = '_dd.ci.library_configurat
|
|
|
211
218
|
const DD_CI_LIBRARY_CONFIGURATION_ERROR_TEST_MANAGEMENT_TESTS =
|
|
212
219
|
'_dd.ci.library_configuration_error.test_management_tests'
|
|
213
220
|
|
|
214
|
-
const UNSUPPORTED_TIA_FRAMEWORKS = new Set(['playwright', '
|
|
221
|
+
const UNSUPPORTED_TIA_FRAMEWORKS = new Set(['playwright', 'webdriverio'])
|
|
215
222
|
const MINIMUM_FRAMEWORK_VERSION_FOR_EFD = {
|
|
216
223
|
playwright: '>=1.38.0',
|
|
217
224
|
}
|
|
@@ -300,7 +307,10 @@ const TEST_MANAGEMENT_IS_QUARANTINED = 'test.test_management.is_quarantined'
|
|
|
300
307
|
const TEST_MANAGEMENT_ENABLED = 'test.test_management.enabled'
|
|
301
308
|
const TEST_MANAGEMENT_ATTEMPT_TO_FIX_PASSED = 'test.test_management.attempt_to_fix_passed'
|
|
302
309
|
|
|
310
|
+
const MAX_TEST_MANAGEMENT_REPORT_ITEMS = 5
|
|
311
|
+
const MAX_TEST_OPTIMIZATION_NAME_LENGTH = 160
|
|
303
312
|
const MAX_TEST_OPTIMIZATION_SUMMARY_ITEMS = 10
|
|
313
|
+
const testManagementExecutions = new Map()
|
|
304
314
|
|
|
305
315
|
// Impacted tests
|
|
306
316
|
const POSSIBLE_BASE_BRANCHES = ['main', 'master', 'preprod', 'prod', 'dev', 'development', 'trunk']
|
|
@@ -472,11 +482,18 @@ module.exports = {
|
|
|
472
482
|
JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
473
483
|
JEST_WORKER_QUARANTINE_PAYLOAD_CODE,
|
|
474
484
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
485
|
+
CUCUMBER_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
475
486
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
476
487
|
MOCHA_WORKER_LOGS_PAYLOAD_CODE,
|
|
488
|
+
MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
477
489
|
PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE,
|
|
490
|
+
PLAYWRIGHT_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
478
491
|
VITEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
492
|
+
VITEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
479
493
|
VITEST_WORKER_LOGS_PAYLOAD_CODE,
|
|
494
|
+
VITEST_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
495
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_REQUEST_CODE,
|
|
496
|
+
VITEST_WORKER_EFD_SUITE_ADMISSION_RESPONSE_CODE,
|
|
480
497
|
TEST_IS_TEST_FRAMEWORK_WORKER,
|
|
481
498
|
TEST_SOURCE_START,
|
|
482
499
|
TEST_SKIPPED_BY_ITR,
|
|
@@ -492,6 +509,7 @@ module.exports = {
|
|
|
492
509
|
getTestParametersString,
|
|
493
510
|
finishAllTraceSpans,
|
|
494
511
|
getTestParentSpan,
|
|
512
|
+
isMarkedAsUnskippable,
|
|
495
513
|
getTestSuitePath,
|
|
496
514
|
getCodeOwnersFileEntries,
|
|
497
515
|
getCodeOwnersForFilename,
|
|
@@ -515,6 +533,7 @@ module.exports = {
|
|
|
515
533
|
TEST_ITR_UNSKIPPABLE,
|
|
516
534
|
TEST_ITR_FORCED_RUN,
|
|
517
535
|
ITR_CORRELATION_ID,
|
|
536
|
+
TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE,
|
|
518
537
|
addIntelligentTestRunnerSpanTags,
|
|
519
538
|
getCoveredFilenamesFromCoverage,
|
|
520
539
|
getCoveredFilesFromCoverage,
|
|
@@ -531,9 +550,7 @@ module.exports = {
|
|
|
531
550
|
removeInvalidMetadata,
|
|
532
551
|
parseAnnotations,
|
|
533
552
|
getIsFaultyEarlyFlakeDetection,
|
|
534
|
-
|
|
535
|
-
getEfdRetryCount,
|
|
536
|
-
getMaxEfdRetryCount,
|
|
553
|
+
getFailedTestReplayPromise,
|
|
537
554
|
TEST_BROWSER_DRIVER,
|
|
538
555
|
TEST_BROWSER_DRIVER_VERSION,
|
|
539
556
|
TEST_BROWSER_NAME,
|
|
@@ -584,8 +601,10 @@ module.exports = {
|
|
|
584
601
|
collectDynamicNamesFromTraces,
|
|
585
602
|
collectTestOptimizationSummariesFromTraces,
|
|
586
603
|
logDynamicNamesWarning,
|
|
604
|
+
recordTestManagementExecution,
|
|
587
605
|
recordAttemptToFixExecution,
|
|
588
606
|
collectAttemptToFixExecutionsFromTraces,
|
|
607
|
+
formatTestManagementSummary,
|
|
589
608
|
formatAttemptToFixSummary,
|
|
590
609
|
logAttemptToFixTestExecution,
|
|
591
610
|
formatDynamicNamesSummary,
|
|
@@ -732,6 +751,7 @@ function checkShaDiscrepancies (ciMetadata, userProvidedGitMetadata) {
|
|
|
732
751
|
*
|
|
733
752
|
* @param {string=} testFramework
|
|
734
753
|
* @param {TestEnvironmentConfig=} config
|
|
754
|
+
* @param {boolean=} shouldSkipGitMetadataExtraction
|
|
735
755
|
* @returns {TestEnvironmentMetadata}
|
|
736
756
|
*/
|
|
737
757
|
function getTestEnvironmentMetadata (testFramework, config, shouldSkipGitMetadataExtraction = false) {
|
|
@@ -888,10 +908,10 @@ function setRumTestCorrelation (context, activeSpan) {
|
|
|
888
908
|
* @returns {import('../../opentracing/span_context')}
|
|
889
909
|
*/
|
|
890
910
|
function getTestParentSpan (tracer, testExecutionId) {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
911
|
+
const carrier = /** @type {Record<string, unknown>} */ ({})
|
|
912
|
+
writeDatadogTraceId(carrier, testExecutionId || id().toString(10))
|
|
913
|
+
writeDatadogParentId(carrier, '0000000000000000')
|
|
914
|
+
return tracer.extract('text_map', carrier)
|
|
895
915
|
}
|
|
896
916
|
|
|
897
917
|
function getTestCommonTags (name, suite, version, testFramework) {
|
|
@@ -912,6 +932,10 @@ function getTestCommonTags (name, suite, version, testFramework) {
|
|
|
912
932
|
/**
|
|
913
933
|
* We want to make sure that test suites are reported the same way for
|
|
914
934
|
* every OS, so we replace `path.sep` by `/`
|
|
935
|
+
*
|
|
936
|
+
* @param {string | undefined} testSuiteAbsolutePath
|
|
937
|
+
* @param {string} sourceRoot
|
|
938
|
+
* @returns {string}
|
|
915
939
|
*/
|
|
916
940
|
function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
|
|
917
941
|
if (!testSuiteAbsolutePath) {
|
|
@@ -924,6 +948,62 @@ function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
|
|
|
924
948
|
return testSuitePath.replaceAll(path.sep, '/')
|
|
925
949
|
}
|
|
926
950
|
|
|
951
|
+
const globalDocblockRegExp = /^\s*(\/\*\*?(.|\r?\n)*?\*\/)/
|
|
952
|
+
const MAX_COMMENTS_CHECKED = 10
|
|
953
|
+
|
|
954
|
+
function isMarkedAsUnskippable (test) {
|
|
955
|
+
let testSource
|
|
956
|
+
|
|
957
|
+
try {
|
|
958
|
+
testSource = fs.readFileSync(test.path, 'utf8')
|
|
959
|
+
} catch {
|
|
960
|
+
return false
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const re = globalDocblockRegExp
|
|
964
|
+
re.lastIndex = 0
|
|
965
|
+
let commentsChecked = 0
|
|
966
|
+
|
|
967
|
+
while (testSource.length) {
|
|
968
|
+
const match = re.exec(testSource)
|
|
969
|
+
if (!match) break
|
|
970
|
+
const comment = match[1]
|
|
971
|
+
|
|
972
|
+
let docblocks
|
|
973
|
+
try {
|
|
974
|
+
docblocks = parse(comment)
|
|
975
|
+
} catch {
|
|
976
|
+
// Skip unparsable comment and continue scanning
|
|
977
|
+
if (commentsChecked++ >= MAX_COMMENTS_CHECKED) {
|
|
978
|
+
return false
|
|
979
|
+
}
|
|
980
|
+
continue
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
if (docblocks?.datadog) {
|
|
984
|
+
try {
|
|
985
|
+
// @ts-expect-error The datadog type is defined by us and may only be a string.
|
|
986
|
+
return JSON.parse(docblocks.datadog).unskippable
|
|
987
|
+
} catch {
|
|
988
|
+
// If the @datadog block comment is present but malformed, we'll run the suite
|
|
989
|
+
log.warn('@datadog block comment is malformed.')
|
|
990
|
+
return true
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (commentsChecked++ >= MAX_COMMENTS_CHECKED) {
|
|
995
|
+
return false
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// To stop as soon as no doc blocks are found, slice the source. That way the
|
|
999
|
+
// regexp works by using the `^` anchor. Without it, it would continue
|
|
1000
|
+
// scanning the rest of the file.
|
|
1001
|
+
testSource = testSource.slice(match[0].length)
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return false
|
|
1005
|
+
}
|
|
1006
|
+
|
|
927
1007
|
const POSSIBLE_CODEOWNERS_LOCATIONS = [
|
|
928
1008
|
'CODEOWNERS',
|
|
929
1009
|
'.github/CODEOWNERS',
|
|
@@ -1526,43 +1606,19 @@ function parseAnnotations (annotations) {
|
|
|
1526
1606
|
}
|
|
1527
1607
|
|
|
1528
1608
|
/**
|
|
1529
|
-
*
|
|
1530
|
-
* from the backend, return how many EFD retries to run.
|
|
1609
|
+
* Combines the optional Failed Test Replay operations that must settle before a retry.
|
|
1531
1610
|
*
|
|
1532
|
-
*
|
|
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}
|
|
1611
|
+
* @param {{setProbePromise?: Promise<void>, finishTestPromise?: Promise<void>}} promises
|
|
1612
|
+
* @returns {Promise<void>|undefined}
|
|
1552
1613
|
*/
|
|
1553
|
-
function
|
|
1554
|
-
if (
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
let maxRetries = 0
|
|
1560
|
-
for (const retryCount of retryCounts) {
|
|
1561
|
-
if (retryCount > maxRetries) {
|
|
1562
|
-
maxRetries = retryCount
|
|
1563
|
-
}
|
|
1614
|
+
function getFailedTestReplayPromise (promises) {
|
|
1615
|
+
if (promises.setProbePromise && promises.finishTestPromise) {
|
|
1616
|
+
return Promise.all([
|
|
1617
|
+
promises.setProbePromise,
|
|
1618
|
+
promises.finishTestPromise,
|
|
1619
|
+
]).then(() => {})
|
|
1564
1620
|
}
|
|
1565
|
-
return
|
|
1621
|
+
return promises.setProbePromise || promises.finishTestPromise
|
|
1566
1622
|
}
|
|
1567
1623
|
|
|
1568
1624
|
function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faultyThresholdPercentage) {
|
|
@@ -1706,7 +1762,8 @@ function isFailedTestReplaySupported (testFramework, frameworkVersion) {
|
|
|
1706
1762
|
|
|
1707
1763
|
function getLibraryCapabilitiesTags (testFramework, frameworkVersion, options = {}) {
|
|
1708
1764
|
return {
|
|
1709
|
-
[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS]:
|
|
1765
|
+
[DD_CAPABILITIES_TEST_IMPACT_ANALYSIS]: !options.omitTestImpactAnalysis &&
|
|
1766
|
+
isTiaSupported(testFramework)
|
|
1710
1767
|
? '1'
|
|
1711
1768
|
: undefined,
|
|
1712
1769
|
[DD_CAPABILITIES_EARLY_FLAKE_DETECTION]: isEarlyFlakeDetectionSupported(testFramework, frameworkVersion)
|
|
@@ -1866,6 +1923,17 @@ function getModifiedFilesFromDiff (diff) {
|
|
|
1866
1923
|
* @typedef {Map<string, AttemptToFixExecutionResult>} AttemptToFixExecutions
|
|
1867
1924
|
*/
|
|
1868
1925
|
|
|
1926
|
+
/**
|
|
1927
|
+
* Returns a collision-free identity for a test's suite and name.
|
|
1928
|
+
*
|
|
1929
|
+
* @param {string | undefined} testSuite
|
|
1930
|
+
* @param {string} testName
|
|
1931
|
+
* @returns {string}
|
|
1932
|
+
*/
|
|
1933
|
+
function getTestOptimizationIdentity (testSuite, testName) {
|
|
1934
|
+
return JSON.stringify([testSuite, testName])
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1869
1937
|
/**
|
|
1870
1938
|
* Formats a test name for user-facing Test Optimization summaries.
|
|
1871
1939
|
*
|
|
@@ -1877,6 +1945,79 @@ function formatTestOptimizationName (testSuite, testName) {
|
|
|
1877
1945
|
return testSuite ? `${testSuite} › ${testName}` : testName
|
|
1878
1946
|
}
|
|
1879
1947
|
|
|
1948
|
+
/**
|
|
1949
|
+
* Replaces characters that could make one test occupy multiple CI log lines.
|
|
1950
|
+
*
|
|
1951
|
+
* @param {string} value
|
|
1952
|
+
* @returns {string}
|
|
1953
|
+
*/
|
|
1954
|
+
function sanitizeTestOptimizationName (value) {
|
|
1955
|
+
return stripVTControlCharacters(value)
|
|
1956
|
+
.replaceAll(TEST_OPTIMIZATION_NAME_CONTROL_RE, '')
|
|
1957
|
+
.replaceAll(TEST_OPTIMIZATION_NAME_WHITESPACE_RE, ' ')
|
|
1958
|
+
.trim()
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
/**
|
|
1962
|
+
* Truncates the beginning of a value while preserving its distinguishing suffix.
|
|
1963
|
+
*
|
|
1964
|
+
* @param {string} value
|
|
1965
|
+
* @param {number} maxLength
|
|
1966
|
+
* @returns {string}
|
|
1967
|
+
*/
|
|
1968
|
+
function truncateTestOptimizationNameStart (value, maxLength) {
|
|
1969
|
+
if (value.length <= maxLength) return value
|
|
1970
|
+
|
|
1971
|
+
let start = value.length - maxLength + 1
|
|
1972
|
+
const code = value.charCodeAt(start)
|
|
1973
|
+
if (code >= 0xDC_00 && code <= 0xDF_FF) start++
|
|
1974
|
+
return `…${value.slice(start)}`
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/**
|
|
1978
|
+
* Truncates the middle of a value while preserving both its context and suffix.
|
|
1979
|
+
*
|
|
1980
|
+
* @param {string} value
|
|
1981
|
+
* @param {number} maxLength
|
|
1982
|
+
* @returns {string}
|
|
1983
|
+
*/
|
|
1984
|
+
function truncateTestOptimizationNameMiddle (value, maxLength) {
|
|
1985
|
+
if (value.length <= maxLength) return value
|
|
1986
|
+
|
|
1987
|
+
let prefixLength = Math.ceil((maxLength - 1) / 2)
|
|
1988
|
+
let suffixLength = maxLength - prefixLength - 1
|
|
1989
|
+
const prefixCode = value.charCodeAt(prefixLength - 1)
|
|
1990
|
+
if (prefixCode >= 0xD8_00 && prefixCode <= 0xDB_FF) prefixLength--
|
|
1991
|
+
const suffixCode = value.charCodeAt(value.length - suffixLength)
|
|
1992
|
+
if (suffixCode >= 0xDC_00 && suffixCode <= 0xDF_FF) suffixLength--
|
|
1993
|
+
return `${value.slice(0, prefixLength)}…${value.slice(-suffixLength)}`
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* Formats a bounded, single-line test name for CI output.
|
|
1998
|
+
*
|
|
1999
|
+
* @param {string | undefined} testSuite
|
|
2000
|
+
* @param {string} testName
|
|
2001
|
+
* @returns {string}
|
|
2002
|
+
*/
|
|
2003
|
+
function formatTestOptimizationDisplayName (testSuite, testName) {
|
|
2004
|
+
const sanitizedSuite = testSuite ? sanitizeTestOptimizationName(testSuite) : ''
|
|
2005
|
+
const sanitizedName = sanitizeTestOptimizationName(testName)
|
|
2006
|
+
if (!sanitizedSuite) {
|
|
2007
|
+
return truncateTestOptimizationNameMiddle(sanitizedName, MAX_TEST_OPTIMIZATION_NAME_LENGTH)
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
const separator = ' › '
|
|
2011
|
+
if (sanitizedSuite.length + separator.length + sanitizedName.length <= MAX_TEST_OPTIMIZATION_NAME_LENGTH) {
|
|
2012
|
+
return `${sanitizedSuite}${separator}${sanitizedName}`
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
const suiteLength = Math.min(60, sanitizedSuite.length)
|
|
2016
|
+
const testNameLength = MAX_TEST_OPTIMIZATION_NAME_LENGTH - separator.length - suiteLength
|
|
2017
|
+
return truncateTestOptimizationNameStart(sanitizedSuite, suiteLength) +
|
|
2018
|
+
`${separator}${truncateTestOptimizationNameMiddle(sanitizedName, testNameLength)}`
|
|
2019
|
+
}
|
|
2020
|
+
|
|
1880
2021
|
/**
|
|
1881
2022
|
* Renders a bounded bullet list for Test Optimization summaries.
|
|
1882
2023
|
*
|
|
@@ -1888,7 +2029,12 @@ function formatTestOptimizationList (items) {
|
|
|
1888
2029
|
const more = items.length - shown.length
|
|
1889
2030
|
const moreSuffix = more > 0 ? `\n ... and ${more} more` : ''
|
|
1890
2031
|
|
|
1891
|
-
return shown
|
|
2032
|
+
return shown
|
|
2033
|
+
.map(({ text, suffix }) => ` • ${truncateTestOptimizationNameMiddle(
|
|
2034
|
+
sanitizeTestOptimizationName(text),
|
|
2035
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
2036
|
+
)}${suffix ? ` (${suffix})` : ''}`)
|
|
2037
|
+
.join('\n') + moreSuffix
|
|
1892
2038
|
}
|
|
1893
2039
|
|
|
1894
2040
|
/**
|
|
@@ -1901,15 +2047,67 @@ function formatTestOptimizationList (items) {
|
|
|
1901
2047
|
function logAttemptToFixTestExecution (testSuite, testName, loggedAttemptToFixTests) {
|
|
1902
2048
|
if (!testName) return
|
|
1903
2049
|
|
|
1904
|
-
const name = formatTestOptimizationName(testSuite, testName)
|
|
1905
2050
|
if (loggedAttemptToFixTests) {
|
|
1906
|
-
|
|
2051
|
+
const identity = getTestOptimizationIdentity(testSuite, testName)
|
|
2052
|
+
if (loggedAttemptToFixTests.has(identity)) return
|
|
1907
2053
|
|
|
1908
|
-
loggedAttemptToFixTests.add(
|
|
2054
|
+
loggedAttemptToFixTests.add(identity)
|
|
1909
2055
|
}
|
|
1910
2056
|
|
|
1911
2057
|
// eslint-disable-next-line no-console -- Intentional user-facing attempt-to-fix progress report
|
|
1912
|
-
console.warn(`Datadog Test Optimization: attempting to fix ${
|
|
2058
|
+
console.warn(`Datadog Test Optimization: attempting to fix ${formatTestOptimizationDisplayName(testSuite, testName)}`)
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
/**
|
|
2062
|
+
* @typedef {object} TestManagementExecutionResult
|
|
2063
|
+
* @property {string} name
|
|
2064
|
+
* @property {'disabled'|'quarantined'} action
|
|
2065
|
+
* @property {boolean} failed
|
|
2066
|
+
*/
|
|
2067
|
+
|
|
2068
|
+
/**
|
|
2069
|
+
* @typedef {Map<string, TestManagementExecutionResult>} TestManagementExecutions
|
|
2070
|
+
*/
|
|
2071
|
+
|
|
2072
|
+
/**
|
|
2073
|
+
* Records the effective non-Attempt-to-Fix Test Management action for one execution.
|
|
2074
|
+
*
|
|
2075
|
+
* @param {{
|
|
2076
|
+
* testSuite?: string,
|
|
2077
|
+
* testName: string,
|
|
2078
|
+
* status?: string,
|
|
2079
|
+
* isAttemptToFix?: boolean,
|
|
2080
|
+
* isDisabled?: boolean,
|
|
2081
|
+
* isQuarantined?: boolean
|
|
2082
|
+
* }} execution
|
|
2083
|
+
* @param {TestManagementExecutions} [executions]
|
|
2084
|
+
*/
|
|
2085
|
+
function recordTestManagementExecution (execution, executions = testManagementExecutions) {
|
|
2086
|
+
if (!execution?.testName || execution.isAttemptToFix) return
|
|
2087
|
+
|
|
2088
|
+
const action = execution.isDisabled
|
|
2089
|
+
? 'disabled'
|
|
2090
|
+
: execution.isQuarantined ? 'quarantined' : undefined
|
|
2091
|
+
if (!action) return
|
|
2092
|
+
if (action === 'quarantined' && execution.status !== 'pass' && execution.status !== 'fail') return
|
|
2093
|
+
if (getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') === false) return
|
|
2094
|
+
|
|
2095
|
+
const identity = getTestOptimizationIdentity(execution.testSuite, execution.testName)
|
|
2096
|
+
const name = formatTestOptimizationName(execution.testSuite, execution.testName)
|
|
2097
|
+
let result = executions.get(identity)
|
|
2098
|
+
|
|
2099
|
+
if (!result) {
|
|
2100
|
+
result = {
|
|
2101
|
+
name,
|
|
2102
|
+
action,
|
|
2103
|
+
failed: false,
|
|
2104
|
+
}
|
|
2105
|
+
executions.set(identity, result)
|
|
2106
|
+
} else if (action === 'disabled') {
|
|
2107
|
+
result.action = action
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
result.failed ||= execution.status === 'fail'
|
|
1913
2111
|
}
|
|
1914
2112
|
|
|
1915
2113
|
/**
|
|
@@ -1926,10 +2124,12 @@ function logAttemptToFixTestExecution (testSuite, testName, loggedAttemptToFixTe
|
|
|
1926
2124
|
*/
|
|
1927
2125
|
function recordAttemptToFixExecution (attemptToFixExecutions, execution) {
|
|
1928
2126
|
if (!execution?.testName) return
|
|
2127
|
+
if (getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') === false) return
|
|
1929
2128
|
|
|
1930
2129
|
const { testSuite, testName, status, isDisabled, isQuarantined } = execution
|
|
2130
|
+
const identity = getTestOptimizationIdentity(testSuite, testName)
|
|
1931
2131
|
const name = formatTestOptimizationName(testSuite, testName)
|
|
1932
|
-
let result = attemptToFixExecutions.get(
|
|
2132
|
+
let result = attemptToFixExecutions.get(identity)
|
|
1933
2133
|
|
|
1934
2134
|
if (!result) {
|
|
1935
2135
|
result = {
|
|
@@ -1939,7 +2139,7 @@ function recordAttemptToFixExecution (attemptToFixExecutions, execution) {
|
|
|
1939
2139
|
isDisabled: false,
|
|
1940
2140
|
isQuarantined: false,
|
|
1941
2141
|
}
|
|
1942
|
-
attemptToFixExecutions.set(
|
|
2142
|
+
attemptToFixExecutions.set(identity, result)
|
|
1943
2143
|
}
|
|
1944
2144
|
|
|
1945
2145
|
result.executions++
|
|
@@ -1975,6 +2175,27 @@ function collectAttemptToFixExecutionFromTraceSpan (span, attemptToFixExecutions
|
|
|
1975
2175
|
})
|
|
1976
2176
|
}
|
|
1977
2177
|
|
|
2178
|
+
/**
|
|
2179
|
+
* Records a Test Management execution from a serialized worker trace span.
|
|
2180
|
+
*
|
|
2181
|
+
* @param {{ meta?: Record<string, string> }} span
|
|
2182
|
+
* @param {TestManagementExecutions} executions
|
|
2183
|
+
* @returns {void}
|
|
2184
|
+
*/
|
|
2185
|
+
function collectTestManagementExecutionFromTraceSpan (span, executions) {
|
|
2186
|
+
const meta = span.meta
|
|
2187
|
+
if (!meta) return
|
|
2188
|
+
|
|
2189
|
+
recordTestManagementExecution({
|
|
2190
|
+
testSuite: meta[TEST_SUITE],
|
|
2191
|
+
testName: meta[TEST_NAME],
|
|
2192
|
+
status: meta[TEST_STATUS],
|
|
2193
|
+
isAttemptToFix: meta[TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX] === 'true',
|
|
2194
|
+
isDisabled: meta[TEST_MANAGEMENT_IS_DISABLED] === 'true',
|
|
2195
|
+
isQuarantined: meta[TEST_MANAGEMENT_IS_QUARANTINED] === 'true',
|
|
2196
|
+
}, executions)
|
|
2197
|
+
}
|
|
2198
|
+
|
|
1978
2199
|
/**
|
|
1979
2200
|
* Scans serialized worker trace payloads and populates Test Optimization summary data.
|
|
1980
2201
|
* Silently ignores parse errors.
|
|
@@ -1982,11 +2203,16 @@ function collectAttemptToFixExecutionFromTraceSpan (span, attemptToFixExecutions
|
|
|
1982
2203
|
* @param {string} data - JSON-serialized traces from a worker
|
|
1983
2204
|
* @param {{
|
|
1984
2205
|
* newTestsWithDynamicNames?: Set<string>,
|
|
1985
|
-
* attemptToFixExecutions?: AttemptToFixExecutions
|
|
2206
|
+
* attemptToFixExecutions?: AttemptToFixExecutions,
|
|
2207
|
+
* testManagementExecutions?: TestManagementExecutions
|
|
1986
2208
|
* }} summaries
|
|
1987
2209
|
*/
|
|
1988
2210
|
function collectTestOptimizationSummariesFromTraces (data, summaries) {
|
|
1989
|
-
const {
|
|
2211
|
+
const {
|
|
2212
|
+
newTestsWithDynamicNames,
|
|
2213
|
+
attemptToFixExecutions,
|
|
2214
|
+
testManagementExecutions: executions = testManagementExecutions,
|
|
2215
|
+
} = summaries
|
|
1990
2216
|
|
|
1991
2217
|
try {
|
|
1992
2218
|
const traces = JSON.parse(data)
|
|
@@ -1998,6 +2224,7 @@ function collectTestOptimizationSummariesFromTraces (data, summaries) {
|
|
|
1998
2224
|
if (attemptToFixExecutions) {
|
|
1999
2225
|
collectAttemptToFixExecutionFromTraceSpan(span, attemptToFixExecutions)
|
|
2000
2226
|
}
|
|
2227
|
+
collectTestManagementExecutionFromTraceSpan(span, executions)
|
|
2001
2228
|
}
|
|
2002
2229
|
}
|
|
2003
2230
|
} catch {
|
|
@@ -2044,7 +2271,10 @@ function hasAttemptToFixManagementNotes (result) {
|
|
|
2044
2271
|
}
|
|
2045
2272
|
|
|
2046
2273
|
function addAttemptToFixResultLine (lines, result) {
|
|
2047
|
-
lines.push(` • ${
|
|
2274
|
+
lines.push(` • ${truncateTestOptimizationNameMiddle(
|
|
2275
|
+
sanitizeTestOptimizationName(result.name),
|
|
2276
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
2277
|
+
)}`)
|
|
2048
2278
|
|
|
2049
2279
|
for (const note of getAttemptToFixManagementNotes(result)) {
|
|
2050
2280
|
lines.push(` ${note}`)
|
|
@@ -2055,9 +2285,10 @@ function addAttemptToFixResultLine (lines, result) {
|
|
|
2055
2285
|
* Formats the attempt-to-fix end-of-session summary.
|
|
2056
2286
|
*
|
|
2057
2287
|
* @param {AttemptToFixExecutions} attemptToFixExecutions
|
|
2288
|
+
* @param {boolean} [includeTestNames]
|
|
2058
2289
|
* @returns {string}
|
|
2059
2290
|
*/
|
|
2060
|
-
function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
2291
|
+
function formatAttemptToFixSummary (attemptToFixExecutions, includeTestNames = true) {
|
|
2061
2292
|
if (attemptToFixExecutions.size === 0) return ''
|
|
2062
2293
|
|
|
2063
2294
|
const results = [...attemptToFixExecutions.values()]
|
|
@@ -2069,9 +2300,11 @@ function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
|
2069
2300
|
`Attempt to fix passed: all ${totalExecutions} execution(s) passed for ${results.length} test(s).`,
|
|
2070
2301
|
]
|
|
2071
2302
|
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2303
|
+
if (includeTestNames) {
|
|
2304
|
+
for (const result of results) {
|
|
2305
|
+
if (hasAttemptToFixManagementNotes(result)) {
|
|
2306
|
+
addAttemptToFixResultLine(lines, result)
|
|
2307
|
+
}
|
|
2075
2308
|
}
|
|
2076
2309
|
}
|
|
2077
2310
|
|
|
@@ -2087,13 +2320,67 @@ function formatAttemptToFixSummary (attemptToFixExecutions) {
|
|
|
2087
2320
|
`across ${failedResults.length} of ${results.length} test(s).`,
|
|
2088
2321
|
]
|
|
2089
2322
|
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
}
|
|
2093
|
-
for (const result of results) {
|
|
2094
|
-
if (result.failedCount === 0 && hasAttemptToFixManagementNotes(result)) {
|
|
2323
|
+
if (includeTestNames) {
|
|
2324
|
+
for (const result of failedResults) {
|
|
2095
2325
|
addAttemptToFixResultLine(lines, result)
|
|
2096
2326
|
}
|
|
2327
|
+
for (const result of results) {
|
|
2328
|
+
if (result.failedCount === 0 && hasAttemptToFixManagementNotes(result)) {
|
|
2329
|
+
addAttemptToFixResultLine(lines, result)
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
return lines.join('\n')
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
/**
|
|
2338
|
+
* Formats the disabled and quarantined Test Management summary.
|
|
2339
|
+
*
|
|
2340
|
+
* @param {TestManagementExecutions} executions
|
|
2341
|
+
* @param {boolean} [includeTestNames]
|
|
2342
|
+
* @returns {string}
|
|
2343
|
+
*/
|
|
2344
|
+
function formatTestManagementSummary (executions, includeTestNames = true) {
|
|
2345
|
+
if (executions.size === 0) return ''
|
|
2346
|
+
|
|
2347
|
+
const results = [...executions.values()]
|
|
2348
|
+
const disabledResults = results.filter(result => result.action === 'disabled')
|
|
2349
|
+
const quarantinedResults = results.filter(result => result.action === 'quarantined')
|
|
2350
|
+
const failedQuarantinedResults = quarantinedResults.filter(result => result.failed)
|
|
2351
|
+
const lines = ['Test Management']
|
|
2352
|
+
|
|
2353
|
+
if (disabledResults.length > 0) {
|
|
2354
|
+
const testLabel = disabledResults.length === 1 ? 'test' : 'tests'
|
|
2355
|
+
lines.push(` Disabled: ${disabledResults.length} ${testLabel} skipped.`)
|
|
2356
|
+
}
|
|
2357
|
+
if (quarantinedResults.length > 0) {
|
|
2358
|
+
const testLabel = quarantinedResults.length === 1 ? 'test' : 'tests'
|
|
2359
|
+
if (failedQuarantinedResults.length > 0) {
|
|
2360
|
+
const failureLabel = failedQuarantinedResults.length === 1 ? 'failure' : 'failures'
|
|
2361
|
+
lines.push(
|
|
2362
|
+
` Quarantined: ${quarantinedResults.length} ${testLabel} run; ` +
|
|
2363
|
+
`${failedQuarantinedResults.length} ${failureLabel} did not affect the test session.`
|
|
2364
|
+
)
|
|
2365
|
+
} else {
|
|
2366
|
+
lines.push(` Quarantined: ${quarantinedResults.length} ${testLabel} run; all passed.`)
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
if (includeTestNames) {
|
|
2371
|
+
lines.push('', ' Affected tests:')
|
|
2372
|
+
results.sort((a, b) => a.name.localeCompare(b.name))
|
|
2373
|
+
for (const result of results) {
|
|
2374
|
+
const status = result.action === 'disabled'
|
|
2375
|
+
? 'disabled'
|
|
2376
|
+
: result.failed ? 'quarantined, failed' : 'quarantined, passed'
|
|
2377
|
+
lines.push(
|
|
2378
|
+
` • [${status}] ${truncateTestOptimizationNameMiddle(
|
|
2379
|
+
sanitizeTestOptimizationName(result.name),
|
|
2380
|
+
MAX_TEST_OPTIMIZATION_NAME_LENGTH
|
|
2381
|
+
)}`
|
|
2382
|
+
)
|
|
2383
|
+
}
|
|
2097
2384
|
}
|
|
2098
2385
|
|
|
2099
2386
|
return lines.join('\n')
|
|
@@ -2124,25 +2411,57 @@ function formatDynamicNamesSummary (newTestsWithDynamicNames) {
|
|
|
2124
2411
|
*
|
|
2125
2412
|
* @param {{
|
|
2126
2413
|
* attemptToFixExecutions?: AttemptToFixExecutions,
|
|
2414
|
+
* testManagementExecutions?: TestManagementExecutions,
|
|
2127
2415
|
* newTestsWithDynamicNames?: Set<string>,
|
|
2128
2416
|
* extraSections?: string[]
|
|
2129
2417
|
* }} summary
|
|
2130
2418
|
*/
|
|
2131
2419
|
function logTestOptimizationSummary (summary) {
|
|
2132
|
-
const {
|
|
2420
|
+
const {
|
|
2421
|
+
attemptToFixExecutions,
|
|
2422
|
+
testManagementExecutions: executions = testManagementExecutions,
|
|
2423
|
+
newTestsWithDynamicNames,
|
|
2424
|
+
extraSections = [],
|
|
2425
|
+
} = summary
|
|
2133
2426
|
const sections = []
|
|
2134
|
-
const
|
|
2135
|
-
|
|
2427
|
+
const isTestManagementReportEnabled =
|
|
2428
|
+
getValueFromEnvSources('DD_TEST_MANAGEMENT_REPORT_ENABLED') !== false
|
|
2429
|
+
const testManagementTestCount = (attemptToFixExecutions?.size || 0) + executions.size
|
|
2430
|
+
const includeTestNames = testManagementTestCount <= MAX_TEST_MANAGEMENT_REPORT_ITEMS
|
|
2431
|
+
const attemptToFixSummary = isTestManagementReportEnabled && attemptToFixExecutions
|
|
2432
|
+
? formatAttemptToFixSummary(attemptToFixExecutions, includeTestNames)
|
|
2433
|
+
: ''
|
|
2434
|
+
const testManagementSummary = isTestManagementReportEnabled
|
|
2435
|
+
? formatTestManagementSummary(executions, includeTestNames)
|
|
2136
2436
|
: ''
|
|
2137
2437
|
const dynamicNamesSummary = newTestsWithDynamicNames
|
|
2138
2438
|
? formatDynamicNamesSummary(newTestsWithDynamicNames)
|
|
2139
2439
|
: ''
|
|
2140
2440
|
|
|
2141
2441
|
if (attemptToFixSummary) sections.push(attemptToFixSummary)
|
|
2442
|
+
if (testManagementSummary) sections.push(testManagementSummary)
|
|
2443
|
+
if (attemptToFixSummary || testManagementSummary) {
|
|
2444
|
+
if (!includeTestNames) {
|
|
2445
|
+
sections.push(`Individual test names omitted because ${testManagementTestCount} tests were affected.`)
|
|
2446
|
+
}
|
|
2447
|
+
sections.push('Hide this report: DD_TEST_MANAGEMENT_REPORT_ENABLED=false')
|
|
2448
|
+
}
|
|
2142
2449
|
sections.push(...extraSections.filter(Boolean))
|
|
2143
2450
|
if (dynamicNamesSummary) sections.push(dynamicNamesSummary)
|
|
2144
2451
|
|
|
2145
|
-
if (sections.length === 0)
|
|
2452
|
+
if (sections.length === 0) {
|
|
2453
|
+
executions.clear()
|
|
2454
|
+
if (executions !== testManagementExecutions) {
|
|
2455
|
+
testManagementExecutions.clear()
|
|
2456
|
+
}
|
|
2457
|
+
if (attemptToFixExecutions) {
|
|
2458
|
+
attemptToFixExecutions.clear()
|
|
2459
|
+
}
|
|
2460
|
+
if (newTestsWithDynamicNames) {
|
|
2461
|
+
newTestsWithDynamicNames.clear()
|
|
2462
|
+
}
|
|
2463
|
+
return
|
|
2464
|
+
}
|
|
2146
2465
|
|
|
2147
2466
|
const line = '-'.repeat(50)
|
|
2148
2467
|
// eslint-disable-next-line no-console -- Intentional user-facing session summary
|
|
@@ -2151,6 +2470,10 @@ function logTestOptimizationSummary (summary) {
|
|
|
2151
2470
|
if (attemptToFixExecutions) {
|
|
2152
2471
|
attemptToFixExecutions.clear()
|
|
2153
2472
|
}
|
|
2473
|
+
executions.clear()
|
|
2474
|
+
if (executions !== testManagementExecutions) {
|
|
2475
|
+
testManagementExecutions.clear()
|
|
2476
|
+
}
|
|
2154
2477
|
if (newTestsWithDynamicNames) {
|
|
2155
2478
|
newTestsWithDynamicNames.clear()
|
|
2156
2479
|
}
|