dd-trace 6.7.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 +14 -8
- 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/playwright.js +5 -5
- package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
- package/ci/test-optimization-validation/generated-files.js +47 -37
- package/ci/test-optimization-validation/generated-test-contract.js +9 -7
- 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 +301 -52
- 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/offline-output.js +6 -6
- 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 +41 -21
- package/ci/test-optimization-validation/runner-contract.js +79 -43
- package/ci/test-optimization-validation/safe-files.js +4 -4
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
- 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/scenarios/test-management.js +2 -2
- 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 +377 -84
- package/index.d.ts +175 -14
- package/init.js +1 -17
- package/initialize.mjs +11 -0
- package/loader-hook.mjs +6 -4
- package/package.json +12 -4
- package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
- package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-esbuild/src/utils.js +17 -2
- 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 +85 -9
- package/packages/datadog-instrumentations/src/cucumber.js +131 -51
- 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/extract-package-and-module-path.js +10 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -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/rewriter/transforms.js +50 -18
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
- package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -3
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +986 -246
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
- package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
- package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
- package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
- package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
- 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 +176 -81
- package/packages/datadog-instrumentations/src/promise-js.js +4 -4
- package/packages/datadog-instrumentations/src/promise.js +3 -3
- package/packages/datadog-instrumentations/src/rhea.js +1 -1
- package/packages/datadog-instrumentations/src/router.js +195 -19
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
- package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
- 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 +1090 -0
- package/packages/datadog-instrumentations/src/when.js +3 -3
- package/packages/datadog-instrumentations/src/ws.js +5 -1
- package/packages/datadog-plugin-aerospike/src/index.js +1 -3
- package/packages/datadog-plugin-amqplib/src/client.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
- package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
- 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/source-map-utils.js +1 -1
- package/packages/datadog-plugin-cypress/src/support.js +7 -4
- package/packages/datadog-plugin-electron/src/net.js +10 -4
- package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -4
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
- package/packages/datadog-plugin-graphql/src/execute.js +1 -0
- package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +3 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +3 -21
- package/packages/datadog-plugin-jest/src/util.js +4 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-mocha/src/index.js +342 -6
- 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-prisma/src/index.js +5 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-undici/src/index.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +179 -18
- package/packages/datadog-shimmer/src/shimmer.js +6 -2
- package/packages/datadog-webpack/index.js +2 -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/downstream_requests.js +1 -1
- 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/hardcoded-base-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
- package/packages/dd-trace/src/appsec/index.js +48 -476
- package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- 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-validation/sink.js +7 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -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/request.js +3 -3
- 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 +2 -2
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
- package/packages/dd-trace/src/config/defaults.js +14 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
- package/packages/dd-trace/src/config/helper.js +2 -0
- package/packages/dd-trace/src/config/index.js +31 -5
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/remote_config.js +1 -1
- package/packages/dd-trace/src/config/supported-configurations.json +13 -6
- package/packages/dd-trace/src/datastreams/encoding.js +3 -4
- package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -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/encode/tags-processors.js +2 -2
- package/packages/dd-trace/src/exporters/common/url.js +3 -5
- package/packages/dd-trace/src/exporters/electron/index.js +4 -1
- package/packages/dd-trace/src/external-logger/src/index.js +1 -2
- package/packages/dd-trace/src/flare/index.js +2 -2
- 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/id.js +1 -1
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
- package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
- package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
- package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
- package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
- package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
- 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/anthropic/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
- package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +152 -78
- package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
- package/packages/dd-trace/src/llmobs/tagger.js +1 -2
- 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/spans.js +12 -6
- 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/noop/proxy.js +2 -2
- 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/otlp_transformer.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
- package/packages/dd-trace/src/opentelemetry/span.js +4 -0
- package/packages/dd-trace/src/opentracing/span.js +1 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -6
- package/packages/dd-trace/src/plugins/util/git.js +7 -5
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
- package/packages/dd-trace/src/plugins/util/llm.js +2 -2
- package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/test.js +356 -86
- package/packages/dd-trace/src/plugins/util/url.js +5 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
- package/packages/dd-trace/src/plugins/util/web.js +24 -2
- package/packages/dd-trace/src/priority_sampler.js +6 -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/profiling/profilers/poisson.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
- package/packages/dd-trace/src/proxy.js +1 -0
- package/packages/dd-trace/src/ritm.js +10 -20
- 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/startup-log.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
- package/packages/dd-trace/src/util.js +16 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/version.js +10 -8
- /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
|
@@ -41,11 +41,9 @@ addHook({
|
|
|
41
41
|
}, (Suite) => {
|
|
42
42
|
shimmer.wrap(Suite.prototype, 'addTest', addTest => function (test) {
|
|
43
43
|
const callSites = getCallSites()
|
|
44
|
-
let startLine
|
|
45
44
|
const testCallSite = callSites.find(site => site.getFileName() === test.file)
|
|
46
45
|
if (testCallSite) {
|
|
47
|
-
|
|
48
|
-
testToStartLine.set(test, startLine)
|
|
46
|
+
testToStartLine.set(test, testCallSite.getLineNumber())
|
|
49
47
|
}
|
|
50
48
|
return addTest.apply(this, arguments)
|
|
51
49
|
})
|
|
@@ -11,11 +11,13 @@ const {
|
|
|
11
11
|
const { addHook, channel } = require('../helpers/instrument')
|
|
12
12
|
const shimmer = require('../../../datadog-shimmer')
|
|
13
13
|
const { isMarkedAsUnskippable } = require('../../../datadog-plugin-jest/src/util')
|
|
14
|
+
const { EMPTY_EFD_RETRY_POLICY } = require('../../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
14
15
|
const { writeCoverageBackfillToCache } = require('../../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
15
16
|
const log = require('../../../dd-trace/src/log')
|
|
16
17
|
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
17
18
|
const {
|
|
18
19
|
getTestSuitePath,
|
|
20
|
+
MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE,
|
|
19
21
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
20
22
|
fromCoverageMapToCoverage,
|
|
21
23
|
getCoveredFilesFromCoverage,
|
|
@@ -28,6 +30,7 @@ const {
|
|
|
28
30
|
getTestCoverageLinesPercentage,
|
|
29
31
|
collectTestOptimizationSummariesFromTraces,
|
|
30
32
|
logTestOptimizationSummary,
|
|
33
|
+
TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE,
|
|
31
34
|
getTestOptimizationRequestResults,
|
|
32
35
|
isModifiedTest,
|
|
33
36
|
} = require('../../../dd-trace/src/plugins/util/test')
|
|
@@ -53,6 +56,7 @@ const {
|
|
|
53
56
|
newTestsWithDynamicNames,
|
|
54
57
|
attemptToFixExecutions,
|
|
55
58
|
loggedAttemptToFixTests,
|
|
59
|
+
adjustRunnerFailuresForTestOptimization,
|
|
56
60
|
} = require('./utils')
|
|
57
61
|
|
|
58
62
|
require('./common')
|
|
@@ -65,12 +69,15 @@ let hasWarnedDeprecatedMochaVersion = false
|
|
|
65
69
|
const unskippableSuites = []
|
|
66
70
|
let suitesToSkip = []
|
|
67
71
|
let isSuitesSkipped = false
|
|
72
|
+
let areAllSuitesSkipped = false
|
|
68
73
|
let skippedSuites = []
|
|
69
74
|
let skippableSuitesCoverage = {}
|
|
70
75
|
let skippedSuitesCoverage = {}
|
|
71
76
|
let itrCorrelationId = ''
|
|
72
77
|
let isForcedToRun = false
|
|
73
|
-
const config = {
|
|
78
|
+
const config = {
|
|
79
|
+
earlyFlakeDetectionRetryPolicy: EMPTY_EFD_RETRY_POLICY,
|
|
80
|
+
}
|
|
74
81
|
|
|
75
82
|
// We'll preserve the original coverage here
|
|
76
83
|
const originalCoverageMap = createCoverageMap()
|
|
@@ -94,6 +101,7 @@ const mochaGlobalRunCh = channel('ci:mocha:global:run')
|
|
|
94
101
|
const testManagementTestsCh = channel('ci:mocha:test-management-tests')
|
|
95
102
|
const modifiedFilesCh = channel('ci:mocha:modified-files')
|
|
96
103
|
const workerReportTraceCh = channel('ci:mocha:worker-report:trace')
|
|
104
|
+
const workerReportTelemetryCh = channel('ci:mocha:worker-report:telemetry')
|
|
97
105
|
const testSessionStartCh = channel('ci:mocha:session:start')
|
|
98
106
|
const testSessionFinishCh = channel('ci:mocha:session:finish')
|
|
99
107
|
const itrSkippedSuitesCh = channel('ci:mocha:itr:skipped-suites')
|
|
@@ -114,17 +122,6 @@ function warnDeprecatedMochaVersion (frameworkVersion) {
|
|
|
114
122
|
)
|
|
115
123
|
}
|
|
116
124
|
|
|
117
|
-
// Tests from workers do not come with `isFailed` method
|
|
118
|
-
function isTestFailed (test) {
|
|
119
|
-
if (test.isFailed) {
|
|
120
|
-
return test.isFailed()
|
|
121
|
-
}
|
|
122
|
-
if (test.isPending) {
|
|
123
|
-
return !test.isPending() && test.state === 'failed'
|
|
124
|
-
}
|
|
125
|
-
return false
|
|
126
|
-
}
|
|
127
|
-
|
|
128
125
|
function getRootSuiteStatus (rootTests) {
|
|
129
126
|
let status = 'pass'
|
|
130
127
|
if (rootTests.every(t => t.isPending())) {
|
|
@@ -237,6 +234,7 @@ function getMochaTestSessionCoverageFiles () {
|
|
|
237
234
|
|
|
238
235
|
function resetSuiteSkippingRunState () {
|
|
239
236
|
isSuitesSkipped = false
|
|
237
|
+
areAllSuitesSkipped = false
|
|
240
238
|
skippedSuites = []
|
|
241
239
|
skippableSuitesCoverage = {}
|
|
242
240
|
skippedSuitesCoverage = {}
|
|
@@ -309,37 +307,7 @@ function getOnEndHandler (isParallel, onDone) {
|
|
|
309
307
|
status = 'fail'
|
|
310
308
|
}
|
|
311
309
|
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* If Early Flake Detection (EFD) is enabled the logic is as follows:
|
|
315
|
-
* - If all attempts for a test are failing, the test has failed and we will let the test process fail.
|
|
316
|
-
* - If just a single attempt passes, we will prevent the test process from failing.
|
|
317
|
-
* The rationale behind is the following: you may still be able to block your CI pipeline by gating
|
|
318
|
-
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
319
|
-
*/
|
|
320
|
-
for (const tests of Object.values(efdTests)) {
|
|
321
|
-
const failingEfdTests = tests.filter(test => isTestFailed(test))
|
|
322
|
-
const areAllEfdTestsFailing = failingEfdTests.length === tests.length
|
|
323
|
-
const nonQuarantinedFailingEfdTests = failingEfdTests.filter(test => !testsQuarantined.has(test))
|
|
324
|
-
if (nonQuarantinedFailingEfdTests.length && !areAllEfdTestsFailing) {
|
|
325
|
-
this.stats.failures -= nonQuarantinedFailingEfdTests.length
|
|
326
|
-
this.failures -= nonQuarantinedFailingEfdTests.length
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// We subtract the errors from quarantined tests from the total number of failures.
|
|
332
|
-
// Attempt-to-fix tests ignore quarantine/disabled suppression and keep their framework result.
|
|
333
|
-
if (config.isTestManagementTestsEnabled) {
|
|
334
|
-
let numFailedQuarantinedTests = 0
|
|
335
|
-
for (const test of testsQuarantined) {
|
|
336
|
-
if (isTestFailed(test)) {
|
|
337
|
-
numFailedQuarantinedTests++
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
this.stats.failures -= numFailedQuarantinedTests
|
|
341
|
-
this.failures -= numFailedQuarantinedTests
|
|
342
|
-
}
|
|
310
|
+
adjustRunnerFailuresForTestOptimization(this, config)
|
|
343
311
|
|
|
344
312
|
// Recompute status after EFD and quarantine adjustments have reduced failure counts
|
|
345
313
|
if (status === 'fail') {
|
|
@@ -397,7 +365,11 @@ function getOnEndHandler (isParallel, onDone) {
|
|
|
397
365
|
isParallel,
|
|
398
366
|
}, onDone)
|
|
399
367
|
|
|
400
|
-
logTestOptimizationSummary({
|
|
368
|
+
logTestOptimizationSummary({
|
|
369
|
+
attemptToFixExecutions,
|
|
370
|
+
newTestsWithDynamicNames,
|
|
371
|
+
extraSections: areAllSuitesSkipped ? [TEST_IMPACT_ANALYSIS_ALL_TESTS_SKIPPED_MESSAGE] : [],
|
|
372
|
+
})
|
|
401
373
|
loggedAttemptToFixTests.clear()
|
|
402
374
|
}
|
|
403
375
|
}
|
|
@@ -426,6 +398,57 @@ function isFailedTestReplayEnabled () {
|
|
|
426
398
|
return config.isTestDynamicInstrumentationEnabled && config.isDiEnabled
|
|
427
399
|
}
|
|
428
400
|
|
|
401
|
+
/**
|
|
402
|
+
* @typedef {object} MochaSuite
|
|
403
|
+
* @property {MochaSuite[]} suites
|
|
404
|
+
* @property {import('mocha').Test[]} tests
|
|
405
|
+
* @property {MochaSuite[]} _onlySuites
|
|
406
|
+
* @property {import('mocha').Test[]} _onlyTests
|
|
407
|
+
*/
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Mirrors Mocha 5's private exclusivity check.
|
|
411
|
+
*
|
|
412
|
+
* @param {MochaSuite} suite
|
|
413
|
+
* @returns {boolean}
|
|
414
|
+
*/
|
|
415
|
+
function hasOnly (suite) {
|
|
416
|
+
if (suite._onlyTests.length || suite._onlySuites.length) return true
|
|
417
|
+
|
|
418
|
+
for (const childSuite of suite.suites) {
|
|
419
|
+
if (hasOnly(childSuite)) return true
|
|
420
|
+
}
|
|
421
|
+
return false
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Mirrors Mocha 5's private exclusivity filter.
|
|
426
|
+
*
|
|
427
|
+
* @param {MochaSuite} suite
|
|
428
|
+
* @returns {boolean}
|
|
429
|
+
*/
|
|
430
|
+
function filterOnly (suite) {
|
|
431
|
+
if (suite._onlyTests.length) {
|
|
432
|
+
suite.tests = suite._onlyTests
|
|
433
|
+
suite.suites = []
|
|
434
|
+
} else {
|
|
435
|
+
suite.tests = []
|
|
436
|
+
|
|
437
|
+
for (const onlySuite of suite._onlySuites) {
|
|
438
|
+
if (hasOnly(onlySuite)) filterOnly(onlySuite)
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const filteredSuites = []
|
|
442
|
+
for (const childSuite of suite.suites) {
|
|
443
|
+
if (suite._onlySuites.includes(childSuite) || filterOnly(childSuite)) {
|
|
444
|
+
filteredSuites.push(childSuite)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
suite.suites = filteredSuites
|
|
448
|
+
}
|
|
449
|
+
return suite.tests.length > 0 || suite.suites.length > 0
|
|
450
|
+
}
|
|
451
|
+
|
|
429
452
|
function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest, localSuites) {
|
|
430
453
|
const ctx = {
|
|
431
454
|
isParallel,
|
|
@@ -458,6 +481,13 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
458
481
|
}
|
|
459
482
|
|
|
460
483
|
// We remove the suites that we skip through ITR
|
|
484
|
+
// Mocha normally applies exclusivity after this asynchronous configuration step.
|
|
485
|
+
if (typeof runner.suite.hasOnly === 'function') {
|
|
486
|
+
if (runner.suite.hasOnly()) runner.suite.filterOnly()
|
|
487
|
+
} else if (hasOnly(runner.suite)) {
|
|
488
|
+
filterOnly(runner.suite)
|
|
489
|
+
}
|
|
490
|
+
const numTestsToRun = runner.grepTotal(runner.suite)
|
|
461
491
|
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
462
492
|
const { suitesToRun, suitesToSkipForRun } = filteredSuites
|
|
463
493
|
|
|
@@ -466,6 +496,7 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
466
496
|
log.debug('%d out of %d suites are going to run.', suitesToRun.length, runner.suite.suites.length)
|
|
467
497
|
|
|
468
498
|
runner.suite.suites = suitesToRun
|
|
499
|
+
areAllSuitesSkipped = isSuitesSkipped && numTestsToRun > 0 && runner.grepTotal(runner.suite) === 0
|
|
469
500
|
|
|
470
501
|
skippedSuites = [...filteredSuites.skippedSuites]
|
|
471
502
|
suitesToSkip = suitesToSkipForRun
|
|
@@ -529,8 +560,8 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
529
560
|
}
|
|
530
561
|
config.repositoryRoot = repositoryRoot
|
|
531
562
|
config.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
532
|
-
config.
|
|
533
|
-
|
|
563
|
+
config.earlyFlakeDetectionRetryPolicy =
|
|
564
|
+
libraryConfig.earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
|
|
534
565
|
config.earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
535
566
|
config.isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
536
567
|
config.isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
@@ -1018,6 +1049,8 @@ function onMessage (message) {
|
|
|
1018
1049
|
attemptToFixExecutions,
|
|
1019
1050
|
})
|
|
1020
1051
|
workerReportTraceCh.publish(payload)
|
|
1052
|
+
} else if (messageCode === MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE) {
|
|
1053
|
+
workerReportTelemetryCh.publish(payload)
|
|
1021
1054
|
}
|
|
1022
1055
|
}
|
|
1023
1056
|
}
|
|
@@ -1082,7 +1115,7 @@ addHook({
|
|
|
1082
1115
|
versions: ['>=8.0.0'],
|
|
1083
1116
|
file: 'lib/nodejs/parallel-buffered-runner.js',
|
|
1084
1117
|
}, (ParallelBufferedRunner, frameworkVersion) => {
|
|
1085
|
-
shimmer.wrap(ParallelBufferedRunner.prototype, 'run', run => function (cb, { files }) {
|
|
1118
|
+
shimmer.wrap(ParallelBufferedRunner.prototype, 'run', run => function (cb, { files, options = {} }) {
|
|
1086
1119
|
if (!testFinishCh.hasSubscribers) {
|
|
1087
1120
|
return run.apply(this, arguments)
|
|
1088
1121
|
}
|
|
@@ -1128,10 +1161,11 @@ addHook({
|
|
|
1128
1161
|
}
|
|
1129
1162
|
}
|
|
1130
1163
|
isSuitesSkipped = skippedFiles.length > 0
|
|
1164
|
+
areAllSuitesSkipped = options.grep === undefined && files.length > 0 && filteredFiles.length === 0
|
|
1131
1165
|
skippedSuites = skippedFiles
|
|
1132
1166
|
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
1133
1167
|
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
1134
|
-
run.apply(this, [onRunDone, { files: filteredFiles }])
|
|
1168
|
+
run.apply(this, [onRunDone, { files: filteredFiles, options }])
|
|
1135
1169
|
} else {
|
|
1136
1170
|
run.apply(this, arguments)
|
|
1137
1171
|
}
|
|
@@ -1150,9 +1184,34 @@ addHook({
|
|
|
1150
1184
|
name: 'mocha',
|
|
1151
1185
|
versions: ['>=8.0.0'],
|
|
1152
1186
|
file: 'lib/nodejs/buffered-worker-pool.js',
|
|
1153
|
-
}, (BufferedWorkerPoolPackage) => {
|
|
1187
|
+
}, (BufferedWorkerPoolPackage, frameworkVersion) => {
|
|
1154
1188
|
const { BufferedWorkerPool } = BufferedWorkerPoolPackage
|
|
1155
1189
|
|
|
1190
|
+
if (satisfies(frameworkVersion, '<9.2.0')) {
|
|
1191
|
+
// Shimmer is required because the worker environment must be changed before workerpool forks,
|
|
1192
|
+
// before any test lifecycle hook can run. Mocha added this worker ID itself in 9.2.0.
|
|
1193
|
+
shimmer.wrap(BufferedWorkerPool, 'create', create => function () {
|
|
1194
|
+
const pool = create.apply(this, arguments)
|
|
1195
|
+
|
|
1196
|
+
if (!testFinishCh.hasSubscribers) return pool
|
|
1197
|
+
|
|
1198
|
+
let workerId = 0
|
|
1199
|
+
shimmer.wrap(pool._pool, '_createWorkerHandler', createWorkerHandler => function () {
|
|
1200
|
+
this.forkOpts = {
|
|
1201
|
+
...this.forkOpts,
|
|
1202
|
+
env: {
|
|
1203
|
+
// eslint-disable-next-line eslint-rules/eslint-process-env
|
|
1204
|
+
...(this.forkOpts.env || process.env),
|
|
1205
|
+
MOCHA_WORKER_ID: String(workerId++),
|
|
1206
|
+
},
|
|
1207
|
+
}
|
|
1208
|
+
return createWorkerHandler.apply(this, arguments)
|
|
1209
|
+
})
|
|
1210
|
+
|
|
1211
|
+
return pool
|
|
1212
|
+
})
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1156
1215
|
shimmer.wrap(BufferedWorkerPool.prototype, 'run', run => async function (testSuiteAbsolutePath, workerArgs) {
|
|
1157
1216
|
if (!testFinishCh.hasSubscribers ||
|
|
1158
1217
|
(!config.isKnownTestsEnabled &&
|
|
@@ -1170,8 +1229,7 @@ addHook({
|
|
|
1170
1229
|
if (config.isKnownTestsEnabled) {
|
|
1171
1230
|
if (config.knownTests?.mocha) {
|
|
1172
1231
|
const testSuiteKnownTests = config.knownTests.mocha[testPath] || []
|
|
1173
|
-
newWorkerArgs.
|
|
1174
|
-
newWorkerArgs._ddEfdSlowTestRetries = config.earlyFlakeDetectionSlowTestRetries
|
|
1232
|
+
newWorkerArgs._ddEfdRetryPolicy = config.earlyFlakeDetectionRetryPolicy
|
|
1175
1233
|
newWorkerArgs._ddIsEfdEnabled = config.isEarlyFlakeDetectionEnabled
|
|
1176
1234
|
newWorkerArgs._ddIsKnownTestsEnabled = true
|
|
1177
1235
|
newWorkerArgs._ddKnownTests = {
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const { performance } = require('node:perf_hooks')
|
|
4
4
|
|
|
5
|
+
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
6
|
+
const {
|
|
7
|
+
getEfdRetryCountForDuration,
|
|
8
|
+
hasEfdRetries,
|
|
9
|
+
shouldSkipEfdRetry,
|
|
10
|
+
} = require('../../../dd-trace/src/ci-visibility/efd-retry-policy')
|
|
5
11
|
const {
|
|
6
12
|
getTestSuitePath,
|
|
7
13
|
DYNAMIC_NAME_RE,
|
|
8
|
-
|
|
9
|
-
getMaxEfdRetryCount,
|
|
14
|
+
recordTestManagementExecution,
|
|
10
15
|
recordAttemptToFixExecution,
|
|
11
16
|
logAttemptToFixTestExecution,
|
|
12
17
|
} = require('../../../dd-trace/src/plugins/util/test')
|
|
@@ -26,6 +31,8 @@ const isModifiedCh = channel('ci:mocha:test:is-modified')
|
|
|
26
31
|
// suite channels
|
|
27
32
|
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
28
33
|
|
|
34
|
+
/** @typedef {{ length: number, [index: number]: unknown } & Iterable<unknown>} ArgumentsLike */
|
|
35
|
+
|
|
29
36
|
const testToContext = new WeakMap()
|
|
30
37
|
const originalFns = new WeakMap()
|
|
31
38
|
const testToStartLine = new WeakMap()
|
|
@@ -40,6 +47,7 @@ const testsStatuses = new Map()
|
|
|
40
47
|
const efdRetryCountByTestFullName = new Map()
|
|
41
48
|
const efdSlowAbortedTests = new Set()
|
|
42
49
|
const attemptToFixExecutions = new Map()
|
|
50
|
+
const isMochaWorker = !!getEnvironmentVariable('MOCHA_WORKER_ID')
|
|
43
51
|
|
|
44
52
|
function waitForHitProbe () {
|
|
45
53
|
const promises = {}
|
|
@@ -48,6 +56,59 @@ function waitForHitProbe () {
|
|
|
48
56
|
}
|
|
49
57
|
const loggedAttemptToFixTests = new Set()
|
|
50
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Checks whether a Mocha test failed, including serialized tests from parallel workers.
|
|
61
|
+
*
|
|
62
|
+
* @param {object} test
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
function isTestFailed (test) {
|
|
66
|
+
if (test.isFailed) {
|
|
67
|
+
return test.isFailed()
|
|
68
|
+
}
|
|
69
|
+
if (test.isPending) {
|
|
70
|
+
return !test.isPending() && test.state === 'failed'
|
|
71
|
+
}
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Applies EFD and quarantine failure suppression to a completed Mocha runner.
|
|
77
|
+
*
|
|
78
|
+
* @param {object} runner
|
|
79
|
+
* @param {object} config
|
|
80
|
+
* @returns {void}
|
|
81
|
+
*/
|
|
82
|
+
function adjustRunnerFailuresForTestOptimization (runner, config) {
|
|
83
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
84
|
+
for (const tests of Object.values(efdTests)) {
|
|
85
|
+
const executedEfdTests = tests.filter(test => !test.isPending())
|
|
86
|
+
const failingEfdTests = tests.filter(test => isTestFailed(test))
|
|
87
|
+
const areAllEfdTestsFailing = failingEfdTests.length === executedEfdTests.length
|
|
88
|
+
const nonQuarantinedFailingEfdTests = failingEfdTests.filter(test => !testsQuarantined.has(test))
|
|
89
|
+
if (nonQuarantinedFailingEfdTests.length && !areAllEfdTestsFailing) {
|
|
90
|
+
if (runner.stats) {
|
|
91
|
+
runner.stats.failures -= nonQuarantinedFailingEfdTests.length
|
|
92
|
+
}
|
|
93
|
+
runner.failures -= nonQuarantinedFailingEfdTests.length
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (config.isTestManagementTestsEnabled) {
|
|
99
|
+
let numFailedQuarantinedTests = 0
|
|
100
|
+
for (const test of testsQuarantined) {
|
|
101
|
+
if (isTestFailed(test)) {
|
|
102
|
+
numFailedQuarantinedTests++
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (runner.stats) {
|
|
106
|
+
runner.stats.failures -= numFailedQuarantinedTests
|
|
107
|
+
}
|
|
108
|
+
runner.failures -= numFailedQuarantinedTests
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
51
112
|
function getAfterEachHooks (testOrHook) {
|
|
52
113
|
const hooks = []
|
|
53
114
|
|
|
@@ -80,19 +141,28 @@ function isNewTest (test, knownTests) {
|
|
|
80
141
|
return !testsForSuite.includes(testName)
|
|
81
142
|
}
|
|
82
143
|
|
|
83
|
-
|
|
144
|
+
/**
|
|
145
|
+
* @param {import('mocha').Test} test
|
|
146
|
+
* @param {number} duration
|
|
147
|
+
* @param {import('../../../dd-trace/src/ci-visibility/efd-retry-policy').EfdRetryPolicy} retryPolicy
|
|
148
|
+
*/
|
|
149
|
+
function setEfdRetryCountForTest (test, duration, retryPolicy) {
|
|
84
150
|
const testName = getTestFullName(test)
|
|
85
151
|
if (efdRetryCountByTestFullName.has(testName)) {
|
|
86
152
|
return
|
|
87
153
|
}
|
|
88
|
-
const retryCount =
|
|
154
|
+
const retryCount = getEfdRetryCountForDuration(duration, retryPolicy)
|
|
89
155
|
efdRetryCountByTestFullName.set(testName, retryCount)
|
|
90
156
|
if (retryCount === 0) {
|
|
91
157
|
efdSlowAbortedTests.add(testName)
|
|
92
158
|
}
|
|
93
159
|
}
|
|
94
160
|
|
|
95
|
-
|
|
161
|
+
/**
|
|
162
|
+
* @param {import('mocha').Test} test
|
|
163
|
+
* @param {import('../../../dd-trace/src/ci-visibility/efd-retry-policy').EfdRetryPolicy} retryPolicy
|
|
164
|
+
*/
|
|
165
|
+
function wrapOriginalEfdTest (test, retryPolicy) {
|
|
96
166
|
if (test._ddEfdDurationWrapped || typeof test.fn !== 'function') {
|
|
97
167
|
return
|
|
98
168
|
}
|
|
@@ -101,7 +171,7 @@ function wrapOriginalEfdTest (test, slowTestRetries) {
|
|
|
101
171
|
test.fn = shimmer.wrapFunction(originalFn, originalFn => function () {
|
|
102
172
|
const start = performance.now()
|
|
103
173
|
const recordDuration = () => {
|
|
104
|
-
setEfdRetryCountForTest(test, performance.now() - start,
|
|
174
|
+
setEfdRetryCountForTest(test, performance.now() - start, retryPolicy)
|
|
105
175
|
}
|
|
106
176
|
|
|
107
177
|
if (originalFn.length > 0) {
|
|
@@ -152,38 +222,51 @@ function disableMochaRetries (test) {
|
|
|
152
222
|
* _ddIsModified?: boolean,
|
|
153
223
|
* _ddIsNew?: boolean
|
|
154
224
|
* }} test
|
|
155
|
-
* @param {{
|
|
225
|
+
* @param {{
|
|
226
|
+
* isEarlyFlakeDetectionEnabled?: boolean,
|
|
227
|
+
* earlyFlakeDetectionRetryPolicy?: import('../../../dd-trace/src/ci-visibility/efd-retry-policy').EfdRetryPolicy
|
|
228
|
+
* }} config
|
|
156
229
|
* @returns {boolean}
|
|
157
230
|
*/
|
|
158
231
|
function isDatadogManagedRetryTest (test, config) {
|
|
159
|
-
return test._ddIsAttemptToFix ||
|
|
160
|
-
test._ddIsEfdRetry ||
|
|
161
|
-
(config.isEarlyFlakeDetectionEnabled && (test._ddIsNew || test._ddIsModified))
|
|
232
|
+
return test._ddIsAttemptToFix || isEarlyFlakeDetectionTest(test, config)
|
|
162
233
|
}
|
|
163
234
|
|
|
164
235
|
/**
|
|
165
236
|
* Checks whether a runnable belongs to an Early Flake Detection execution.
|
|
166
237
|
* @param {{
|
|
167
238
|
* _ddIsAttemptToFix?: boolean,
|
|
239
|
+
* _ddIsDisabled?: boolean,
|
|
168
240
|
* _ddIsEfdRetry?: boolean,
|
|
169
241
|
* _ddIsModified?: boolean,
|
|
170
242
|
* _ddIsNew?: boolean
|
|
171
243
|
* }} test
|
|
172
|
-
* @param {{
|
|
244
|
+
* @param {{
|
|
245
|
+
* isEarlyFlakeDetectionEnabled?: boolean,
|
|
246
|
+
* earlyFlakeDetectionRetryPolicy?: import('../../../dd-trace/src/ci-visibility/efd-retry-policy').EfdRetryPolicy
|
|
247
|
+
* }} config
|
|
173
248
|
* @returns {boolean}
|
|
174
249
|
*/
|
|
175
250
|
function isEarlyFlakeDetectionTest (test, config) {
|
|
176
251
|
return !test._ddIsAttemptToFix &&
|
|
252
|
+
!test._ddIsDisabled &&
|
|
177
253
|
config.isEarlyFlakeDetectionEnabled &&
|
|
254
|
+
hasEfdRetries(config.earlyFlakeDetectionRetryPolicy) &&
|
|
178
255
|
(test._ddIsEfdRetry || test._ddIsNew || test._ddIsModified)
|
|
179
256
|
}
|
|
180
257
|
|
|
181
|
-
|
|
258
|
+
/**
|
|
259
|
+
* @param {import('mocha').Test} test
|
|
260
|
+
* @param {number} numRetries
|
|
261
|
+
* @param {string[]} tags
|
|
262
|
+
* @param {import('../../../dd-trace/src/ci-visibility/efd-retry-policy').EfdRetryPolicy} retryPolicy
|
|
263
|
+
*/
|
|
264
|
+
function retryTest (test, numRetries, tags, retryPolicy) {
|
|
182
265
|
const suite = test.parent
|
|
183
266
|
const isEfdRetry = tags.includes('_ddIsEfdRetry')
|
|
184
267
|
disableMochaRetries(test)
|
|
185
268
|
if (isEfdRetry) {
|
|
186
|
-
wrapOriginalEfdTest(test,
|
|
269
|
+
wrapOriginalEfdTest(test, retryPolicy)
|
|
187
270
|
}
|
|
188
271
|
for (let retryIndex = 0; retryIndex < numRetries; retryIndex++) {
|
|
189
272
|
const clonedTest = test.clone()
|
|
@@ -195,7 +278,7 @@ function retryTest (test, numRetries, tags, slowTestRetries) {
|
|
|
195
278
|
if (typeof originalFn === 'function') {
|
|
196
279
|
clonedTest.fn = shimmer.wrapFunction(originalFn, originalFn => function (...args) {
|
|
197
280
|
const efdRetryCount = efdRetryCountByTestFullName.get(getTestFullName(clonedTest))
|
|
198
|
-
if (
|
|
281
|
+
if (shouldSkipEfdRetry(clonedTest._ddEfdRetryIndex, efdRetryCount)) {
|
|
199
282
|
clonedTest._ddShouldSkipEfdRetry = true
|
|
200
283
|
this.skip()
|
|
201
284
|
}
|
|
@@ -211,14 +294,6 @@ function retryTest (test, numRetries, tags, slowTestRetries) {
|
|
|
211
294
|
}
|
|
212
295
|
}
|
|
213
296
|
|
|
214
|
-
function getConfiguredEfdRetryCount (config) {
|
|
215
|
-
const { earlyFlakeDetectionSlowTestRetries } = config
|
|
216
|
-
if (!earlyFlakeDetectionSlowTestRetries || !Object.keys(earlyFlakeDetectionSlowTestRetries).length) {
|
|
217
|
-
return config.earlyFlakeDetectionNumRetries
|
|
218
|
-
}
|
|
219
|
-
return getMaxEfdRetryCount(earlyFlakeDetectionSlowTestRetries)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
297
|
function getSuitesByTestFile (root) {
|
|
223
298
|
const suitesByTestFile = {}
|
|
224
299
|
function getSuites (suite) {
|
|
@@ -407,7 +482,7 @@ function getOnTestHandler (isMain) {
|
|
|
407
482
|
|
|
408
483
|
if (isEfdRetry) {
|
|
409
484
|
const efdRetryCount = efdRetryCountByTestFullName.get(getTestFullName(test))
|
|
410
|
-
if (
|
|
485
|
+
if (shouldSkipEfdRetry(test._ddEfdRetryIndex, efdRetryCount)) {
|
|
411
486
|
test.pending = true
|
|
412
487
|
test._ddShouldSkipEfdRetry = true
|
|
413
488
|
return
|
|
@@ -521,7 +596,7 @@ function getTestFinishInfo (test, status, config, error) {
|
|
|
521
596
|
!efdRetryCountByTestFullName.has(testName)
|
|
522
597
|
) {
|
|
523
598
|
const duration = test.duration > 0 ? test.duration : performance.now() - test._ddStartTime
|
|
524
|
-
setEfdRetryCountForTest(test, duration, config.
|
|
599
|
+
setEfdRetryCountForTest(test, duration, config.earlyFlakeDetectionRetryPolicy)
|
|
525
600
|
}
|
|
526
601
|
|
|
527
602
|
if (testsStatuses.get(testName)) {
|
|
@@ -532,7 +607,8 @@ function getTestFinishInfo (test, status, config, error) {
|
|
|
532
607
|
const testStatuses = testsStatuses.get(testName)
|
|
533
608
|
|
|
534
609
|
const isLastAttempt = testStatuses.length === config.testManagementAttemptToFixRetries + 1
|
|
535
|
-
const efdRetryCount = efdRetryCountByTestFullName.get(testName) ??
|
|
610
|
+
const efdRetryCount = efdRetryCountByTestFullName.get(testName) ??
|
|
611
|
+
config.earlyFlakeDetectionRetryPolicy.schedulingRetryCount
|
|
536
612
|
const isLastEfdRetry = testStatuses.length === efdRetryCount + 1
|
|
537
613
|
const isLastAtrAttempt = getIsLastRetry(test) || (config.isFlakyTestRetriesEnabled && status === 'pass')
|
|
538
614
|
|
|
@@ -587,6 +663,17 @@ function getTestFinishInfo (test, status, config, error) {
|
|
|
587
663
|
isFinalAttempt,
|
|
588
664
|
})
|
|
589
665
|
|
|
666
|
+
if (!isMochaWorker) {
|
|
667
|
+
recordTestManagementExecution({
|
|
668
|
+
testSuite: getTestSuitePath(test.file, process.cwd()),
|
|
669
|
+
testName: test.fullTitle(),
|
|
670
|
+
status,
|
|
671
|
+
isAttemptToFix: _ddIsAttemptToFix,
|
|
672
|
+
isDisabled: _ddIsDisabled,
|
|
673
|
+
isQuarantined: _ddIsQuarantined,
|
|
674
|
+
})
|
|
675
|
+
}
|
|
676
|
+
|
|
590
677
|
if (_ddIsAttemptToFix) {
|
|
591
678
|
recordAttemptToFixExecution(attemptToFixExecutions, {
|
|
592
679
|
testSuite: getTestSuitePath(test.file, process.cwd()),
|
|
@@ -733,7 +820,7 @@ function finishDeferredHookEnd (test) {
|
|
|
733
820
|
* @param {object} test - Mocha test currently owning the hook.
|
|
734
821
|
* @param {Promise<void>|undefined} failedTestReplayPromise - Pending Failed Test Replay wait, if any.
|
|
735
822
|
* @param {unknown} hookThis - Callback receiver.
|
|
736
|
-
* @param {
|
|
823
|
+
* @param {ArgumentsLike} args - Arguments passed by Mocha.
|
|
737
824
|
* @returns {unknown}
|
|
738
825
|
*/
|
|
739
826
|
function runFailedTestReplayHookUpCallback (fn, test, failedTestReplayPromise, hookThis, args) {
|
|
@@ -949,12 +1036,12 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
949
1036
|
onDone: (isModified) => {
|
|
950
1037
|
if (isModified) {
|
|
951
1038
|
test._ddIsModified = true
|
|
952
|
-
if (!test.isPending() &&
|
|
1039
|
+
if (!test.isPending() && isEarlyFlakeDetectionTest(test, config)) {
|
|
953
1040
|
retryTest(
|
|
954
1041
|
test,
|
|
955
|
-
|
|
1042
|
+
config.earlyFlakeDetectionRetryPolicy.schedulingRetryCount,
|
|
956
1043
|
['_ddIsModified', '_ddIsEfdRetry'],
|
|
957
|
-
config.
|
|
1044
|
+
config.earlyFlakeDetectionRetryPolicy
|
|
958
1045
|
)
|
|
959
1046
|
}
|
|
960
1047
|
}
|
|
@@ -968,12 +1055,12 @@ function getRunTestsWrapper (runTests, config) {
|
|
|
968
1055
|
suite.tests.forEach((test) => {
|
|
969
1056
|
if (!test.isPending() && isNewTest(test, config.knownTests)) {
|
|
970
1057
|
test._ddIsNew = true
|
|
971
|
-
if (
|
|
1058
|
+
if (!test._ddIsModified && isEarlyFlakeDetectionTest(test, config)) {
|
|
972
1059
|
retryTest(
|
|
973
1060
|
test,
|
|
974
|
-
|
|
1061
|
+
config.earlyFlakeDetectionRetryPolicy.schedulingRetryCount,
|
|
975
1062
|
['_ddIsNew', '_ddIsEfdRetry'],
|
|
976
|
-
config.
|
|
1063
|
+
config.earlyFlakeDetectionRetryPolicy
|
|
977
1064
|
)
|
|
978
1065
|
}
|
|
979
1066
|
}
|
|
@@ -1015,4 +1102,5 @@ module.exports = {
|
|
|
1015
1102
|
testsStatuses,
|
|
1016
1103
|
attemptToFixExecutions,
|
|
1017
1104
|
loggedAttemptToFixTests,
|
|
1105
|
+
adjustRunnerFailuresForTestOptimization,
|
|
1018
1106
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
createWebdriverioWorkerMessage,
|
|
5
|
+
WEBDRIVERIO_WORKER_ENV,
|
|
6
|
+
WEBDRIVERIO_WORKER_EVENT,
|
|
7
|
+
WEBDRIVERIO_WORKER_ORIGIN,
|
|
8
|
+
} = require('../../../dd-trace/src/ci-visibility/exporters/test-worker/webdriverio')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Sends a message over WebdriverIO's worker IPC envelope.
|
|
12
|
+
*
|
|
13
|
+
* @param {object} message
|
|
14
|
+
* @param {(error?: Error) => void} [onError]
|
|
15
|
+
* @param {() => void} [onDone]
|
|
16
|
+
* @returns {void}
|
|
17
|
+
*/
|
|
18
|
+
function sendWebdriverioWorkerMessage (message, onError, onDone) {
|
|
19
|
+
if (!process.send || !process.connected) {
|
|
20
|
+
onError?.()
|
|
21
|
+
onDone?.()
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
process.send(createWebdriverioWorkerMessage(message), (error) => {
|
|
26
|
+
if (error) {
|
|
27
|
+
onError?.(error)
|
|
28
|
+
}
|
|
29
|
+
onDone?.()
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
CONFIGURATION_REQUEST: 'dd:test-optimization:webdriverio:configuration:request',
|
|
35
|
+
CONFIGURATION_RESPONSE: 'dd:test-optimization:webdriverio:configuration:response',
|
|
36
|
+
createWebdriverioWorkerMessage,
|
|
37
|
+
sendWebdriverioWorkerMessage,
|
|
38
|
+
SUITE_FINISH: 'dd:test-optimization:webdriverio:test-suite:finish',
|
|
39
|
+
WORKER_READY: 'dd:test-optimization:webdriverio:worker:ready',
|
|
40
|
+
WORKER_READY_RESPONSE: 'dd:test-optimization:webdriverio:worker:ready:response',
|
|
41
|
+
WEBDRIVERIO_WORKER_ENV,
|
|
42
|
+
WEBDRIVERIO_WORKER_EVENT,
|
|
43
|
+
WEBDRIVERIO_WORKER_ORIGIN,
|
|
44
|
+
}
|