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,141 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
discoverScenarioTests,
|
|
5
|
+
discoveryEvidence,
|
|
6
|
+
error,
|
|
7
|
+
failWithDebugRerun,
|
|
8
|
+
pass,
|
|
9
|
+
prepareGeneratedScenario,
|
|
10
|
+
requireGeneratedScenario,
|
|
11
|
+
runInstrumentedCommand,
|
|
12
|
+
skip,
|
|
13
|
+
testEventSamples,
|
|
14
|
+
testsForDiscoveredScenario,
|
|
15
|
+
} = require('./helpers')
|
|
16
|
+
|
|
17
|
+
async function runEarlyFlakeDetection ({ framework, out, options }) {
|
|
18
|
+
const scenarioName = 'efd'
|
|
19
|
+
const skipResult = requireGeneratedScenario(framework, 'basic-pass', scenarioName)
|
|
20
|
+
if (skipResult) return skipResult
|
|
21
|
+
|
|
22
|
+
let outDir
|
|
23
|
+
try {
|
|
24
|
+
const { scenario } = await prepareGeneratedScenario(framework, 'basic-pass')
|
|
25
|
+
if (!scenario) {
|
|
26
|
+
return skip(framework, scenarioName, 'Generated scenario "basic-pass" is not present in the manifest.')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const discovery = await discoverScenarioTests({ framework, out, scenarioName, scenario, options })
|
|
30
|
+
if (discovery.tests.length === 0) {
|
|
31
|
+
return failWithDebugRerun({
|
|
32
|
+
command: scenario.runCommand,
|
|
33
|
+
diagnosis: 'The generated new-test candidate was not reported during baseline identity discovery.',
|
|
34
|
+
evidence: discoveryEvidence(discovery),
|
|
35
|
+
framework,
|
|
36
|
+
options,
|
|
37
|
+
out,
|
|
38
|
+
outDir: discovery.outDir,
|
|
39
|
+
scenarioName,
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const fixtureConfig = {
|
|
44
|
+
settings: {
|
|
45
|
+
early_flake_detection: {
|
|
46
|
+
enabled: true,
|
|
47
|
+
slow_test_retries: {
|
|
48
|
+
'5s': 3,
|
|
49
|
+
},
|
|
50
|
+
faulty_session_threshold: 100,
|
|
51
|
+
},
|
|
52
|
+
known_tests_enabled: true,
|
|
53
|
+
},
|
|
54
|
+
knownTests: {
|
|
55
|
+
[framework.framework]: {},
|
|
56
|
+
},
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const run = await runInstrumentedCommand({
|
|
60
|
+
framework,
|
|
61
|
+
out,
|
|
62
|
+
scenarioName,
|
|
63
|
+
command: scenario.runCommand,
|
|
64
|
+
options,
|
|
65
|
+
fixtureConfig,
|
|
66
|
+
})
|
|
67
|
+
outDir = run.outDir
|
|
68
|
+
|
|
69
|
+
const tests = testsForDiscoveredScenario(run.events, scenario, discovery)
|
|
70
|
+
const earlyFlakeRetryEvents = tests.filter(test => test.retryReason === 'early_flake_detection')
|
|
71
|
+
const externalRetryEvents = tests.filter(test => test.isRetry && test.retryReason !== 'early_flake_detection')
|
|
72
|
+
const evidence = {
|
|
73
|
+
...discoveryEvidence(discovery),
|
|
74
|
+
commandExitCode: run.result.exitCode,
|
|
75
|
+
commandTimedOut: run.result.timedOut,
|
|
76
|
+
settingsLoadedFromCache: run.offline.inputs.settings?.status === 'loaded',
|
|
77
|
+
knownTestsLoadedFromCache: run.offline.inputs.known_tests?.status === 'loaded',
|
|
78
|
+
matchingTestEvents: tests.length,
|
|
79
|
+
earlyFlakeRetryEvents: earlyFlakeRetryEvents.length,
|
|
80
|
+
externalRetryEvents: externalRetryEvents.length,
|
|
81
|
+
earlyFlakeTaggedEvents: tests.filter(test => test.earlyFlakeEnabled).length,
|
|
82
|
+
samples: testEventSamples(tests),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (run.result.exitCode !== 0) {
|
|
86
|
+
return failWithDebugRerun({
|
|
87
|
+
command: scenario.runCommand,
|
|
88
|
+
fixtureConfig,
|
|
89
|
+
diagnosis: 'The generated new-test command reported Early Flake Detection retry evidence, but the ' +
|
|
90
|
+
`command exited ${run.result.exitCode}. Early Flake Detection is only valid when the command ` +
|
|
91
|
+
'completes successfully after retries.',
|
|
92
|
+
evidence,
|
|
93
|
+
framework,
|
|
94
|
+
options,
|
|
95
|
+
out,
|
|
96
|
+
outDir,
|
|
97
|
+
scenarioName,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!evidence.settingsLoadedFromCache || !evidence.knownTestsLoadedFromCache) {
|
|
102
|
+
return failWithDebugRerun({
|
|
103
|
+
command: scenario.runCommand,
|
|
104
|
+
fixtureConfig,
|
|
105
|
+
diagnosis: 'EFD settings or known-tests data were not loaded from the offline cache fixture.',
|
|
106
|
+
evidence,
|
|
107
|
+
framework,
|
|
108
|
+
options,
|
|
109
|
+
out,
|
|
110
|
+
outDir,
|
|
111
|
+
scenarioName,
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (tests.length < 2 || earlyFlakeRetryEvents.length === 0) {
|
|
116
|
+
return failWithDebugRerun({
|
|
117
|
+
command: scenario.runCommand,
|
|
118
|
+
fixtureConfig,
|
|
119
|
+
diagnosis: 'The generated new test did not appear to be retried for Early Flake Detection.',
|
|
120
|
+
evidence,
|
|
121
|
+
framework,
|
|
122
|
+
options,
|
|
123
|
+
out,
|
|
124
|
+
outDir,
|
|
125
|
+
scenarioName,
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return pass(
|
|
130
|
+
framework,
|
|
131
|
+
scenarioName,
|
|
132
|
+
'The generated new test was reported with retry evidence for Early Flake Detection.',
|
|
133
|
+
evidence,
|
|
134
|
+
outDir
|
|
135
|
+
)
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return error(framework, scenarioName, err, outDir)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = { runEarlyFlakeDetection }
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
const { getArtifactId } = require('../artifact-id')
|
|
7
|
+
const { buildCiWiringEnv, buildDatadogEnv, runCommand } = require('../command-runner')
|
|
8
|
+
const {
|
|
9
|
+
cleanupGeneratedRuntimeFiles,
|
|
10
|
+
findGeneratedScenario,
|
|
11
|
+
writeGeneratedFiles,
|
|
12
|
+
} = require('../generated-files')
|
|
13
|
+
const {
|
|
14
|
+
eventsOfType,
|
|
15
|
+
findTestsByIdentity,
|
|
16
|
+
} = require('../payload-normalizer')
|
|
17
|
+
const { getLocalValidationCommand } = require('../local-command')
|
|
18
|
+
const { cleanupOfflineFixture, createOfflineFixture } = require('../offline-fixtures')
|
|
19
|
+
const { readOfflineOutput } = require('../offline-output')
|
|
20
|
+
const { sanitizeForReport, sanitizeString } = require('../redaction')
|
|
21
|
+
const { ensureSafeDirectory, writeFileSafely } = require('../safe-files')
|
|
22
|
+
|
|
23
|
+
const ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}${String.raw`\[[0-?]*[ -/]*[@-~]`}`, 'g')
|
|
24
|
+
|
|
25
|
+
function frameworkOutDir (out, framework, scenario) {
|
|
26
|
+
return path.join(out, 'runs', getArtifactId(framework.id), scenario)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function runInstrumentedCommand ({
|
|
30
|
+
framework,
|
|
31
|
+
out,
|
|
32
|
+
scenarioName,
|
|
33
|
+
command,
|
|
34
|
+
options,
|
|
35
|
+
extraEnv,
|
|
36
|
+
fixtureConfig,
|
|
37
|
+
ciWiring = false,
|
|
38
|
+
allowMissingInitialization = false,
|
|
39
|
+
}) {
|
|
40
|
+
const outDir = frameworkOutDir(out, framework, scenarioName)
|
|
41
|
+
const rawOutputRoot = path.join(outDir, '.offline-payloads')
|
|
42
|
+
ensureSafeDirectory(out, rawOutputRoot, 'offline validation payload output')
|
|
43
|
+
let fixture
|
|
44
|
+
let result
|
|
45
|
+
let offline
|
|
46
|
+
try {
|
|
47
|
+
fixture = createOfflineFixture({
|
|
48
|
+
approvedPlanSha256: options.approvedPlanSha256,
|
|
49
|
+
offlineFixtureNonce: options.offlineFixtureNonce,
|
|
50
|
+
framework,
|
|
51
|
+
repositoryRoot: options.repositoryRoot,
|
|
52
|
+
scenarioName,
|
|
53
|
+
...fixtureConfig,
|
|
54
|
+
})
|
|
55
|
+
const validationEnv = ciWiring
|
|
56
|
+
? buildCiWiringEnv({ fixture, outputRoot: rawOutputRoot })
|
|
57
|
+
: buildDatadogEnv({ fixture, outputRoot: rawOutputRoot, scenario: scenarioName, framework })
|
|
58
|
+
result = await runCommand(command, {
|
|
59
|
+
env: {
|
|
60
|
+
...validationEnv,
|
|
61
|
+
...extraEnv,
|
|
62
|
+
},
|
|
63
|
+
artifactRoot: out,
|
|
64
|
+
envMode: 'clean',
|
|
65
|
+
outDir,
|
|
66
|
+
label: `${framework.id}:${scenarioName}`,
|
|
67
|
+
repositoryRoot: options.repositoryRoot,
|
|
68
|
+
requireExecutableApproval: options.requireExecutableApproval,
|
|
69
|
+
verbose: options.verbose,
|
|
70
|
+
})
|
|
71
|
+
offline = readOfflineOutput(rawOutputRoot)
|
|
72
|
+
const sanitizedEvents = sanitizeForReport(offline.events)
|
|
73
|
+
writeFileSafely(
|
|
74
|
+
out,
|
|
75
|
+
path.join(outDir, 'events.ndjson'),
|
|
76
|
+
sanitizedEvents.map(event => JSON.stringify(event)).join('\n') + '\n',
|
|
77
|
+
'scenario events artifact'
|
|
78
|
+
)
|
|
79
|
+
writeFileSafely(
|
|
80
|
+
out,
|
|
81
|
+
path.join(outDir, 'result.json'),
|
|
82
|
+
`${JSON.stringify(sanitizeForReport(result), null, 2)}\n`,
|
|
83
|
+
'scenario result artifact'
|
|
84
|
+
)
|
|
85
|
+
if (!offline.initialized && !ciWiring && !allowMissingInitialization) {
|
|
86
|
+
const stderr = sanitizeString(result.stderr).trim().slice(-2000)
|
|
87
|
+
throw new Error(
|
|
88
|
+
'Offline Test Optimization exporter did not initialize or write completion evidence. ' +
|
|
89
|
+
`The test command exited ${result.exitCode}${result.signal ? ` with signal ${result.signal}` : ''}` +
|
|
90
|
+
`${result.timedOut ? ' after timing out' : ''}.${stderr ? ` Sanitized stderr tail: ${stderr}` : ''}`
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
if (offline.summary?.errors.length > 0) {
|
|
94
|
+
throw new Error(`Offline Test Optimization exporter failed: ${offline.summary.errors.join(', ')}`)
|
|
95
|
+
}
|
|
96
|
+
} catch (err) {
|
|
97
|
+
err.artifactDirectory = outDir
|
|
98
|
+
throw err
|
|
99
|
+
} finally {
|
|
100
|
+
if (fixture) cleanupOfflineFixture(fixture.root)
|
|
101
|
+
fs.rmSync(rawOutputRoot, { force: true, recursive: true })
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { result, events: offline.events, offline, outDir }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function failWithDebugRerun ({
|
|
108
|
+
command,
|
|
109
|
+
fixtureConfig,
|
|
110
|
+
diagnosis,
|
|
111
|
+
evidence,
|
|
112
|
+
framework,
|
|
113
|
+
options,
|
|
114
|
+
out,
|
|
115
|
+
outDir,
|
|
116
|
+
scenarioName,
|
|
117
|
+
skipDebug,
|
|
118
|
+
}) {
|
|
119
|
+
if (!skipDebug && command) {
|
|
120
|
+
const debugRerun = await runDebugInstrumentedCommand({
|
|
121
|
+
command,
|
|
122
|
+
fixtureConfig,
|
|
123
|
+
framework,
|
|
124
|
+
options,
|
|
125
|
+
out,
|
|
126
|
+
scenarioName,
|
|
127
|
+
})
|
|
128
|
+
evidence.debugRerun = debugRerun.summary
|
|
129
|
+
|
|
130
|
+
const failure = fail(framework, scenarioName, diagnosis, evidence, outDir)
|
|
131
|
+
if (debugRerun.artifacts) {
|
|
132
|
+
failure.artifacts.push(...debugRerun.artifacts)
|
|
133
|
+
}
|
|
134
|
+
return failure
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return fail(framework, scenarioName, diagnosis, evidence, outDir)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function runDebugInstrumentedCommand ({
|
|
141
|
+
command,
|
|
142
|
+
fixtureConfig,
|
|
143
|
+
framework,
|
|
144
|
+
options,
|
|
145
|
+
out,
|
|
146
|
+
scenarioName,
|
|
147
|
+
}) {
|
|
148
|
+
try {
|
|
149
|
+
cleanupGeneratedRuntimeFiles(framework)
|
|
150
|
+
|
|
151
|
+
const debug = await runInstrumentedCommand({
|
|
152
|
+
framework,
|
|
153
|
+
out,
|
|
154
|
+
scenarioName: `${scenarioName}-debug`,
|
|
155
|
+
command,
|
|
156
|
+
options,
|
|
157
|
+
fixtureConfig,
|
|
158
|
+
extraEnv: {
|
|
159
|
+
DD_TRACE_DEBUG: '1',
|
|
160
|
+
DD_TRACE_LOG_LEVEL: 'debug',
|
|
161
|
+
},
|
|
162
|
+
allowMissingInitialization: true,
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
summary: summarizeDebugRerun(debug),
|
|
167
|
+
artifacts: getDebugArtifacts(debug.outDir),
|
|
168
|
+
}
|
|
169
|
+
} catch (err) {
|
|
170
|
+
return {
|
|
171
|
+
summary: {
|
|
172
|
+
ran: false,
|
|
173
|
+
error: err && err.message ? err.message : String(err),
|
|
174
|
+
},
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function prepareGeneratedScenario (framework, scenarioId) {
|
|
180
|
+
const scenario = findGeneratedScenario(framework, scenarioId)
|
|
181
|
+
if (!scenario) return { scenario: null, written: [] }
|
|
182
|
+
cleanupGeneratedRuntimeFiles(framework)
|
|
183
|
+
const written = await writeGeneratedFiles(framework)
|
|
184
|
+
return {
|
|
185
|
+
scenario: {
|
|
186
|
+
...scenario,
|
|
187
|
+
runCommand: getLocalValidationCommand(framework, scenario.runCommand),
|
|
188
|
+
},
|
|
189
|
+
written,
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function requireGeneratedScenario (framework, scenarioId, scenarioName) {
|
|
194
|
+
const strategy = framework.generatedTestStrategy
|
|
195
|
+
if (strategy?.status === 'not_possible') {
|
|
196
|
+
return skip(
|
|
197
|
+
framework,
|
|
198
|
+
scenarioName,
|
|
199
|
+
`Skipped because this advanced feature is not eligible: ${strategy.reason}`,
|
|
200
|
+
getGeneratedStrategySkipEvidence(framework, scenarioName, scenarioId)
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!strategy || strategy.status !== 'verified') {
|
|
205
|
+
return incomplete(
|
|
206
|
+
framework,
|
|
207
|
+
scenarioName,
|
|
208
|
+
'The validation manifest is incomplete because no verified generated test strategy is available. ' +
|
|
209
|
+
'No conclusion was reached for this advanced feature.',
|
|
210
|
+
getGeneratedStrategySkipEvidence(framework, scenarioName, scenarioId)
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const scenario = findGeneratedScenario(framework, scenarioId)
|
|
215
|
+
if (!scenario) {
|
|
216
|
+
return incomplete(
|
|
217
|
+
framework,
|
|
218
|
+
scenarioName,
|
|
219
|
+
`The validation manifest is incomplete because generated scenario "${scenarioId}" is missing. ` +
|
|
220
|
+
'No conclusion was reached for this advanced feature.',
|
|
221
|
+
{
|
|
222
|
+
featureEligibility: {
|
|
223
|
+
eligible: false,
|
|
224
|
+
blockedBy: 'generated-scenario',
|
|
225
|
+
reasonCode: 'generated-scenario-missing',
|
|
226
|
+
scenario: scenarioName,
|
|
227
|
+
requiredGeneratedScenario: scenarioId,
|
|
228
|
+
},
|
|
229
|
+
}
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Builds stable evidence for advanced feature checks that cannot run without generated tests.
|
|
238
|
+
*
|
|
239
|
+
* @param {object} framework manifest framework entry
|
|
240
|
+
* @param {string} scenarioName advanced scenario name
|
|
241
|
+
* @param {string} scenarioId required generated scenario id
|
|
242
|
+
* @returns {object} skip evidence for reports and UI payloads
|
|
243
|
+
*/
|
|
244
|
+
function getGeneratedStrategySkipEvidence (framework, scenarioName, scenarioId) {
|
|
245
|
+
const strategy = framework.generatedTestStrategy
|
|
246
|
+
const status = strategy?.status || 'missing'
|
|
247
|
+
let reasonCode = 'generated-test-strategy-missing'
|
|
248
|
+
|
|
249
|
+
if (status === 'proposed') {
|
|
250
|
+
reasonCode = 'generated-test-strategy-proposed-only'
|
|
251
|
+
} else if (status === 'not_possible') {
|
|
252
|
+
reasonCode = 'generated-test-strategy-not-possible'
|
|
253
|
+
} else if (status !== 'missing') {
|
|
254
|
+
reasonCode = 'generated-test-strategy-not-verified'
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
featureEligibility: {
|
|
259
|
+
eligible: false,
|
|
260
|
+
blockedBy: 'generated-test-strategy',
|
|
261
|
+
reason: strategy?.reason,
|
|
262
|
+
reasonCode,
|
|
263
|
+
scenario: scenarioName,
|
|
264
|
+
strategyStatus: status,
|
|
265
|
+
requiredGeneratedScenario: scenarioId,
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function basicEventEvidence (events) {
|
|
271
|
+
return {
|
|
272
|
+
testSessionEvents: eventsOfType(events, 'test_session_end').length,
|
|
273
|
+
testModuleEvents: eventsOfType(events, 'test_module_end').length,
|
|
274
|
+
testSuiteEvents: eventsOfType(events, 'test_suite_end').length,
|
|
275
|
+
testEvents: eventsOfType(events, 'test').length,
|
|
276
|
+
samples: basicEventSamples(events),
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function hasAllBasicEventTypes (events) {
|
|
281
|
+
const evidence = basicEventEvidence(events)
|
|
282
|
+
return evidence.testSessionEvents > 0 &&
|
|
283
|
+
evidence.testModuleEvents > 0 &&
|
|
284
|
+
evidence.testSuiteEvents > 0 &&
|
|
285
|
+
evidence.testEvents > 0
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function testsForScenario (events, scenario) {
|
|
289
|
+
return findTestsByIdentity(events, scenario.testIdentities || [])
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function discoverScenarioTests ({ framework, out, scenarioName, scenario, options }) {
|
|
293
|
+
const baseline = await runInstrumentedCommand({
|
|
294
|
+
framework,
|
|
295
|
+
out,
|
|
296
|
+
scenarioName: `${scenarioName}-baseline`,
|
|
297
|
+
command: scenario.runCommand,
|
|
298
|
+
options,
|
|
299
|
+
})
|
|
300
|
+
let tests = testsForScenario(baseline.events, scenario)
|
|
301
|
+
let identityMatch = 'manifest'
|
|
302
|
+
if (tests.length === 0) {
|
|
303
|
+
const nameAndFileIdentities = (scenario.testIdentities || [])
|
|
304
|
+
.filter(identity => identity.name && identity.file)
|
|
305
|
+
tests = findTestsByIdentity(baseline.events, nameAndFileIdentities, { ignoreSuite: true })
|
|
306
|
+
if (tests.length > 0) identityMatch = 'name-and-file-fallback'
|
|
307
|
+
}
|
|
308
|
+
cleanupGeneratedRuntimeFiles(framework)
|
|
309
|
+
return {
|
|
310
|
+
...baseline,
|
|
311
|
+
identityMatch,
|
|
312
|
+
tests,
|
|
313
|
+
testIdentities: tests.map(testToIdentity),
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function testsForDiscoveredScenario (events, scenario, discovery) {
|
|
318
|
+
if (discovery?.testIdentities?.length > 0) {
|
|
319
|
+
return findTestsByIdentity(events, discovery.testIdentities)
|
|
320
|
+
}
|
|
321
|
+
return testsForScenario(events, scenario)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function discoveryEvidence (discovery) {
|
|
325
|
+
return {
|
|
326
|
+
baselineCommandExitCode: discovery.result.exitCode,
|
|
327
|
+
baselineIdentityMatch: discovery.identityMatch,
|
|
328
|
+
baselineMatchingTestEvents: discovery.tests.length,
|
|
329
|
+
baselineSamples: testEventSamples(discovery.tests),
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function testToIdentity (test) {
|
|
334
|
+
return {
|
|
335
|
+
discovered: true,
|
|
336
|
+
suite: test.testSuite,
|
|
337
|
+
name: test.testName,
|
|
338
|
+
file: test.testSourceFile,
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function basicEventSamples (events) {
|
|
343
|
+
return [
|
|
344
|
+
sampleLevel(events, 'test_session_end', 'test session'),
|
|
345
|
+
sampleLevel(events, 'test_module_end', 'test module'),
|
|
346
|
+
sampleLevel(events, 'test_suite_end', 'test suite'),
|
|
347
|
+
sampleLevel(events, 'test', 'test'),
|
|
348
|
+
].filter(Boolean)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function sampleLevel (events, type, level) {
|
|
352
|
+
const event = eventsOfType(events, type)[0]
|
|
353
|
+
if (!event) return null
|
|
354
|
+
|
|
355
|
+
const sample = { level }
|
|
356
|
+
copy(sample, event.meta, 'test.command')
|
|
357
|
+
copy(sample, event.meta, 'test.module')
|
|
358
|
+
copy(sample, event.meta, 'test.suite')
|
|
359
|
+
copy(sample, event.meta, 'test.name')
|
|
360
|
+
copy(sample, event.meta, 'test.status')
|
|
361
|
+
return sample
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function testEventSamples (tests) {
|
|
365
|
+
return tests.slice(0, 3).map(test => {
|
|
366
|
+
const sample = {}
|
|
367
|
+
copy(sample, test.meta, 'test.name')
|
|
368
|
+
copy(sample, test.meta, 'test.status')
|
|
369
|
+
copy(sample, test.meta, 'test.is_new')
|
|
370
|
+
copy(sample, test.meta, 'test.is_retry')
|
|
371
|
+
copy(sample, test.meta, 'test.retry_reason')
|
|
372
|
+
copy(sample, test.meta, 'test.final_status')
|
|
373
|
+
copy(sample, test.meta, 'test.test_management.enabled')
|
|
374
|
+
copy(sample, test.meta, 'test.test_management.is_test_disabled')
|
|
375
|
+
copy(sample, test.meta, 'test.test_management.is_quarantined')
|
|
376
|
+
copy(sample, test.meta, 'test.test_management.is_attempt_to_fix')
|
|
377
|
+
copy(sample, test.meta, 'test.test_management.attempt_to_fix_passed')
|
|
378
|
+
return sample
|
|
379
|
+
})
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function copy (target, source, key) {
|
|
383
|
+
if (source && source[key] !== undefined) target[key] = source[key]
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function summarizeDebugRerun ({ result, events, offline, outDir }) {
|
|
387
|
+
const output = `${result.stdout}\n${result.stderr}`
|
|
388
|
+
|
|
389
|
+
return {
|
|
390
|
+
ran: true,
|
|
391
|
+
commandExitCode: result.exitCode,
|
|
392
|
+
commandTimedOut: result.timedOut,
|
|
393
|
+
debugCommandFailed: result.exitCode !== 0 || result.timedOut === true,
|
|
394
|
+
offlineExporterInitialized: offline.initialized,
|
|
395
|
+
artifactDirectory: outDir,
|
|
396
|
+
...basicEventEvidence(events),
|
|
397
|
+
debugLines: findInterestingLines(output, [
|
|
398
|
+
/dd-trace/i,
|
|
399
|
+
/test optimization/i,
|
|
400
|
+
/ci visibility/i,
|
|
401
|
+
/citestcycle/i,
|
|
402
|
+
/auto.?test.?retr/i,
|
|
403
|
+
/flaky.?retr/i,
|
|
404
|
+
/\b(?:error|warn)\b/i,
|
|
405
|
+
], 20),
|
|
406
|
+
stderrExcerpt: tailInterestingLines(result.stderr),
|
|
407
|
+
stdoutExcerpt: tailInterestingLines(result.stdout),
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function getDebugArtifacts (outDir) {
|
|
412
|
+
return [
|
|
413
|
+
'command.json',
|
|
414
|
+
'stdout.txt',
|
|
415
|
+
'stderr.txt',
|
|
416
|
+
'events.ndjson',
|
|
417
|
+
'result.json',
|
|
418
|
+
].map(filename => path.join(outDir, filename))
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function findInterestingLines (output, patterns, limit = 8) {
|
|
422
|
+
return uniqueLines(output.split(/\r?\n/).map(stripAnsi).filter(line => {
|
|
423
|
+
if (/^\s*Encoding payload:/.test(line)) return false
|
|
424
|
+
return patterns.some(pattern => pattern.test(line))
|
|
425
|
+
}).map(truncateLine)).slice(0, limit)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function truncateLine (line) {
|
|
429
|
+
const maxLength = 500
|
|
430
|
+
return line.length > maxLength ? `${line.slice(0, maxLength)}...` : line
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function tailInterestingLines (output) {
|
|
434
|
+
return uniqueLines(output
|
|
435
|
+
.split(/\r?\n/)
|
|
436
|
+
.map(stripAnsi)
|
|
437
|
+
.map(line => line.trimEnd())
|
|
438
|
+
.filter(line => line.trim() !== '')
|
|
439
|
+
.filter(line => !/^\s*Encoding payload:/.test(line))
|
|
440
|
+
.map(truncateLine))
|
|
441
|
+
.slice(-12)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function stripAnsi (line) {
|
|
445
|
+
return line.replaceAll(ANSI_PATTERN, '')
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function uniqueLines (lines) {
|
|
449
|
+
const seen = new Set()
|
|
450
|
+
const unique = []
|
|
451
|
+
for (const line of lines) {
|
|
452
|
+
const normalized = line.trim()
|
|
453
|
+
if (!normalized || seen.has(normalized)) continue
|
|
454
|
+
seen.add(normalized)
|
|
455
|
+
unique.push(line)
|
|
456
|
+
}
|
|
457
|
+
return unique
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function pass (framework, scenario, diagnosis, evidence, outDir, extraArtifacts) {
|
|
461
|
+
return result(framework, scenario, 'pass', diagnosis, evidence, outDir, extraArtifacts)
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function fail (framework, scenario, diagnosis, evidence, outDir, extraArtifacts) {
|
|
465
|
+
return result(framework, scenario, 'fail', diagnosis, evidence, outDir, extraArtifacts)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function skip (framework, scenario, diagnosis, evidence = {}) {
|
|
469
|
+
return result(framework, scenario, 'skip', diagnosis, evidence, null)
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function incomplete (framework, scenario, diagnosis, evidence = {}) {
|
|
473
|
+
return result(framework, scenario, 'error', diagnosis, {
|
|
474
|
+
...evidence,
|
|
475
|
+
manifestIncomplete: true,
|
|
476
|
+
}, null)
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function inconclusive (framework, scenario, diagnosis, evidence = {}, outDir, extraArtifacts) {
|
|
480
|
+
return result(framework, scenario, 'error', diagnosis, {
|
|
481
|
+
...evidence,
|
|
482
|
+
validationIncomplete: true,
|
|
483
|
+
}, outDir, extraArtifacts)
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function error (framework, scenario, err, outDir = err?.artifactDirectory) {
|
|
487
|
+
return result(framework, scenario, 'error', err && err.stack ? err.stack : String(err), {}, outDir)
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function result (framework, scenario, status, diagnosis, evidence, outDir, extraArtifacts) {
|
|
491
|
+
const artifacts = outDir
|
|
492
|
+
? [
|
|
493
|
+
path.join(outDir, 'command.json'),
|
|
494
|
+
path.join(outDir, 'stdout.txt'),
|
|
495
|
+
path.join(outDir, 'stderr.txt'),
|
|
496
|
+
path.join(outDir, 'events.ndjson'),
|
|
497
|
+
path.join(outDir, 'result.json'),
|
|
498
|
+
]
|
|
499
|
+
: []
|
|
500
|
+
|
|
501
|
+
if (Array.isArray(extraArtifacts)) {
|
|
502
|
+
artifacts.push(...extraArtifacts)
|
|
503
|
+
} else if (extraArtifacts && typeof extraArtifacts === 'object') {
|
|
504
|
+
artifacts.push(...Object.values(extraArtifacts).filter(Boolean))
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return {
|
|
508
|
+
frameworkId: framework.id,
|
|
509
|
+
scenario,
|
|
510
|
+
status,
|
|
511
|
+
diagnosis,
|
|
512
|
+
evidence,
|
|
513
|
+
artifacts,
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
module.exports = {
|
|
518
|
+
basicEventEvidence,
|
|
519
|
+
discoverScenarioTests,
|
|
520
|
+
discoveryEvidence,
|
|
521
|
+
error,
|
|
522
|
+
fail,
|
|
523
|
+
failWithDebugRerun,
|
|
524
|
+
findInterestingLines,
|
|
525
|
+
frameworkOutDir,
|
|
526
|
+
hasAllBasicEventTypes,
|
|
527
|
+
incomplete,
|
|
528
|
+
inconclusive,
|
|
529
|
+
pass,
|
|
530
|
+
prepareGeneratedScenario,
|
|
531
|
+
requireGeneratedScenario,
|
|
532
|
+
runDebugInstrumentedCommand,
|
|
533
|
+
runInstrumentedCommand,
|
|
534
|
+
skip,
|
|
535
|
+
testEventSamples,
|
|
536
|
+
tailInterestingLines,
|
|
537
|
+
testsForDiscoveredScenario,
|
|
538
|
+
testsForScenario,
|
|
539
|
+
}
|