dd-trace 6.3.0 → 6.5.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/README.electron.md +7 -0
- package/README.md +17 -0
- package/ci/diagnose.js +2100 -0
- package/ci/init.js +23 -2
- package/ci/runbook.md +198 -0
- package/ci/test-optimization-validation/approval-artifacts.js +143 -0
- package/ci/test-optimization-validation/approval.js +299 -0
- package/ci/test-optimization-validation/artifact-id.js +20 -0
- package/ci/test-optimization-validation/bounded-json.js +121 -0
- package/ci/test-optimization-validation/ci-command-candidate.js +83 -0
- package/ci/test-optimization-validation/ci-discovery.js +181 -0
- package/ci/test-optimization-validation/ci-remediation.js +210 -0
- package/ci/test-optimization-validation/cli.js +903 -0
- package/ci/test-optimization-validation/command-blocker.js +81 -0
- package/ci/test-optimization-validation/command-output-policy.js +206 -0
- package/ci/test-optimization-validation/command-runner.js +707 -0
- package/ci/test-optimization-validation/command-suitability.js +471 -0
- package/ci/test-optimization-validation/executable-approval.js +48 -0
- package/ci/test-optimization-validation/executable.js +480 -0
- package/ci/test-optimization-validation/generated-file-policy.js +63 -0
- package/ci/test-optimization-validation/generated-files.js +351 -0
- package/ci/test-optimization-validation/generated-verifier.js +196 -0
- package/ci/test-optimization-validation/init-probe-preload.js +163 -0
- package/ci/test-optimization-validation/init-probe.js +246 -0
- package/ci/test-optimization-validation/late-initialization.js +63 -0
- package/ci/test-optimization-validation/local-command.js +163 -0
- package/ci/test-optimization-validation/manifest-loader.js +133 -0
- package/ci/test-optimization-validation/manifest-scaffold.js +738 -0
- package/ci/test-optimization-validation/manifest-schema.js +862 -0
- package/ci/test-optimization-validation/offline-fixtures.js +327 -0
- package/ci/test-optimization-validation/offline-output.js +406 -0
- package/ci/test-optimization-validation/payload-normalizer.js +72 -0
- package/ci/test-optimization-validation/plan-writer.js +1120 -0
- package/ci/test-optimization-validation/preflight-runner.js +114 -0
- package/ci/test-optimization-validation/redaction.js +331 -0
- package/ci/test-optimization-validation/report-writer.js +1508 -0
- package/ci/test-optimization-validation/safe-files.js +203 -0
- package/ci/test-optimization-validation/scenarios/auto-test-retries.js +159 -0
- package/ci/test-optimization-validation/scenarios/basic-reporting.js +657 -0
- package/ci/test-optimization-validation/scenarios/ci-wiring.js +780 -0
- package/ci/test-optimization-validation/scenarios/early-flake-detection.js +141 -0
- package/ci/test-optimization-validation/scenarios/helpers.js +539 -0
- package/ci/test-optimization-validation/scenarios/test-management.js +218 -0
- package/ci/test-optimization-validation/setup-runner.js +97 -0
- package/ci/test-optimization-validation/static-diagnosis.js +159 -0
- package/ci/test-optimization-validation/test-output.js +129 -0
- package/ci/test-optimization-validation-manifest.schema.json +1 -0
- package/ci/validate-test-optimization.js +3 -0
- package/ext/exporters.js +1 -0
- package/index.d.ts +121 -8
- package/index.electron.js +3 -0
- package/init.js +18 -0
- package/initialize.mjs +1 -1
- package/loader-hook.mjs +28 -18
- package/openfeature.d.ts +1 -0
- package/openfeature.js +4 -0
- package/package.json +15 -8
- package/packages/datadog-instrumentations/src/ai.js +37 -26
- package/packages/datadog-instrumentations/src/child_process.js +1 -1
- package/packages/datadog-instrumentations/src/claude-agent-sdk.js +1 -1
- package/packages/datadog-instrumentations/src/cucumber-worker-threads.js +9 -3
- package/packages/datadog-instrumentations/src/cucumber.js +24 -10
- package/packages/datadog-instrumentations/src/cypress-config.js +398 -52
- package/packages/datadog-instrumentations/src/express.js +20 -2
- package/packages/datadog-instrumentations/src/fastify.js +7 -11
- package/packages/datadog-instrumentations/src/grpc/server.js +18 -0
- package/packages/datadog-instrumentations/src/helpers/hook.js +27 -6
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +8 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +28 -2
- package/packages/datadog-instrumentations/src/helpers/router-helper.js +8 -8
- package/packages/datadog-instrumentations/src/http2/server.js +143 -17
- package/packages/datadog-instrumentations/src/jest.js +36 -4
- package/packages/datadog-instrumentations/src/mariadb.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +0 -2
- package/packages/datadog-instrumentations/src/mocha/utils.js +0 -4
- package/packages/datadog-instrumentations/src/mongodb.js +3 -3
- package/packages/datadog-instrumentations/src/mongoose.js +3 -3
- package/packages/datadog-instrumentations/src/mquery.js +2 -2
- package/packages/datadog-instrumentations/src/mysql.js +1 -1
- package/packages/datadog-instrumentations/src/next.js +24 -0
- package/packages/datadog-instrumentations/src/nyc.js +0 -2
- package/packages/datadog-instrumentations/src/oracledb.js +2 -2
- package/packages/datadog-instrumentations/src/pg.js +2 -2
- package/packages/datadog-instrumentations/src/playwright.js +159 -22
- package/packages/datadog-instrumentations/src/process.js +3 -0
- package/packages/datadog-instrumentations/src/router.js +191 -106
- package/packages/datadog-instrumentations/src/selenium.js +52 -26
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +2 -2
- package/packages/datadog-instrumentations/src/vitest-main.js +0 -2
- package/packages/datadog-instrumentations/src/ws.js +2 -1
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +2 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +41 -16
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +21 -21
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +14 -8
- package/packages/datadog-plugin-aws-sdk/src/util.js +2 -24
- package/packages/datadog-plugin-cucumber/src/index.js +1 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +24 -62
- package/packages/datadog-plugin-cypress/src/index.js +6 -1
- package/packages/datadog-plugin-cypress/src/support.js +92 -26
- package/packages/datadog-plugin-electron/src/ipc.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +177 -59
- package/packages/datadog-plugin-graphql/src/parse.js +22 -1
- package/packages/datadog-plugin-graphql/src/request.js +32 -1
- package/packages/datadog-plugin-graphql/src/utils.js +42 -0
- package/packages/datadog-plugin-graphql/src/validate.js +15 -3
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +38 -6
- package/packages/datadog-plugin-jest/src/util.js +21 -6
- package/packages/datadog-plugin-langchain/src/handlers/embedding.js +2 -1
- package/packages/datadog-plugin-langchain/src/handlers/language_models.js +2 -1
- package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
- package/packages/datadog-plugin-playwright/src/index.js +177 -64
- package/packages/datadog-plugin-router/src/index.js +11 -2
- package/packages/datadog-plugin-selenium/src/index.js +5 -36
- package/packages/datadog-plugin-vitest/src/index.js +4 -2
- package/packages/datadog-plugin-ws/src/close.js +2 -1
- package/packages/datadog-plugin-ws/src/producer.js +2 -1
- package/packages/datadog-plugin-ws/src/receiver.js +2 -1
- package/packages/datadog-plugin-ws/src/server.js +2 -1
- package/packages/dd-trace/index.electron.js +3 -0
- package/packages/dd-trace/index.js +2 -37
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +3 -1
- package/packages/dd-trace/src/azure_metadata.js +2 -1
- package/packages/dd-trace/src/bootstrap.js +39 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +93 -28
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/index.js +160 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/msgpack-to-json.js +288 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/payload-projection.js +84 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +369 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/writer.js +60 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -5
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +5 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +62 -7
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -2
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +6 -2
- package/packages/dd-trace/src/ci-visibility/rum.js +7 -0
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +137 -9
- package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +173 -9
- package/packages/dd-trace/src/ci-visibility/test-screenshot.js +90 -0
- package/packages/dd-trace/src/config/generated-config-types.d.ts +20 -0
- package/packages/dd-trace/src/config/helper.js +1 -0
- package/packages/dd-trace/src/config/index.js +10 -0
- package/packages/dd-trace/src/config/supported-configurations.json +83 -0
- package/packages/dd-trace/src/constants.js +7 -0
- package/packages/dd-trace/src/datastreams/pathway.js +6 -4
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/common/client-library-headers.js +21 -0
- package/packages/dd-trace/src/exporters/common/request.js +59 -30
- package/packages/dd-trace/src/exporters/common/url.js +15 -1
- package/packages/dd-trace/src/feature-registry.js +29 -0
- package/packages/dd-trace/src/llmobs/constants/tags.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +113 -0
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +154 -0
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +283 -0
- package/packages/dd-trace/src/llmobs/experiments/index.js +152 -0
- package/packages/dd-trace/src/llmobs/experiments/noop.js +30 -0
- package/packages/dd-trace/src/llmobs/experiments/result.js +34 -0
- package/packages/dd-trace/src/llmobs/index.js +10 -2
- package/packages/dd-trace/src/llmobs/noop.js +6 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/vercelTelemetry.js +20 -3
- package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/constants.js +8 -0
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +48 -14
- package/packages/dd-trace/src/llmobs/plugins/openai/utils.js +43 -0
- package/packages/dd-trace/src/llmobs/sdk.js +17 -0
- package/packages/dd-trace/src/llmobs/tagger.js +79 -7
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/llmobs/util.js +32 -0
- package/packages/dd-trace/src/noop/proxy.js +5 -4
- package/packages/dd-trace/src/openfeature/agentless_configuration_source.js +322 -0
- package/packages/dd-trace/src/openfeature/configuration_source.js +90 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +14 -23
- package/packages/dd-trace/src/openfeature/index.js +0 -2
- package/packages/dd-trace/src/openfeature/noop.js +1 -28
- package/packages/dd-trace/src/openfeature/register.js +35 -0
- package/packages/dd-trace/src/openfeature/remote_config.js +15 -18
- package/packages/dd-trace/src/openfeature/require-provider.js +18 -0
- package/packages/dd-trace/src/opentelemetry/span-ending-hook.js +10 -0
- package/packages/dd-trace/src/opentelemetry/span.js +5 -0
- package/packages/dd-trace/src/opentracing/propagation/log.js +11 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +80 -14
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +10 -1
- package/packages/dd-trace/src/opentracing/tracer.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -6
- package/packages/dd-trace/src/plugins/util/git.js +3 -2
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +29 -5
- package/packages/dd-trace/src/plugins/util/test.js +65 -8
- package/packages/dd-trace/src/plugins/util/web.js +12 -0
- package/packages/dd-trace/src/proxy.js +99 -10
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/standalone/index.js +0 -36
- package/packages/dd-trace/src/telemetry/send-data.js +2 -2
- package/packages/dd-trace/src/util.js +26 -0
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +0 -17
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
const { runCommand } = require('../command-runner')
|
|
7
|
+
const { getDatadogCleanCommand, getLocalValidationCommand } = require('../local-command')
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
basicEventEvidence,
|
|
11
|
+
error,
|
|
12
|
+
failWithDebugRerun,
|
|
13
|
+
findInterestingLines,
|
|
14
|
+
frameworkOutDir,
|
|
15
|
+
hasAllBasicEventTypes,
|
|
16
|
+
inconclusive,
|
|
17
|
+
pass,
|
|
18
|
+
runInstrumentedCommand,
|
|
19
|
+
tailInterestingLines,
|
|
20
|
+
} = require('./helpers')
|
|
21
|
+
|
|
22
|
+
async function runBasicReporting ({ framework, out, options }) {
|
|
23
|
+
const scenarioName = 'basic-reporting'
|
|
24
|
+
try {
|
|
25
|
+
const command = getBasicReportingCommand(framework)
|
|
26
|
+
const { result, events, offline, outDir } = await runInstrumentedCommand({
|
|
27
|
+
framework,
|
|
28
|
+
out,
|
|
29
|
+
scenarioName,
|
|
30
|
+
command,
|
|
31
|
+
options,
|
|
32
|
+
allowMissingInitialization: true,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const evidence = {
|
|
36
|
+
commandExitCode: result.exitCode,
|
|
37
|
+
commandTimedOut: result.timedOut,
|
|
38
|
+
commandDescription: command?.description,
|
|
39
|
+
commandOutputSummary: summarizeTestOutput(result.stdout, result.stderr),
|
|
40
|
+
manifestNotes: Array.isArray(framework.notes) ? framework.notes : [],
|
|
41
|
+
preflight: summarizePreflight(framework.preflight),
|
|
42
|
+
offlineExporterInitialized: offline.initialized,
|
|
43
|
+
settingsLoadedFromCache: offline.inputs.settings?.status === 'loaded',
|
|
44
|
+
offlineExporterSummary: offline.summary,
|
|
45
|
+
...basicEventEvidence(events),
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (evidence.offlineExporterInitialized && !evidence.settingsLoadedFromCache) {
|
|
49
|
+
return error(
|
|
50
|
+
framework,
|
|
51
|
+
scenarioName,
|
|
52
|
+
new Error('Basic Reporting settings were not loaded from the authoritative offline cache fixture.'),
|
|
53
|
+
outDir
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!hasAllBasicEventTypes(events)) {
|
|
58
|
+
if (result.exitCode !== 0) {
|
|
59
|
+
evidence.commandFailure = summarizeCommandFailure(result, evidence)
|
|
60
|
+
}
|
|
61
|
+
const eventLevelFailure = getMissingEventDiagnosis({ framework, result, evidence })
|
|
62
|
+
evidence.eventLevelFailure = eventLevelFailure
|
|
63
|
+
|
|
64
|
+
return failBasicReportingWithDebugRerun({
|
|
65
|
+
command,
|
|
66
|
+
diagnosis: eventLevelFailure.summary,
|
|
67
|
+
evidence,
|
|
68
|
+
framework,
|
|
69
|
+
options,
|
|
70
|
+
out,
|
|
71
|
+
outDir,
|
|
72
|
+
scenarioName,
|
|
73
|
+
skipDebug: evidence.commandFailure?.buildErrors?.length > 0 ||
|
|
74
|
+
!shouldRunDebugRerun(eventLevelFailure, result),
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (result.exitCode === 0) {
|
|
79
|
+
return pass(
|
|
80
|
+
framework,
|
|
81
|
+
scenarioName,
|
|
82
|
+
'Basic reporting emitted session, module, suite, and test events.',
|
|
83
|
+
evidence,
|
|
84
|
+
outDir
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (matchesPreflightExitCode(framework.preflight, result.exitCode)) {
|
|
89
|
+
evidence.commandFailure = summarizeCommandFailure(result, evidence)
|
|
90
|
+
evidence.commandExitMatchesPreflight = true
|
|
91
|
+
return pass(
|
|
92
|
+
framework,
|
|
93
|
+
scenarioName,
|
|
94
|
+
'Basic reporting emitted session, module, suite, and test events. ' +
|
|
95
|
+
`The command exited ${result.exitCode}, matching the dd-trace-less preflight run.`,
|
|
96
|
+
evidence,
|
|
97
|
+
outDir
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
evidence.commandFailure = summarizeCommandFailure(result, evidence)
|
|
102
|
+
evidence.commandExitMatchesPreflight = false
|
|
103
|
+
const cleanConfirmation = await runCleanConfirmation({ command, framework, options, out, scenarioName })
|
|
104
|
+
evidence.cleanConfirmation = cleanConfirmation.evidence
|
|
105
|
+
|
|
106
|
+
if (!cleanConfirmation.evidence.exitMatchesPreflight) {
|
|
107
|
+
return inconclusive(
|
|
108
|
+
framework,
|
|
109
|
+
scenarioName,
|
|
110
|
+
getUnstableBaselineDiagnosis(framework.preflight, result, cleanConfirmation.result),
|
|
111
|
+
evidence,
|
|
112
|
+
outDir,
|
|
113
|
+
cleanConfirmation.artifacts
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const failure = await failBasicReportingWithDebugRerun({
|
|
118
|
+
command,
|
|
119
|
+
diagnosis: getPossibleCompatibilityDiagnosis(framework.preflight, result),
|
|
120
|
+
evidence,
|
|
121
|
+
framework,
|
|
122
|
+
options,
|
|
123
|
+
out,
|
|
124
|
+
outDir,
|
|
125
|
+
scenarioName,
|
|
126
|
+
})
|
|
127
|
+
failure.artifacts.push(...cleanConfirmation.artifacts)
|
|
128
|
+
return failure
|
|
129
|
+
} catch (err) {
|
|
130
|
+
return error(framework, scenarioName, err)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Repeats the selected command without Datadog after an instrumented exit-code mismatch.
|
|
136
|
+
*
|
|
137
|
+
* @param {object} input confirmation inputs
|
|
138
|
+
* @param {object} input.command selected project command
|
|
139
|
+
* @param {object} input.framework manifest framework entry
|
|
140
|
+
* @param {object} input.options validator options
|
|
141
|
+
* @param {string} input.out validation output directory
|
|
142
|
+
* @param {string} input.scenarioName scenario identifier
|
|
143
|
+
* @returns {Promise<{artifacts: string[], evidence: object, result: object}>} clean confirmation outcome
|
|
144
|
+
*/
|
|
145
|
+
async function runCleanConfirmation ({ command, framework, options, out, scenarioName }) {
|
|
146
|
+
const outDir = frameworkOutDir(out, framework, `${scenarioName}-clean-confirmation`)
|
|
147
|
+
const result = await runCommand(getDatadogCleanCommand(command), {
|
|
148
|
+
artifactRoot: out,
|
|
149
|
+
envMode: 'clean',
|
|
150
|
+
label: `${framework.id}:${scenarioName}:clean-confirmation`,
|
|
151
|
+
outDir,
|
|
152
|
+
repositoryRoot: options.repositoryRoot,
|
|
153
|
+
requireExecutableApproval: options.requireExecutableApproval,
|
|
154
|
+
verbose: options.verbose,
|
|
155
|
+
})
|
|
156
|
+
const exitMatchesPreflight = !result.timedOut && matchesPreflightExitCode(framework.preflight, result.exitCode)
|
|
157
|
+
return {
|
|
158
|
+
artifacts: Object.values(result.artifacts),
|
|
159
|
+
result,
|
|
160
|
+
evidence: {
|
|
161
|
+
ran: true,
|
|
162
|
+
exitCode: result.exitCode,
|
|
163
|
+
timedOut: result.timedOut,
|
|
164
|
+
exitMatchesPreflight,
|
|
165
|
+
commandOutputSummary: summarizeTestOutput(result.stdout, result.stderr),
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Describes an exit mismatch that cannot be attributed because clean executions disagreed.
|
|
172
|
+
*
|
|
173
|
+
* @param {object} preflight initial clean preflight evidence
|
|
174
|
+
* @param {object} instrumented instrumented command result
|
|
175
|
+
* @param {object} cleanConfirmation repeated clean command result
|
|
176
|
+
* @returns {string} customer-facing diagnosis
|
|
177
|
+
*/
|
|
178
|
+
function getUnstableBaselineDiagnosis (preflight, instrumented, cleanConfirmation) {
|
|
179
|
+
const confirmation = cleanConfirmation.timedOut
|
|
180
|
+
? 'timed out'
|
|
181
|
+
: `exited ${cleanConfirmation.exitCode}`
|
|
182
|
+
return `The selected command exited ${preflight.exitCode} during the initial clean preflight, exited ` +
|
|
183
|
+
`${instrumented.exitCode} with Datadog initialized, and ${confirmation} during a second clean run. The ` +
|
|
184
|
+
'non-Datadog baseline was not stable, so no Test Optimization compatibility conclusion was reached.'
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Describes an instrumented-only exit mismatch after the clean baseline was reproduced.
|
|
189
|
+
*
|
|
190
|
+
* @param {object} preflight initial clean preflight evidence
|
|
191
|
+
* @param {object} instrumented instrumented command result
|
|
192
|
+
* @returns {string} customer-facing diagnosis
|
|
193
|
+
*/
|
|
194
|
+
function getPossibleCompatibilityDiagnosis (preflight, instrumented) {
|
|
195
|
+
return `The selected command exited ${preflight.exitCode} in both runs without Datadog, but exited ` +
|
|
196
|
+
`${instrumented.exitCode} with Datadog initialized after reporting Test Optimization events. This may indicate ` +
|
|
197
|
+
'a dd-trace compatibility issue rather than a project baseline failure.'
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function getBasicReportingCommand (framework) {
|
|
201
|
+
return getLocalValidationCommand(framework, framework.existingTestCommand)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function failBasicReportingWithDebugRerun (options) {
|
|
205
|
+
const failure = await failWithDebugRerun(options)
|
|
206
|
+
return refineBasicReportingFailure(failure)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function refineBasicReportingFailure (failure) {
|
|
210
|
+
const evidence = failure.evidence || {}
|
|
211
|
+
if (['dd-trace-preload-failed', 'command-setup-failed'].includes(evidence.eventLevelFailure?.kind)) {
|
|
212
|
+
failure.status = 'error'
|
|
213
|
+
evidence.localDiagnosis = evidence.eventLevelFailure
|
|
214
|
+
return failure
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const diagnosis = getDebugAwareDiagnosis(failure.diagnosis, evidence)
|
|
218
|
+
if (!diagnosis) return failure
|
|
219
|
+
|
|
220
|
+
failure.diagnosis = diagnosis.summary
|
|
221
|
+
evidence.localDiagnosis = diagnosis
|
|
222
|
+
|
|
223
|
+
if (evidence.eventLevelFailure) {
|
|
224
|
+
evidence.eventLevelFailure = {
|
|
225
|
+
...evidence.eventLevelFailure,
|
|
226
|
+
summary: diagnosis.summary,
|
|
227
|
+
recommendation: diagnosis.recommendation,
|
|
228
|
+
signals: diagnosis.signals,
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return failure
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function getDebugAwareDiagnosis (currentDiagnosis, evidence) {
|
|
236
|
+
if (evidence.eventLevelFailure?.kind !== 'no-test-optimization-events') return null
|
|
237
|
+
|
|
238
|
+
const debugRerun = evidence.debugRerun
|
|
239
|
+
if (!debugRerun || debugRerun.ran !== true) return null
|
|
240
|
+
|
|
241
|
+
const testOutputSummary = summarizeTestOutput(
|
|
242
|
+
(evidence.commandOutputSummary || []).join('\n'),
|
|
243
|
+
(debugRerun.stdoutExcerpt || []).join('\n')
|
|
244
|
+
)
|
|
245
|
+
const testsRan = commandOutputShowsTestsRan(testOutputSummary)
|
|
246
|
+
const debugLine = findDebugLine(debugRerun, /dd-trace is not initialized in a package manager/i)
|
|
247
|
+
const noDebugEvents = !hasAnyTestOptimizationEvent(debugRerun)
|
|
248
|
+
|
|
249
|
+
if (testsRan && debugLine && noDebugEvents) {
|
|
250
|
+
return {
|
|
251
|
+
kind: 'tests-ran-tracer-not-initialized',
|
|
252
|
+
summary: 'The selected command ran tests, but no Test Optimization events reached the offline event artifact. ' +
|
|
253
|
+
`The debug rerun printed "${debugLine}", which means the preload executed in the package-manager ` +
|
|
254
|
+
'wrapper without producing Test Optimization events from the test process.',
|
|
255
|
+
recommendation: 'Try a direct test-runner command, or verify NODE_OPTIONS with dd-trace/ci/init reaches the ' +
|
|
256
|
+
'final test process rather than only the package-manager wrapper.',
|
|
257
|
+
signals: getDebugSignals({
|
|
258
|
+
debugLine,
|
|
259
|
+
debugRerun,
|
|
260
|
+
testOutputSummary,
|
|
261
|
+
}),
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (testsRan && noDebugEvents) {
|
|
266
|
+
return {
|
|
267
|
+
kind: 'tests-ran-no-test-optimization-events',
|
|
268
|
+
summary: 'The selected command ran tests, but no Test Optimization events reached the offline event artifact. ' +
|
|
269
|
+
'The debug rerun did not emit Test Optimization events either.',
|
|
270
|
+
recommendation: 'Inspect the debug rerun excerpt for tracer initialization or offline exporter errors, then ' +
|
|
271
|
+
'verify NODE_OPTIONS with dd-trace/ci/init reaches the final test process.',
|
|
272
|
+
signals: getDebugSignals({
|
|
273
|
+
debugRerun,
|
|
274
|
+
testOutputSummary,
|
|
275
|
+
}),
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (debugLine && noDebugEvents) {
|
|
280
|
+
return {
|
|
281
|
+
kind: 'tracer-not-initialized',
|
|
282
|
+
summary: `${currentDiagnosis} The debug rerun printed "${debugLine}".`,
|
|
283
|
+
recommendation: 'Verify NODE_OPTIONS with dd-trace/ci/init reaches the final test process.',
|
|
284
|
+
signals: getDebugSignals({
|
|
285
|
+
debugLine,
|
|
286
|
+
debugRerun,
|
|
287
|
+
testOutputSummary,
|
|
288
|
+
}),
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function shouldRunDebugRerun (eventLevelFailure, result) {
|
|
294
|
+
return result.timedOut !== true &&
|
|
295
|
+
eventLevelFailure.kind !== 'vitest-benchmark' &&
|
|
296
|
+
eventLevelFailure.kind !== 'custom-jest-runner'
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function matchesPreflightExitCode (preflight, exitCode) {
|
|
300
|
+
return preflight?.ran === true &&
|
|
301
|
+
Number.isInteger(preflight.exitCode) &&
|
|
302
|
+
preflight.exitCode === exitCode
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function summarizePreflight (preflight) {
|
|
306
|
+
if (!preflight || preflight.ran !== true) {
|
|
307
|
+
return {
|
|
308
|
+
ran: false,
|
|
309
|
+
reason: 'No dd-trace-less preflight result was recorded in the manifest.',
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
ran: true,
|
|
315
|
+
exitCode: preflight.exitCode,
|
|
316
|
+
observedTestCount: preflight.observedTestCount,
|
|
317
|
+
stdoutSummary: preflight.stdoutSummary,
|
|
318
|
+
stderrSummary: preflight.stderrSummary,
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function summarizeTestOutput (stdout = '', stderr = '') {
|
|
323
|
+
return findInterestingLines(`${stdout}\n${stderr}`, [
|
|
324
|
+
/\b\d+\s+passing\b/i,
|
|
325
|
+
/\b\d+\s+pending\b/i,
|
|
326
|
+
/\b\d+\s+failing\b/i,
|
|
327
|
+
/\b\d+\s+passed\b/i,
|
|
328
|
+
/\b\d+\s+failed\b/i,
|
|
329
|
+
/\btests?\b.*\bpassed\b/i,
|
|
330
|
+
/\btests?\b.*\bfailed\b/i,
|
|
331
|
+
/\bSuccessfully ran target\b.*\btest\b/i,
|
|
332
|
+
/\bsuccess:\s*\d+\b/i,
|
|
333
|
+
/\bTasks:\s*\d+\s+successful\b/i,
|
|
334
|
+
], 8)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function commandOutputShowsTestsRan (lines) {
|
|
338
|
+
return lines.some(line => {
|
|
339
|
+
return /\b\d+\s+(?:passing|passed)\b/i.test(line) ||
|
|
340
|
+
/\btests?\b.*\bpassed\b/i.test(line) ||
|
|
341
|
+
/\bSuccessfully ran target\b.*\btest\b/i.test(line) ||
|
|
342
|
+
/\bsuccess:\s*[1-9]\d*\b/i.test(line) ||
|
|
343
|
+
/\bfailed:\s*[1-9]\d*\b/i.test(line) ||
|
|
344
|
+
/\bTasks:\s*[1-9]\d*\s+successful\b/i.test(line)
|
|
345
|
+
})
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function findDebugLine (debugRerun, pattern) {
|
|
349
|
+
const lines = [
|
|
350
|
+
...(debugRerun.debugLines || []),
|
|
351
|
+
...(debugRerun.stdoutExcerpt || []),
|
|
352
|
+
...(debugRerun.stderrExcerpt || []),
|
|
353
|
+
]
|
|
354
|
+
return lines.find(line => pattern.test(line))
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function getDebugSignals ({ debugLine, debugRerun, testOutputSummary }) {
|
|
358
|
+
return {
|
|
359
|
+
debugLine,
|
|
360
|
+
debugLines: debugRerun.debugLines || [],
|
|
361
|
+
stdoutExcerpt: debugRerun.stdoutExcerpt || [],
|
|
362
|
+
stderrExcerpt: debugRerun.stderrExcerpt || [],
|
|
363
|
+
testOutputSummary,
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function summarizeCommandFailure (result, evidence) {
|
|
368
|
+
const output = `${result.stdout}\n${result.stderr}`
|
|
369
|
+
const buildErrors = findInterestingLines(output, [
|
|
370
|
+
/Could not resolve /,
|
|
371
|
+
/Cannot find module/,
|
|
372
|
+
/Module not found/,
|
|
373
|
+
/Error \[ERR_MODULE_NOT_FOUND\]/,
|
|
374
|
+
])
|
|
375
|
+
const assertionFailures = findInterestingLines(output, [
|
|
376
|
+
/AssertionError/,
|
|
377
|
+
/Timed out retrying/,
|
|
378
|
+
/^\s+\d+\) /,
|
|
379
|
+
])
|
|
380
|
+
const testEventsWereReported = evidence.testSessionEvents > 0 &&
|
|
381
|
+
evidence.testModuleEvents > 0 &&
|
|
382
|
+
evidence.testSuiteEvents > 0 &&
|
|
383
|
+
evidence.testEvents > 0
|
|
384
|
+
const summary = getFailureSummary({
|
|
385
|
+
buildErrors,
|
|
386
|
+
assertionFailures,
|
|
387
|
+
exitCode: result.exitCode,
|
|
388
|
+
testEventsWereReported,
|
|
389
|
+
timedOut: result.timedOut,
|
|
390
|
+
})
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
assertionFailures,
|
|
394
|
+
buildErrors,
|
|
395
|
+
stderrExcerpt: tailInterestingLines(result.stderr),
|
|
396
|
+
stdoutExcerpt: tailInterestingLines(result.stdout),
|
|
397
|
+
summary,
|
|
398
|
+
testEventsWereReported,
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function getMissingEventDiagnosis ({ framework, result, evidence }) {
|
|
403
|
+
const missingLevels = getMissingLevels(evidence)
|
|
404
|
+
const commandFailure = evidence.commandFailure
|
|
405
|
+
const vitestBenchmark = detectVitestBenchmark(framework, result)
|
|
406
|
+
const frameworkSourceTreeRunner = detectFrameworkSourceTreeRunner(framework, result)
|
|
407
|
+
const customJestRunner = detectCustomJestRunner(framework)
|
|
408
|
+
|
|
409
|
+
if (commandFailure?.buildErrors?.length > 0 && !hasAnyTestOptimizationEvent(evidence)) {
|
|
410
|
+
const preloadFailed = /(?:ci\/init\.js|internal\/preload)/.test(`${result.stdout}\n${result.stderr}`)
|
|
411
|
+
return {
|
|
412
|
+
kind: preloadFailed ? 'dd-trace-preload-failed' : 'command-setup-failed',
|
|
413
|
+
missingLevels,
|
|
414
|
+
signals: commandFailure.buildErrors,
|
|
415
|
+
summary: preloadFailed
|
|
416
|
+
? `The Test Optimization preload failed before tests started: ${commandFailure.buildErrors[0]}. ` +
|
|
417
|
+
'No Test Optimization conclusion was reached.'
|
|
418
|
+
: `${commandFailure.summary} No Test Optimization conclusion was reached.`,
|
|
419
|
+
recommendation: preloadFailed
|
|
420
|
+
? 'Repair or reinstall dd-trace so its declared dependencies resolve, then rerun validation.'
|
|
421
|
+
: 'Fix the selected project command or its setup, then rerun validation.',
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (vitestBenchmark) {
|
|
426
|
+
return {
|
|
427
|
+
kind: 'vitest-benchmark',
|
|
428
|
+
missingLevels,
|
|
429
|
+
signals: vitestBenchmark.signals,
|
|
430
|
+
summary: 'The selected Vitest command appears to run benchmark mode, not normal tests. ' +
|
|
431
|
+
'Test Optimization reported session/module/suite events, but Vitest benchmark mode did not emit ' +
|
|
432
|
+
'per-test events. Choose a normal Vitest test command such as "vitest run <test-file>" for validation.',
|
|
433
|
+
recommendation: 'Replace the selected command with a normal Vitest test command; do not use `vitest bench` ' +
|
|
434
|
+
'or benchmark-only `*.bench.*` files for Test Optimization validation.',
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (frameworkSourceTreeRunner && !hasAnyTestOptimizationEvent(evidence)) {
|
|
439
|
+
return {
|
|
440
|
+
kind: 'framework-source-tree-runner',
|
|
441
|
+
missingLevels,
|
|
442
|
+
signals: frameworkSourceTreeRunner.signals,
|
|
443
|
+
summary: 'The selected command ran tests from the test framework source tree, but no Test Optimization ' +
|
|
444
|
+
'events reached the offline event artifact. This command is not equivalent to a customer project running an ' +
|
|
445
|
+
'installed test-runner package.',
|
|
446
|
+
recommendation: 'Choose a project test command that uses an installed supported framework package. If this ' +
|
|
447
|
+
'repository is the framework itself, treat this entry as not runnable for Test Optimization validation.',
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (!hasAnyTestOptimizationEvent(evidence)) {
|
|
452
|
+
return {
|
|
453
|
+
kind: 'no-test-optimization-events',
|
|
454
|
+
missingLevels,
|
|
455
|
+
summary: 'No Test Optimization test events reached the offline event artifact. The tracer may not have ' +
|
|
456
|
+
'initialized in the test process, or the selected command may not have executed tests.',
|
|
457
|
+
recommendation: 'Check the debug rerun output for tracer initialization or offline exporter errors.',
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (evidence.testEvents === 0) {
|
|
462
|
+
if (customJestRunner) {
|
|
463
|
+
return {
|
|
464
|
+
kind: 'custom-jest-runner',
|
|
465
|
+
missingLevels,
|
|
466
|
+
customTestRunner: customJestRunner,
|
|
467
|
+
signals: customJestRunner.signals,
|
|
468
|
+
summary: `We detected a custom Jest-compatible runner: \`${customJestRunner.name}\`. The test command ` +
|
|
469
|
+
'executes tests, but it does not use a currently supported Jest entrypoint. Test Optimization ' +
|
|
470
|
+
'initialized, but this runner did not emit the Jest lifecycle events needed to report individual ' +
|
|
471
|
+
'suites and tests.',
|
|
472
|
+
recommendation: 'Try a standard Jest runner command for validation, or choose a test command that does not ' +
|
|
473
|
+
'use the custom runner. If this project must use the custom runner, dd-trace may need explicit support ' +
|
|
474
|
+
'for that runner before per-test reporting and advanced Test Optimization features can work.',
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return {
|
|
479
|
+
kind: 'missing-test-events',
|
|
480
|
+
missingLevels,
|
|
481
|
+
summary: 'Test Optimization initialized and emitted higher-level events, but per-test events were missing. ' +
|
|
482
|
+
'This usually points to an unsupported runner mode, unsupported framework configuration, or per-test hooks ' +
|
|
483
|
+
'not firing for the selected command.',
|
|
484
|
+
recommendation: 'Choose a smaller standard test command, then inspect the debug rerun output for hook or ' +
|
|
485
|
+
'exporter errors.',
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
return {
|
|
490
|
+
kind: 'missing-event-levels',
|
|
491
|
+
missingLevels,
|
|
492
|
+
summary: `The command ran, but these required Test Optimization event levels were missing: ${
|
|
493
|
+
missingLevels.join(', ')
|
|
494
|
+
}.`,
|
|
495
|
+
recommendation: 'Inspect the debug rerun output for tracer initialization, hook, or exporter errors.',
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
function getMissingLevels (evidence) {
|
|
500
|
+
const missing = []
|
|
501
|
+
if (evidence.testSessionEvents === 0) missing.push('test_session_end')
|
|
502
|
+
if (evidence.testModuleEvents === 0) missing.push('test_module_end')
|
|
503
|
+
if (evidence.testSuiteEvents === 0) missing.push('test_suite_end')
|
|
504
|
+
if (evidence.testEvents === 0) missing.push('test')
|
|
505
|
+
return missing
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function hasAnyTestOptimizationEvent (evidence) {
|
|
509
|
+
return evidence.testSessionEvents > 0 ||
|
|
510
|
+
evidence.testModuleEvents > 0 ||
|
|
511
|
+
evidence.testSuiteEvents > 0 ||
|
|
512
|
+
evidence.testEvents > 0
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function detectVitestBenchmark (framework, result) {
|
|
516
|
+
if (framework.framework !== 'vitest') return null
|
|
517
|
+
|
|
518
|
+
const command = result.command || ''
|
|
519
|
+
const output = `${result.stdout}\n${result.stderr}`
|
|
520
|
+
const signals = []
|
|
521
|
+
|
|
522
|
+
if (/\bvitest\s+bench\b/.test(command)) signals.push('command contains `vitest bench`')
|
|
523
|
+
if (/\.bench\.[cm]?[jt]sx?\b/.test(command)) signals.push('command targets a `*.bench.*` file')
|
|
524
|
+
if (/^\s*BENCH\s+Summary\b/m.test(output)) signals.push('stdout contains a Vitest BENCH summary')
|
|
525
|
+
if (/Benchmarking is an experimental feature/.test(output)) {
|
|
526
|
+
signals.push('stderr says Vitest benchmarking is experimental')
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return signals.length > 0 ? { signals } : null
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function detectCustomJestRunner (framework) {
|
|
533
|
+
if (framework.framework !== 'jest') return null
|
|
534
|
+
|
|
535
|
+
const configRunner = findJestRunnerInConfigFiles(framework.project?.configFiles || [])
|
|
536
|
+
if (configRunner && isCustomJestRunner(configRunner.name)) return configRunner
|
|
537
|
+
|
|
538
|
+
const packageRunner = findJestRunnerInPackageJson(framework.project?.packageJson)
|
|
539
|
+
if (packageRunner && isCustomJestRunner(packageRunner.name)) return packageRunner
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function findJestRunnerInConfigFiles (configFiles) {
|
|
543
|
+
for (const configFile of configFiles) {
|
|
544
|
+
const content = readFile(configFile)
|
|
545
|
+
if (!content) continue
|
|
546
|
+
|
|
547
|
+
const match = /(?:^|[,{]\s*)runner\s*:\s*['"]([^'"]+)['"]/.exec(content)
|
|
548
|
+
if (!match) continue
|
|
549
|
+
|
|
550
|
+
return {
|
|
551
|
+
name: match[1],
|
|
552
|
+
source: configFile,
|
|
553
|
+
sourceType: 'config',
|
|
554
|
+
signals: [
|
|
555
|
+
`Jest config ${configFile} sets runner: ${match[1]}`,
|
|
556
|
+
],
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function findJestRunnerInPackageJson (packageJsonPath) {
|
|
562
|
+
if (!packageJsonPath) return
|
|
563
|
+
|
|
564
|
+
try {
|
|
565
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
|
|
566
|
+
const runner = packageJson.jest?.runner
|
|
567
|
+
if (typeof runner !== 'string' || runner.length === 0) return
|
|
568
|
+
|
|
569
|
+
return {
|
|
570
|
+
name: runner,
|
|
571
|
+
source: packageJsonPath,
|
|
572
|
+
sourceType: 'package.json',
|
|
573
|
+
signals: [
|
|
574
|
+
`package.json jest.runner is ${runner}`,
|
|
575
|
+
],
|
|
576
|
+
}
|
|
577
|
+
} catch {}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function isCustomJestRunner (runner) {
|
|
581
|
+
return runner !== 'jest-runner'
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function detectFrameworkSourceTreeRunner (framework, result) {
|
|
585
|
+
if (framework.framework !== 'mocha') return null
|
|
586
|
+
|
|
587
|
+
const projectName = framework.project?.name || ''
|
|
588
|
+
const commandAndOutput = [
|
|
589
|
+
result.command || '',
|
|
590
|
+
result.stdout || '',
|
|
591
|
+
result.stderr || '',
|
|
592
|
+
].join('\n')
|
|
593
|
+
const signals = []
|
|
594
|
+
|
|
595
|
+
if (projectName === 'mocha') {
|
|
596
|
+
signals.push('repository package name is `mocha`')
|
|
597
|
+
}
|
|
598
|
+
if (/\bnode\s+\.\/bin\/mocha\.js\b/.test(commandAndOutput) ||
|
|
599
|
+
/\bnode\s+bin\/mocha\.js\b/.test(commandAndOutput)) {
|
|
600
|
+
signals.push('selected command invokes the repository-local `bin/mocha.js` source-tree runner')
|
|
601
|
+
}
|
|
602
|
+
if (fileExists(framework.project?.root, 'lib/mocha.cjs') && fileExists(framework.project?.root, 'lib/runner.cjs')) {
|
|
603
|
+
signals.push('repository contains Mocha source files `lib/mocha.cjs` and `lib/runner.cjs`')
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return signals.length >= 2 ? { signals } : null
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function fileExists (root, filename) {
|
|
610
|
+
if (!root) return false
|
|
611
|
+
|
|
612
|
+
try {
|
|
613
|
+
return fs.existsSync(path.join(root, filename))
|
|
614
|
+
} catch {
|
|
615
|
+
return false
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
function readFile (filename) {
|
|
620
|
+
try {
|
|
621
|
+
return fs.readFileSync(filename, 'utf8')
|
|
622
|
+
} catch {}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
function getFailureSummary ({ buildErrors, assertionFailures, exitCode, testEventsWereReported, timedOut }) {
|
|
626
|
+
if (timedOut) {
|
|
627
|
+
return 'The selected test command timed out before payload validation could pass.'
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (buildErrors.length > 0) {
|
|
631
|
+
if (testEventsWereReported) {
|
|
632
|
+
return 'The selected test command reported Datadog test events, but project setup/build errors made it fail.'
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
return 'The selected test command failed during project setup/build before payload validation could pass.'
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (assertionFailures.length > 0 && testEventsWereReported) {
|
|
639
|
+
return 'The selected test command reported Datadog test events, but the tests failed.'
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
if (testEventsWereReported) {
|
|
643
|
+
return `The selected test command reported Datadog test events, but exited ${exitCode}.`
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
return `The selected test command exited ${exitCode} before payload validation could pass.`
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
module.exports = {
|
|
650
|
+
getDebugAwareDiagnosis,
|
|
651
|
+
getBasicReportingCommand,
|
|
652
|
+
getMissingEventDiagnosis,
|
|
653
|
+
refineBasicReportingFailure,
|
|
654
|
+
runBasicReporting,
|
|
655
|
+
shouldRunDebugRerun,
|
|
656
|
+
summarizeTestOutput,
|
|
657
|
+
}
|