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.
Files changed (272) hide show
  1. package/ci/diagnose.js +27 -25
  2. package/ci/init.js +6 -6
  3. package/ci/runbook.md +114 -20
  4. package/ci/test-optimization-validation/approval-artifacts.js +36 -3
  5. package/ci/test-optimization-validation/approval.js +78 -22
  6. package/ci/test-optimization-validation/blocker-category.js +24 -0
  7. package/ci/test-optimization-validation/ci-discovery.js +23 -17
  8. package/ci/test-optimization-validation/ci-package-scripts.js +34 -6
  9. package/ci/test-optimization-validation/ci-remediation.js +1 -1
  10. package/ci/test-optimization-validation/cli.js +280 -52
  11. package/ci/test-optimization-validation/command-blocker.js +159 -20
  12. package/ci/test-optimization-validation/command-output-policy.js +14 -8
  13. package/ci/test-optimization-validation/command-runner.js +9 -7
  14. package/ci/test-optimization-validation/environment.js +4 -2
  15. package/ci/test-optimization-validation/executable.js +15 -13
  16. package/ci/test-optimization-validation/execution-lock.js +70 -0
  17. package/ci/test-optimization-validation/framework-adapters/cucumber-validation.json +3 -0
  18. package/ci/test-optimization-validation/framework-adapters/cucumber.js +657 -5
  19. package/ci/test-optimization-validation/framework-adapters/playwright.js +5 -5
  20. package/ci/test-optimization-validation/framework-adapters/vitest.js +517 -0
  21. package/ci/test-optimization-validation/generated-files.js +47 -37
  22. package/ci/test-optimization-validation/generated-test-contract.js +9 -7
  23. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  24. package/ci/test-optimization-validation/literal-glob.js +52 -0
  25. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  26. package/ci/test-optimization-validation/manifest-scaffold.js +301 -52
  27. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  28. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  29. package/ci/test-optimization-validation/offline-output.js +6 -6
  30. package/ci/test-optimization-validation/package-check.js +94 -0
  31. package/ci/test-optimization-validation/plan-writer.js +183 -10
  32. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  33. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  34. package/ci/test-optimization-validation/redaction.js +18 -27
  35. package/ci/test-optimization-validation/report-writer.js +182 -48
  36. package/ci/test-optimization-validation/result-semantics.js +20 -3
  37. package/ci/test-optimization-validation/runner-command.js +41 -21
  38. package/ci/test-optimization-validation/runner-contract.js +79 -43
  39. package/ci/test-optimization-validation/safe-files.js +4 -4
  40. package/ci/test-optimization-validation/scenarios/basic-reporting.js +60 -6
  41. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  42. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  43. package/ci/test-optimization-validation/scenarios/test-management.js +2 -2
  44. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  45. package/ci/test-optimization-validation/test-output.js +2 -1
  46. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  47. package/ci/vitest-no-worker-init-setup.mjs +377 -84
  48. package/index.d.ts +175 -14
  49. package/init.js +1 -17
  50. package/initialize.mjs +11 -0
  51. package/loader-hook.mjs +6 -4
  52. package/package.json +12 -4
  53. package/packages/datadog-core/src/utils/src/kebabcase.js +8 -2
  54. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  55. package/packages/datadog-esbuild/index.js +4 -2
  56. package/packages/datadog-esbuild/src/utils.js +17 -2
  57. package/packages/datadog-instrumentations/src/ai.js +61 -34
  58. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  59. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +85 -9
  60. package/packages/datadog-instrumentations/src/cucumber.js +131 -51
  61. package/packages/datadog-instrumentations/src/dns.js +21 -2
  62. package/packages/datadog-instrumentations/src/electron.js +1 -0
  63. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  64. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  65. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  66. package/packages/datadog-instrumentations/src/helpers/extract-package-and-module-path.js +10 -0
  67. package/packages/datadog-instrumentations/src/helpers/hook.js +19 -2
  68. package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
  69. package/packages/datadog-instrumentations/src/helpers/register.js +9 -3
  70. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  71. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  72. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +175 -0
  73. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  74. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  75. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +61 -0
  76. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +50 -18
  77. package/packages/datadog-instrumentations/src/helpers/router-helper.js +38 -7
  78. package/packages/datadog-instrumentations/src/helpers/shared-utils.js +39 -0
  79. package/packages/datadog-instrumentations/src/http/client.js +1 -3
  80. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  81. package/packages/datadog-instrumentations/src/jest.js +986 -246
  82. package/packages/datadog-instrumentations/src/mocha/common.js +1 -3
  83. package/packages/datadog-instrumentations/src/mocha/main.js +109 -51
  84. package/packages/datadog-instrumentations/src/mocha/utils.js +120 -32
  85. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +44 -0
  86. package/packages/datadog-instrumentations/src/mocha/worker.js +441 -43
  87. package/packages/datadog-instrumentations/src/moleculer/client.js +1 -1
  88. package/packages/datadog-instrumentations/src/mysql.js +1 -1
  89. package/packages/datadog-instrumentations/src/next.js +155 -23
  90. package/packages/datadog-instrumentations/src/openai.js +14 -0
  91. package/packages/datadog-instrumentations/src/pg.js +180 -6
  92. package/packages/datadog-instrumentations/src/playwright.js +176 -81
  93. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  94. package/packages/datadog-instrumentations/src/promise.js +3 -3
  95. package/packages/datadog-instrumentations/src/rhea.js +1 -1
  96. package/packages/datadog-instrumentations/src/router.js +195 -19
  97. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +567 -65
  98. package/packages/datadog-instrumentations/src/vitest-main.js +438 -54
  99. package/packages/datadog-instrumentations/src/vitest-util.js +42 -7
  100. package/packages/datadog-instrumentations/src/vitest-worker.js +234 -17
  101. package/packages/datadog-instrumentations/src/webdriverio.js +1090 -0
  102. package/packages/datadog-instrumentations/src/when.js +3 -3
  103. package/packages/datadog-instrumentations/src/ws.js +5 -1
  104. package/packages/datadog-plugin-aerospike/src/index.js +1 -3
  105. package/packages/datadog-plugin-amqplib/src/client.js +1 -1
  106. package/packages/datadog-plugin-amqplib/src/producer.js +1 -1
  107. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  108. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  109. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +2 -2
  110. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -3
  111. package/packages/datadog-plugin-azure-service-bus/src/producer.js +5 -3
  112. package/packages/datadog-plugin-bullmq/src/producer.js +3 -3
  113. package/packages/datadog-plugin-child_process/src/index.js +3 -3
  114. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -11
  115. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  116. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +50 -46
  117. package/packages/datadog-plugin-cypress/src/source-map-utils.js +1 -1
  118. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  119. package/packages/datadog-plugin-electron/src/net.js +10 -4
  120. package/packages/datadog-plugin-fastify/src/tracing.js +1 -1
  121. package/packages/datadog-plugin-fs/src/index.js +0 -4
  122. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +14 -7
  123. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +19 -10
  124. package/packages/datadog-plugin-graphql/src/execute.js +1 -0
  125. package/packages/datadog-plugin-graphql/src/tools/signature.js +1 -1
  126. package/packages/datadog-plugin-http/src/client.js +3 -2
  127. package/packages/datadog-plugin-http2/src/client.js +1 -1
  128. package/packages/datadog-plugin-jest/src/index.js +3 -21
  129. package/packages/datadog-plugin-jest/src/util.js +4 -1
  130. package/packages/datadog-plugin-kafkajs/src/producer.js +2 -1
  131. package/packages/datadog-plugin-langchain/src/tokens.js +2 -2
  132. package/packages/datadog-plugin-mocha/src/index.js +342 -6
  133. package/packages/datadog-plugin-next/src/index.js +57 -9
  134. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  135. package/packages/datadog-plugin-pg/src/index.js +65 -1
  136. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  137. package/packages/datadog-plugin-prisma/src/index.js +5 -1
  138. package/packages/datadog-plugin-rhea/src/consumer.js +16 -13
  139. package/packages/datadog-plugin-rhea/src/producer.js +1 -1
  140. package/packages/datadog-plugin-undici/src/index.js +2 -1
  141. package/packages/datadog-plugin-vitest/src/index.js +179 -18
  142. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  143. package/packages/datadog-webpack/index.js +2 -2
  144. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  145. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  146. package/packages/dd-trace/src/appsec/downstream_requests.js +1 -1
  147. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  148. package/packages/dd-trace/src/appsec/handlers/http-request.js +215 -0
  149. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  150. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  151. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  152. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +1 -1
  153. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +1 -1
  154. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  155. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +1 -1
  156. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -3
  157. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
  158. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -2
  159. package/packages/dd-trace/src/appsec/index.js +48 -476
  160. package/packages/dd-trace/src/appsec/sdk/track_event.js +10 -1
  161. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  162. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  163. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  164. package/packages/dd-trace/src/ci-visibility/exporters/ci-validation/sink.js +7 -6
  165. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +29 -15
  166. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +19 -1
  167. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +25 -1
  168. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/webdriverio.js +26 -0
  169. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -1
  170. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  171. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  172. package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -3
  173. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  174. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +2 -2
  175. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  176. package/packages/dd-trace/src/config/defaults.js +14 -6
  177. package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -2
  178. package/packages/dd-trace/src/config/helper.js +2 -0
  179. package/packages/dd-trace/src/config/index.js +31 -5
  180. package/packages/dd-trace/src/config/parsers.js +19 -1
  181. package/packages/dd-trace/src/config/remote_config.js +1 -1
  182. package/packages/dd-trace/src/config/supported-configurations.json +13 -6
  183. package/packages/dd-trace/src/datastreams/encoding.js +3 -4
  184. package/packages/dd-trace/src/debugger/devtools_client/log.js +2 -1
  185. package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +1 -4
  186. package/packages/dd-trace/src/debugger/devtools_client/send.js +1 -2
  187. package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +2 -2
  188. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +16 -2
  189. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  190. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  191. package/packages/dd-trace/src/encode/tags-processors.js +2 -2
  192. package/packages/dd-trace/src/exporters/common/url.js +3 -5
  193. package/packages/dd-trace/src/exporters/electron/index.js +4 -1
  194. package/packages/dd-trace/src/external-logger/src/index.js +1 -2
  195. package/packages/dd-trace/src/flare/index.js +2 -2
  196. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  197. package/packages/dd-trace/src/guardrails/log.js +1 -10
  198. package/packages/dd-trace/src/id.js +1 -1
  199. package/packages/dd-trace/src/llmobs/constants/tags.js +1 -1
  200. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  201. package/packages/dd-trace/src/llmobs/experiments/client.js +4 -2
  202. package/packages/dd-trace/src/llmobs/experiments/dataset.js +66 -14
  203. package/packages/dd-trace/src/llmobs/experiments/experiment.js +289 -95
  204. package/packages/dd-trace/src/llmobs/experiments/index.js +66 -19
  205. package/packages/dd-trace/src/llmobs/experiments/noop.js +95 -10
  206. package/packages/dd-trace/src/llmobs/experiments/result.js +13 -2
  207. package/packages/dd-trace/src/llmobs/experiments/util.js +220 -0
  208. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  209. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  210. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  211. package/packages/dd-trace/src/llmobs/plugins/anthropic/index.js +1 -1
  212. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  213. package/packages/dd-trace/src/llmobs/plugins/claude-agent-sdk/index.js +1 -1
  214. package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
  215. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
  216. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  217. package/packages/dd-trace/src/llmobs/sdk.js +152 -78
  218. package/packages/dd-trace/src/llmobs/span_processor.js +9 -7
  219. package/packages/dd-trace/src/llmobs/tagger.js +1 -2
  220. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  221. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  222. package/packages/dd-trace/src/llmobs/writers/spans.js +12 -6
  223. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  224. package/packages/dd-trace/src/log/channels.js +1 -9
  225. package/packages/dd-trace/src/log/levels.js +12 -0
  226. package/packages/dd-trace/src/noop/proxy.js +2 -2
  227. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  228. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  229. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  230. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  231. package/packages/dd-trace/src/opentelemetry/metrics/otlp_transformer.js +1 -1
  232. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +3 -2
  233. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  234. package/packages/dd-trace/src/opentracing/span.js +1 -1
  235. package/packages/dd-trace/src/opentracing/span_context.js +1 -1
  236. package/packages/dd-trace/src/plugins/ci_plugin.js +124 -23
  237. package/packages/dd-trace/src/plugins/index.js +2 -0
  238. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  239. package/packages/dd-trace/src/plugins/tracing.js +1 -0
  240. package/packages/dd-trace/src/plugins/util/ci.js +13 -6
  241. package/packages/dd-trace/src/plugins/util/git.js +7 -5
  242. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +3 -3
  243. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  244. package/packages/dd-trace/src/plugins/util/llm.js +2 -2
  245. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  246. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  247. package/packages/dd-trace/src/plugins/util/test.js +356 -86
  248. package/packages/dd-trace/src/plugins/util/url.js +5 -5
  249. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -1
  250. package/packages/dd-trace/src/plugins/util/web.js +24 -2
  251. package/packages/dd-trace/src/priority_sampler.js +6 -3
  252. package/packages/dd-trace/src/profiler.js +1 -1
  253. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  254. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  255. package/packages/dd-trace/src/profiling/profilers/poisson.js +1 -1
  256. package/packages/dd-trace/src/profiling/profilers/shared.js +2 -2
  257. package/packages/dd-trace/src/proxy.js +1 -0
  258. package/packages/dd-trace/src/ritm.js +10 -20
  259. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  260. package/packages/dd-trace/src/sampling_rule.js +4 -2
  261. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  262. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  263. package/packages/dd-trace/src/startup-log.js +3 -0
  264. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  265. package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -1
  266. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  267. package/packages/dd-trace/src/util.js +16 -0
  268. package/vendor/dist/@apm-js-collab/code-transformer/index.js +12 -12
  269. package/vendor/dist/pprof-format/index.js +1 -1
  270. package/vendor/dist/source-map/index.js +1 -1
  271. package/version.js +10 -8
  272. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -2,6 +2,9 @@
2
2
 
3
3
  const { addHook, channel } = require('../helpers/instrument')
4
4
  const shimmer = require('../../../datadog-shimmer')
5
+ const { EMPTY_EFD_RETRY_POLICY } = require('../../../dd-trace/src/ci-visibility/efd-retry-policy')
6
+ const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
7
+ const log = require('../../../dd-trace/src/log')
5
8
  const { DD_MAJOR } = require('../../../../version')
6
9
 
7
10
  const {
@@ -14,14 +17,344 @@ const {
14
17
  getOnTestRetryHandler,
15
18
  getRunTestsWrapper,
16
19
  patchFailedTestReplayHookUp,
20
+ adjustRunnerFailuresForTestOptimization,
21
+ efdTests,
22
+ getTestFullName,
17
23
  } = require('./utils')
24
+ const {
25
+ CONFIGURATION_REQUEST,
26
+ CONFIGURATION_RESPONSE,
27
+ sendWebdriverioWorkerMessage,
28
+ SUITE_FINISH,
29
+ WEBDRIVERIO_WORKER_ENV,
30
+ WORKER_READY,
31
+ } = require('./webdriverio-protocol')
18
32
  require('./common')
19
33
 
20
34
  const MINIMUM_MOCHA_VERSION = DD_MAJOR >= 6 ? '>=8.0.0' : '>=5.2.0'
21
35
 
22
36
  const workerFinishCh = channel('ci:mocha:worker:finish')
37
+ const workerConfigurationCh = channel('ci:mocha:worker:configuration')
38
+
39
+ const config = {
40
+ earlyFlakeDetectionRetryPolicy: EMPTY_EFD_RETRY_POLICY,
41
+ }
42
+ const runnerToFiles = new WeakMap()
43
+ const runnerToFailedHooks = new WeakMap()
44
+ const isWebdriverioWorker = !!getEnvironmentVariable(WEBDRIVERIO_WORKER_ENV)
45
+ let configurationRequestId = 0
46
+
47
+ /**
48
+ * Sends a message to the WebdriverIO launcher without surfacing closed IPC channels.
49
+ *
50
+ * @param {object} message
51
+ * @param {() => void} [onError]
52
+ * @param {() => void} [onDone]
53
+ * @returns {void}
54
+ */
55
+ function sendWebdriverioMessage (message, onError, onDone) {
56
+ sendWebdriverioWorkerMessage(message, error => {
57
+ if (error) {
58
+ log.error('WebdriverIO Test Optimization IPC error', error)
59
+ }
60
+ onError?.()
61
+ }, onDone)
62
+ }
63
+
64
+ /**
65
+ * Applies configuration encoded as private Mocha options by its parallel runner.
66
+ *
67
+ * @param {object} options
68
+ * @returns {void}
69
+ */
70
+ function applyMochaOptions (options) {
71
+ if (options._ddIsKnownTestsEnabled) {
72
+ config.isKnownTestsEnabled = true
73
+ config.isEarlyFlakeDetectionEnabled = options._ddIsEfdEnabled
74
+ config.knownTests = options._ddKnownTests
75
+ config.earlyFlakeDetectionRetryPolicy = options._ddEfdRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
76
+ delete options._ddIsEfdEnabled
77
+ delete options._ddKnownTests
78
+ delete options._ddEfdRetryPolicy
79
+ delete options._ddIsKnownTestsEnabled
80
+ }
81
+ if (options._ddIsImpactedTestsEnabled) {
82
+ config.isImpactedTestsEnabled = true
83
+ config.modifiedFiles = options._ddModifiedFiles
84
+ delete options._ddIsImpactedTestsEnabled
85
+ delete options._ddModifiedFiles
86
+ }
87
+ if (options._ddIsTestManagementTestsEnabled) {
88
+ config.isTestManagementTestsEnabled = true
89
+ config.testManagementAttemptToFixRetries = options._ddTestManagementAttemptToFixRetries
90
+ config.testManagementTests = options._ddTestManagementTests
91
+ delete options._ddIsTestManagementTestsEnabled
92
+ delete options._ddTestManagementAttemptToFixRetries
93
+ delete options._ddTestManagementTests
94
+ }
95
+ if (options._ddIsFlakyTestRetriesEnabled) {
96
+ config.isFlakyTestRetriesEnabled = true
97
+ config.flakyTestRetriesCount = options._ddFlakyTestRetriesCount
98
+ delete options._ddIsFlakyTestRetriesEnabled
99
+ delete options._ddFlakyTestRetriesCount
100
+ }
101
+ if (options._ddIsFailedTestReplayEnabled) {
102
+ config.isTestDynamicInstrumentationEnabled = true
103
+ config.isDiEnabled = true
104
+ delete options._ddIsFailedTestReplayEnabled
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Removes files selected for suite-level skipping from an already loaded Mocha root suite.
110
+ *
111
+ * @param {object} runner
112
+ * @param {string[]} skippedFiles
113
+ * @returns {void}
114
+ */
115
+ function filterSkippedFiles (runner, skippedFiles) {
116
+ if (!skippedFiles.length) {
117
+ return
118
+ }
119
+
120
+ const skippedFilesSet = new Set(skippedFiles)
121
+ runner.suite.suites = runner.suite.suites.filter(suite => !skippedFilesSet.has(suite.file))
122
+ runner.suite.tests = runner.suite.tests.filter(test => !skippedFilesSet.has(test.file))
123
+ }
124
+
125
+ /**
126
+ * Requests configuration from the WebdriverIO launcher before releasing Mocha's delayed root suite.
127
+ *
128
+ * @param {string} frameworkVersion
129
+ * @param {string[]} files
130
+ * @param {(response: object) => void} onDone
131
+ * @returns {void}
132
+ */
133
+ function requestWebdriverioConfiguration (frameworkVersion, files, onDone) {
134
+ const requestId = `${process.pid}-${++configurationRequestId}`
135
+ let finished = false
136
+
137
+ /**
138
+ * Finishes the configuration request exactly once.
139
+ *
140
+ * @param {object} response
141
+ * @returns {void}
142
+ */
143
+ function finish (response) {
144
+ if (finished) {
145
+ return
146
+ }
147
+ finished = true
148
+ clearTimeout(timeout)
149
+ process.off('message', onMessage)
150
+ process.off('disconnect', onDisconnect)
151
+ onDone(response)
152
+ }
153
+
154
+ /**
155
+ * Receives the matching coordinator response.
156
+ *
157
+ * @param {object} message
158
+ * @returns {void}
159
+ */
160
+ function onMessage (message) {
161
+ if (message?.name === CONFIGURATION_RESPONSE && message.content?.requestId === requestId) {
162
+ finish(message.content)
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Releases the runner if its parent disconnects.
168
+ *
169
+ * @returns {void}
170
+ */
171
+ function onDisconnect () {
172
+ finish({})
173
+ }
174
+
175
+ const timeout = setTimeout(() => finish({}), 30_000)
176
+ process.on('message', onMessage)
177
+ process.once('disconnect', onDisconnect)
178
+ sendWebdriverioMessage({
179
+ origin: 'datadog',
180
+ name: CONFIGURATION_REQUEST,
181
+ content: {
182
+ files,
183
+ frameworkVersion,
184
+ requestId,
185
+ },
186
+ }, () => finish({}))
187
+ }
188
+
189
+ /**
190
+ * Reports the Mocha version as soon as WebdriverIO loads its framework adapter.
191
+ *
192
+ * @param {string} frameworkVersion
193
+ * @returns {void}
194
+ */
195
+ function reportWebdriverioWorkerReady (frameworkVersion) {
196
+ if (!isWebdriverioWorker) {
197
+ return
198
+ }
199
+
200
+ sendWebdriverioMessage({
201
+ origin: 'datadog',
202
+ name: WORKER_READY,
203
+ content: { frameworkVersion },
204
+ })
205
+ }
206
+
207
+ /**
208
+ * Checks whether Test Optimization converts a failed WebdriverIO test attempt to a passing result.
209
+ *
210
+ * @param {object|undefined} test
211
+ * @returns {boolean}
212
+ */
213
+ function isWebdriverioFailureSuppressed (test) {
214
+ if (!test) {
215
+ return false
216
+ }
217
+ const hasPassingEfdAttempt = config.isEarlyFlakeDetectionEnabled &&
218
+ efdTests[getTestFullName(test)]?.some(attempt => attempt.state === 'passed' && !attempt._ddHookFailed)
219
+ return (test._ddIsQuarantined && !test._ddIsAttemptToFix) || hasPassingEfdAttempt
220
+ }
221
+
222
+ /**
223
+ * Gets the test owned by a per-test hook without associating suite hooks with boundary tests.
224
+ *
225
+ * @param {object} hook
226
+ * @returns {object|undefined}
227
+ */
228
+ function getWebdriverioHookTest (hook) {
229
+ const { parent } = hook
230
+ const isTestHook = parent?._beforeEach?.includes(hook) || parent?._afterEach?.includes(hook)
231
+ return isTestHook ? hook.ctx?.currentTest : undefined
232
+ }
233
+
234
+ /**
235
+ * Removes managed hook failures from WebdriverIO's Mocha runner totals.
236
+ *
237
+ * @param {object} runner
238
+ * @returns {void}
239
+ */
240
+ function adjustWebdriverioHookFailures (runner) {
241
+ let suppressedFailures = 0
242
+ for (const { test } of runnerToFailedHooks.get(runner)) {
243
+ if (isWebdriverioFailureSuppressed(test)) {
244
+ suppressedFailures++
245
+ }
246
+ }
247
+ if (runner.stats) {
248
+ runner.stats.failures -= suppressedFailures
249
+ }
250
+ runner.failures -= suppressedFailures
251
+ }
252
+
253
+ /**
254
+ * Computes a final result for every file loaded into one Mocha worker.
255
+ *
256
+ * @param {object} runner
257
+ * @returns {object[]}
258
+ */
259
+ function getWebdriverioSuiteResults (runner) {
260
+ const resultsByFile = new Map()
261
+ const files = runnerToFiles.get(runner) || []
262
+
263
+ for (const file of files) {
264
+ resultsByFile.set(file, {
265
+ file,
266
+ hasPassingTest: false,
267
+ status: 'skip',
268
+ })
269
+ }
23
270
 
24
- const config = {}
271
+ runner.suite.eachTest(test => {
272
+ const result = resultsByFile.get(test.file)
273
+ if (!result) {
274
+ return
275
+ }
276
+ const isSuppressedFailure = isWebdriverioFailureSuppressed(test)
277
+ if ((test.state === 'failed' || test.timedOut || test._ddHookFailed) && !isSuppressedFailure) {
278
+ result.status = 'fail'
279
+ } else if (test.state === 'passed' || isSuppressedFailure) {
280
+ result.hasPassingTest = true
281
+ }
282
+ })
283
+
284
+ for (const { file, test } of runnerToFailedHooks.get(runner)) {
285
+ const result = resultsByFile.get(file)
286
+ if (result && !isWebdriverioFailureSuppressed(test)) {
287
+ result.status = 'fail'
288
+ }
289
+ }
290
+
291
+ const results = []
292
+ let hasFailedSuite = false
293
+ for (const result of resultsByFile.values()) {
294
+ if (result.status === 'fail') {
295
+ hasFailedSuite = true
296
+ } else if (result.hasPassingTest) {
297
+ result.status = 'pass'
298
+ }
299
+ delete result.hasPassingTest
300
+ results.push(result)
301
+ }
302
+
303
+ if (runner.failures > 0 && !hasFailedSuite) {
304
+ for (const result of results) {
305
+ result.status = 'fail'
306
+ }
307
+ }
308
+
309
+ return results
310
+ }
311
+
312
+ /**
313
+ * Sends suite results to the WebdriverIO launcher.
314
+ *
315
+ * @param {object} runner
316
+ * @param {() => void} [onDone]
317
+ * @returns {void}
318
+ */
319
+ function reportWebdriverioSuiteResults (runner, onDone) {
320
+ if (!isWebdriverioWorker) {
321
+ onDone?.()
322
+ return
323
+ }
324
+
325
+ sendWebdriverioMessage({
326
+ origin: 'datadog',
327
+ name: SUITE_FINISH,
328
+ content: {
329
+ results: getWebdriverioSuiteResults(runner),
330
+ },
331
+ }, undefined, onDone)
332
+ }
333
+
334
+ /**
335
+ * Flushes worker payloads before reporting suite results and completing Mocha.
336
+ *
337
+ * @param {object} runner
338
+ * @param {() => void} onDone
339
+ * @returns {void}
340
+ */
341
+ function finishWebdriverioWorker (runner, onDone) {
342
+ try {
343
+ workerFinishCh.publish({
344
+ onDone: () => {
345
+ try {
346
+ reportWebdriverioSuiteResults(runner, onDone)
347
+ } catch (error) {
348
+ log.error('WebdriverIO Test Optimization worker completion error', error)
349
+ onDone()
350
+ }
351
+ },
352
+ })
353
+ } catch (error) {
354
+ log.error('WebdriverIO Test Optimization worker completion error', error)
355
+ onDone()
356
+ }
357
+ }
25
358
 
26
359
  function isFailedTestReplayEnabled () {
27
360
  return config.isTestDynamicInstrumentationEnabled && config.isDiEnabled
@@ -31,46 +364,77 @@ addHook({
31
364
  name: 'mocha',
32
365
  versions: ['>=8.0.0'],
33
366
  file: 'lib/mocha.js',
34
- }, (Mocha) => {
367
+ }, (Mocha, frameworkVersion) => {
368
+ reportWebdriverioWorkerReady(frameworkVersion)
369
+
35
370
  shimmer.wrap(Mocha.prototype, 'run', run => function (...args) {
36
- if (this.options._ddIsKnownTestsEnabled) {
37
- config.isKnownTestsEnabled = true
38
- config.isEarlyFlakeDetectionEnabled = this.options._ddIsEfdEnabled
39
- config.knownTests = this.options._ddKnownTests
40
- config.earlyFlakeDetectionNumRetries = this.options._ddEfdNumRetries
41
- config.earlyFlakeDetectionSlowTestRetries = this.options._ddEfdSlowTestRetries ?? {}
42
- delete this.options._ddIsEfdEnabled
43
- delete this.options._ddKnownTests
44
- delete this.options._ddEfdNumRetries
45
- delete this.options._ddEfdSlowTestRetries
46
- delete this.options._ddIsKnownTestsEnabled
47
- }
48
- if (this.options._ddIsImpactedTestsEnabled) {
49
- config.isImpactedTestsEnabled = true
50
- config.modifiedFiles = this.options._ddModifiedFiles
51
- delete this.options._ddIsImpactedTestsEnabled
52
- delete this.options._ddModifiedFiles
53
- }
54
- if (this.options._ddIsTestManagementTestsEnabled) {
55
- config.isTestManagementTestsEnabled = true
56
- config.testManagementAttemptToFixRetries = this.options._ddTestManagementAttemptToFixRetries
57
- config.testManagementTests = this.options._ddTestManagementTests
58
- delete this.options._ddIsTestManagementTestsEnabled
59
- delete this.options._ddTestManagementAttemptToFixRetries
60
- delete this.options._ddTestManagementTests
61
- }
62
- if (this.options._ddIsFlakyTestRetriesEnabled) {
63
- config.isFlakyTestRetriesEnabled = true
64
- config.flakyTestRetriesCount = this.options._ddFlakyTestRetriesCount
65
- delete this.options._ddIsFlakyTestRetriesEnabled
66
- delete this.options._ddFlakyTestRetriesCount
67
- }
68
- if (this.options._ddIsFailedTestReplayEnabled) {
69
- config.isTestDynamicInstrumentationEnabled = true
70
- config.isDiEnabled = true
71
- delete this.options._ddIsFailedTestReplayEnabled
371
+ applyMochaOptions(this.options)
372
+ if (!isWebdriverioWorker || !workerFinishCh.hasSubscribers) {
373
+ return run.apply(this, args)
72
374
  }
73
- return run.apply(this, args)
375
+
376
+ const isUserDelayed = this.options.delay
377
+ const rootSuite = this.suite
378
+ const rootSuiteRun = rootSuite.run
379
+ const hasOwnRootSuiteRun = Object.hasOwn(rootSuite, 'run')
380
+ let configurationReady = false
381
+ let userReady = !isUserDelayed
382
+
383
+ /**
384
+ * Restores the root suite method after both delayed-mode gates are open.
385
+ *
386
+ * @returns {void}
387
+ */
388
+ function restoreRootSuiteRun () {
389
+ if (hasOwnRootSuiteRun) {
390
+ rootSuite.run = rootSuiteRun
391
+ } else {
392
+ delete rootSuite.run
393
+ }
394
+ }
395
+
396
+ if (isUserDelayed) {
397
+ rootSuite.run = function (...args) {
398
+ userReady = true
399
+ if (!configurationReady) {
400
+ return
401
+ }
402
+ restoreRootSuiteRun()
403
+ return rootSuiteRun.apply(this, args)
404
+ }
405
+ }
406
+
407
+ this.options.delay = true
408
+ const files = [...this.files]
409
+ const runner = run.apply(this, args)
410
+ runnerToFiles.set(runner, files)
411
+
412
+ requestWebdriverioConfiguration(frameworkVersion, files, ({
413
+ configuration,
414
+ skippedFiles = [],
415
+ }) => {
416
+ if (configuration) {
417
+ Object.assign(config, configuration)
418
+ workerConfigurationCh.publish({
419
+ libraryConfig: config,
420
+ repositoryRoot: config.repositoryRoot,
421
+ testFramework: config.testFramework,
422
+ })
423
+ }
424
+ filterSkippedFiles(runner, skippedFiles)
425
+ if (isFailedTestReplayEnabled()) {
426
+ patchFailedTestReplayHookUp(runner.constructor)
427
+ }
428
+ configurationReady = true
429
+ if (userReady) {
430
+ if (isUserDelayed) {
431
+ restoreRootSuiteRun()
432
+ }
433
+ rootSuite.run()
434
+ }
435
+ })
436
+
437
+ return runner
74
438
  })
75
439
 
76
440
  return Mocha
@@ -91,10 +455,32 @@ addHook({
91
455
  if (isFailedTestReplayEnabled()) {
92
456
  patchFailedTestReplayHookUp(Runner)
93
457
  }
94
- // We flush when the worker ends with its test file (a mocha instance in a worker runs a single test file)
95
- this.once('end', () => {
96
- workerFinishCh.publish()
97
- })
458
+ if (isWebdriverioWorker) {
459
+ this.prependOnceListener('end', () => {
460
+ try {
461
+ adjustRunnerFailuresForTestOptimization(this, config)
462
+ adjustWebdriverioHookFailures(this)
463
+ } catch (error) {
464
+ log.error('WebdriverIO Test Optimization failure adjustment error', error)
465
+ }
466
+ })
467
+ }
468
+ const onRunDone = args[0]
469
+ if (isWebdriverioWorker && typeof onRunDone === 'function') {
470
+ args[0] = (...onRunDoneArgs) => {
471
+ finishWebdriverioWorker(this, () => onRunDone(...onRunDoneArgs))
472
+ }
473
+ } else {
474
+ // Flush after the worker finishes its Mocha run, including grouped spec files.
475
+ this.once('end', () => {
476
+ try {
477
+ workerFinishCh.publish()
478
+ reportWebdriverioSuiteResults(this)
479
+ } catch (error) {
480
+ log.error('WebdriverIO Test Optimization worker completion error', error)
481
+ }
482
+ })
483
+ }
98
484
  this.on('test', getOnTestHandler(false))
99
485
 
100
486
  this.on('test end', getOnTestEndHandler(config))
@@ -104,6 +490,18 @@ addHook({
104
490
  // If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
105
491
  this.on('hook end', getOnHookEndHandler(config))
106
492
 
493
+ if (isWebdriverioWorker) {
494
+ const failedHooks = []
495
+ runnerToFailedHooks.set(this, failedHooks)
496
+ this.on('fail', runnable => {
497
+ if (runnable.type === 'hook' && runnable.file) {
498
+ failedHooks.push({
499
+ file: runnable.file,
500
+ test: getWebdriverioHookTest(runnable),
501
+ })
502
+ }
503
+ })
504
+ }
107
505
  this.on('fail', getOnFailHandler(false, config))
108
506
 
109
507
  this.on('pending', getOnPendingHandler())
@@ -10,7 +10,7 @@ const errorChannel = channel('apm:moleculer:call:error')
10
10
  function wrapCall (call) {
11
11
  return function (actionName, params, opts) {
12
12
  opts = arguments[2] = opts || {}
13
- opts.meta = opts.meta || {}
13
+ opts.meta ||= {}
14
14
 
15
15
  arguments.length = Math.max(3, arguments.length)
16
16
 
@@ -36,7 +36,7 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
36
36
  }
37
37
  ctx.result = result
38
38
 
39
- return finishCh.runStores(ctx, cb, this, error, result)
39
+ return finishCh.runStores(ctx, cb, this, ...arguments)
40
40
  })
41
41
  } else {
42
42
  res.once('end', () => finishCh.publish(ctx))