dd-trace 6.8.0 → 6.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) 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 +9 -3
  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/vitest.js +517 -0
  20. package/ci/test-optimization-validation/generated-files.js +38 -28
  21. package/ci/test-optimization-validation/generated-test-contract.js +8 -4
  22. package/ci/test-optimization-validation/generated-verifier.js +24 -17
  23. package/ci/test-optimization-validation/literal-glob.js +52 -0
  24. package/ci/test-optimization-validation/manifest-loader.js +3 -0
  25. package/ci/test-optimization-validation/manifest-scaffold.js +300 -50
  26. package/ci/test-optimization-validation/manifest-schema.js +80 -17
  27. package/ci/test-optimization-validation/offline-fixtures.js +13 -4
  28. package/ci/test-optimization-validation/package-check.js +94 -0
  29. package/ci/test-optimization-validation/plan-writer.js +183 -10
  30. package/ci/test-optimization-validation/preflight-runner.js +110 -31
  31. package/ci/test-optimization-validation/project-build-artifact.js +31 -0
  32. package/ci/test-optimization-validation/redaction.js +18 -27
  33. package/ci/test-optimization-validation/report-writer.js +182 -48
  34. package/ci/test-optimization-validation/result-semantics.js +20 -3
  35. package/ci/test-optimization-validation/runner-command.js +40 -20
  36. package/ci/test-optimization-validation/runner-contract.js +79 -43
  37. package/ci/test-optimization-validation/scenarios/basic-reporting.js +59 -5
  38. package/ci/test-optimization-validation/scenarios/ci-wiring.js +141 -35
  39. package/ci/test-optimization-validation/scenarios/helpers.js +30 -6
  40. package/ci/test-optimization-validation/static-diagnosis.js +10 -3
  41. package/ci/test-optimization-validation/test-output.js +2 -1
  42. package/ci/test-optimization-validation/validation-blocker.js +21 -0
  43. package/ci/vitest-no-worker-init-setup.mjs +140 -42
  44. package/index.d.ts +140 -1
  45. package/init.js +1 -17
  46. package/initialize.mjs +11 -0
  47. package/loader-hook.mjs +6 -4
  48. package/package.json +8 -5
  49. package/packages/datadog-core/src/utils/src/parse-tags.js +0 -1
  50. package/packages/datadog-esbuild/src/utils.js +16 -1
  51. package/packages/datadog-instrumentations/src/ai.js +61 -34
  52. package/packages/datadog-instrumentations/src/bluebird.js +6 -6
  53. package/packages/datadog-instrumentations/src/claude-agent-sdk.js +81 -5
  54. package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
  55. package/packages/datadog-instrumentations/src/cucumber.js +124 -47
  56. package/packages/datadog-instrumentations/src/dns.js +21 -2
  57. package/packages/datadog-instrumentations/src/electron.js +1 -0
  58. package/packages/datadog-instrumentations/src/fastify.js +3 -1
  59. package/packages/datadog-instrumentations/src/grpc/client.js +4 -2
  60. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +3 -1
  61. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  62. package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +629 -0
  63. package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +34 -9
  64. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +199 -0
  65. package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +20 -2
  66. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.js +32 -0
  67. package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +62 -0
  68. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
  69. package/packages/datadog-instrumentations/src/helpers/router-helper.js +37 -6
  70. package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +1 -1
  71. package/packages/datadog-instrumentations/src/jest.js +980 -234
  72. package/packages/datadog-instrumentations/src/mocha/main.js +108 -10
  73. package/packages/datadog-instrumentations/src/mocha/utils.js +66 -50
  74. package/packages/datadog-instrumentations/src/mocha/webdriverio-protocol.js +25 -0
  75. package/packages/datadog-instrumentations/src/mocha/worker.js +12 -18
  76. package/packages/datadog-instrumentations/src/mysql.js +46 -16
  77. package/packages/datadog-instrumentations/src/mysql2.js +119 -18
  78. package/packages/datadog-instrumentations/src/next.js +155 -23
  79. package/packages/datadog-instrumentations/src/openai.js +14 -0
  80. package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
  81. package/packages/datadog-instrumentations/src/pg.js +209 -11
  82. package/packages/datadog-instrumentations/src/playwright.js +173 -79
  83. package/packages/datadog-instrumentations/src/promise-js.js +4 -4
  84. package/packages/datadog-instrumentations/src/promise.js +3 -3
  85. package/packages/datadog-instrumentations/src/router.js +195 -19
  86. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +85 -13
  87. package/packages/datadog-instrumentations/src/vitest-main.js +528 -72
  88. package/packages/datadog-instrumentations/src/vitest-util.js +106 -12
  89. package/packages/datadog-instrumentations/src/vitest-worker.js +382 -40
  90. package/packages/datadog-instrumentations/src/webdriverio.js +212 -22
  91. package/packages/datadog-instrumentations/src/when.js +3 -3
  92. package/packages/datadog-instrumentations/src/ws.js +5 -1
  93. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
  94. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +59 -48
  95. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +2 -5
  96. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
  97. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +1 -3
  98. package/packages/datadog-plugin-cucumber/src/index.js +5 -1
  99. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +51 -47
  100. package/packages/datadog-plugin-cypress/src/support.js +7 -4
  101. package/packages/datadog-plugin-electron/src/net.js +10 -4
  102. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
  103. package/packages/datadog-plugin-http/src/client.js +1 -1
  104. package/packages/datadog-plugin-http2/src/client.js +1 -1
  105. package/packages/datadog-plugin-jest/src/index.js +6 -22
  106. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
  107. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
  108. package/packages/datadog-plugin-kafkajs/src/producer.js +5 -3
  109. package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
  110. package/packages/datadog-plugin-mocha/src/index.js +832 -4
  111. package/packages/datadog-plugin-mysql/src/index.js +37 -0
  112. package/packages/datadog-plugin-next/src/index.js +51 -21
  113. package/packages/datadog-plugin-openai/src/tracing.js +4 -0
  114. package/packages/datadog-plugin-openai-agents/src/integration.js +278 -69
  115. package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
  116. package/packages/datadog-plugin-pg/src/index.js +66 -1
  117. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  118. package/packages/datadog-plugin-vitest/src/index.js +103 -27
  119. package/packages/datadog-plugin-ws/src/util.js +2 -1
  120. package/packages/datadog-shimmer/src/shimmer.js +6 -2
  121. package/packages/dd-trace/src/aiguard/sdk.js +3 -0
  122. package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
  123. package/packages/dd-trace/src/appsec/{blocking.js → blocking/index.js} +26 -6
  124. package/packages/dd-trace/src/appsec/handlers/auth.js +62 -0
  125. package/packages/dd-trace/src/appsec/handlers/http-request.js +228 -0
  126. package/packages/dd-trace/src/appsec/handlers/http-response.js +78 -0
  127. package/packages/dd-trace/src/appsec/handlers/http-shared.js +24 -0
  128. package/packages/dd-trace/src/appsec/handlers/payments.js +104 -0
  129. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +1 -1
  130. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
  131. package/packages/dd-trace/src/appsec/index.js +48 -476
  132. package/packages/dd-trace/src/appsec/sdk/track_event.js +9 -0
  133. package/packages/dd-trace/src/carrier.js +356 -0
  134. package/packages/dd-trace/src/ci-visibility/coverage-report-discovery.js +46 -14
  135. package/packages/dd-trace/src/ci-visibility/efd-retry-policy.js +89 -0
  136. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +27 -13
  137. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +17 -0
  138. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +21 -1
  139. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +22 -7
  140. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +9 -14
  141. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +21 -5
  142. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +1 -1
  143. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +5 -1
  144. package/packages/dd-trace/src/config/generated-config-types.d.ts +5 -0
  145. package/packages/dd-trace/src/config/helper.js +2 -0
  146. package/packages/dd-trace/src/config/index.js +16 -5
  147. package/packages/dd-trace/src/config/remote_config.js +1 -1
  148. package/packages/dd-trace/src/config/supported-configurations.json +18 -0
  149. package/packages/dd-trace/src/datastreams/context.js +6 -1
  150. package/packages/dd-trace/src/datastreams/manager.js +5 -1
  151. package/packages/dd-trace/src/datastreams/pathway.js +23 -22
  152. package/packages/dd-trace/src/datastreams/processor.js +3 -2
  153. package/packages/dd-trace/src/debugger/devtools_client/status.js +1 -1
  154. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
  155. package/packages/dd-trace/src/guardrails/apply-pm2-env.js +16 -0
  156. package/packages/dd-trace/src/guardrails/log.js +1 -10
  157. package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
  158. package/packages/dd-trace/src/llmobs/eval-metric.js +249 -0
  159. package/packages/dd-trace/src/llmobs/experiments/index.js +33 -25
  160. package/packages/dd-trace/src/llmobs/experiments/util.js +4 -2
  161. package/packages/dd-trace/src/llmobs/index.js +34 -2
  162. package/packages/dd-trace/src/llmobs/noop.js +2 -0
  163. package/packages/dd-trace/src/llmobs/plugins/ai/ddTelemetry.js +1 -1
  164. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
  165. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +5 -5
  166. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +1 -1
  167. package/packages/dd-trace/src/llmobs/sdk.js +149 -68
  168. package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
  169. package/packages/dd-trace/src/llmobs/tagger.js +96 -0
  170. package/packages/dd-trace/src/llmobs/telemetry.js +18 -0
  171. package/packages/dd-trace/src/llmobs/util.js +78 -0
  172. package/packages/dd-trace/src/llmobs/writers/base.js +3 -0
  173. package/packages/dd-trace/src/llmobs/writers/util.js +2 -0
  174. package/packages/dd-trace/src/log/channels.js +1 -9
  175. package/packages/dd-trace/src/log/levels.js +12 -0
  176. package/packages/dd-trace/src/openfeature/writers/exposures.js +1 -1
  177. package/packages/dd-trace/src/openfeature/writers/util.js +1 -1
  178. package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +1 -1
  179. package/packages/dd-trace/src/opentelemetry/metrics/meter.js +8 -4
  180. package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +1 -1
  181. package/packages/dd-trace/src/opentelemetry/span.js +4 -0
  182. package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
  183. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
  184. package/packages/dd-trace/src/plugin_manager.js +2 -0
  185. package/packages/dd-trace/src/plugins/ci_plugin.js +21 -5
  186. package/packages/dd-trace/src/plugins/index.js +1 -0
  187. package/packages/dd-trace/src/plugins/util/ci.js +6 -0
  188. package/packages/dd-trace/src/plugins/util/git.js +6 -4
  189. package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +2 -2
  190. package/packages/dd-trace/src/plugins/util/ip_extractor.js +1 -1
  191. package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +3 -62
  192. package/packages/dd-trace/src/plugins/util/stacktrace.js +3 -0
  193. package/packages/dd-trace/src/plugins/util/test.js +397 -74
  194. package/packages/dd-trace/src/plugins/util/url.js +1 -1
  195. package/packages/dd-trace/src/plugins/util/web.js +76 -3
  196. package/packages/dd-trace/src/profiler.js +1 -1
  197. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +1 -1
  198. package/packages/dd-trace/src/profiling/profilers/events.js +2 -2
  199. package/packages/dd-trace/src/proxy.js +1 -0
  200. package/packages/dd-trace/src/ritm.js +5 -0
  201. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +4 -2
  202. package/packages/dd-trace/src/sampling_rule.js +4 -2
  203. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +1 -1
  204. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +1 -1
  205. package/packages/dd-trace/src/telemetry/logs/index.js +3 -0
  206. package/packages/dd-trace/src/telemetry/telemetry.js +1 -1
  207. package/vendor/dist/pprof-format/index.js +1 -1
  208. package/version.js +10 -8
  209. /package/packages/dd-trace/src/appsec/{blocked_templates.js → blocking/templates.js} +0 -0
@@ -3,6 +3,7 @@
3
3
  const { AsyncResource } = require('node:async_hooks')
4
4
  const { fileURLToPath } = require('node:url')
5
5
 
6
+ const { EMPTY_EFD_RETRY_POLICY } = require('../../dd-trace/src/ci-visibility/efd-retry-policy')
6
7
  const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
7
8
  const log = require('../../dd-trace/src/log')
8
9
  const {
@@ -11,6 +12,7 @@ const {
11
12
  getTestSuitePath,
12
13
  logTestOptimizationSummary,
13
14
  MOCHA_WORKER_LOGS_PAYLOAD_CODE,
15
+ MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE,
14
16
  MOCHA_WORKER_TRACE_PAYLOAD_CODE,
15
17
  TEST_SUITE_EXECUTION_ID,
16
18
  } = require('../../dd-trace/src/plugins/util/test')
@@ -18,31 +20,43 @@ const { addHook, channel, tracingChannel } = require('./helpers/instrument')
18
20
  const {
19
21
  CONFIGURATION_REQUEST,
20
22
  CONFIGURATION_RESPONSE,
23
+ sendWebdriverioWorkerMessage,
21
24
  SUITE_FINISH,
22
25
  WEBDRIVERIO_WORKER_ENV,
23
26
  WEBDRIVERIO_WORKER_EVENT,
24
27
  WEBDRIVERIO_WORKER_ORIGIN,
25
28
  WORKER_READY,
29
+ WORKER_READY_RESPONSE,
26
30
  } = require('./mocha/webdriverio-protocol')
27
31
 
32
+ const jasmineDoneCh = channel('ci:webdriverio:jasmine:done')
28
33
  const testFinishCh = channel('ci:mocha:test:finish')
29
34
  const testSessionStartCh = channel('ci:mocha:session:start')
30
35
  const testSessionFinishCh = channel('ci:mocha:session:finish')
36
+ const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
31
37
  const testSuiteStartCh = channel('ci:mocha:test-suite:start')
32
38
  const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
33
39
  const knownTestsCh = channel('ci:mocha:known-tests')
34
40
  const libraryConfigurationCh = channel('ci:mocha:library-configuration')
35
41
  const modifiedFilesCh = channel('ci:mocha:modified-files')
36
42
  const testManagementTestsCh = channel('ci:mocha:test-management-tests')
43
+ const workerConfigurationCh = channel('ci:mocha:worker:configuration')
37
44
  const workerReportLogsCh = channel('ci:mocha:worker-report:logs')
45
+ const workerReportTelemetryCh = channel('ci:mocha:worker-report:telemetry')
38
46
  const workerReportTraceCh = channel('ci:mocha:worker-report:trace')
39
47
 
48
+ const jasmineAdapterInitCh = tracingChannel('orchestrion:@wdio/jasmine-framework:JasmineAdapter_init')
40
49
  const launcherStartInstanceCh = tracingChannel('orchestrion:@wdio/cli:Launcher_startInstance')
41
50
  const localRunnerRunCh = tracingChannel('orchestrion:@wdio/local-runner:LocalRunner_run')
42
51
  const localRunnerShutdownCh = tracingChannel('orchestrion:@wdio/local-runner:LocalRunner_shutdown')
43
52
 
44
53
  const NODE_OPTIONS_SEPARATOR_RE = /\s/
54
+ const JASMINE_FRAMEWORK_ADAPTER = 'jasmine'
55
+ const MOCHA_FRAMEWORK_ADAPTER = 'mocha'
56
+ const SUPPORTED_FRAMEWORK_ADAPTERS = new Set([JASMINE_FRAMEWORK_ADAPTER, MOCHA_FRAMEWORK_ADAPTER])
45
57
  const TEST_FRAMEWORK = 'webdriverio'
58
+ const isWebdriverioWorker = !!getEnvironmentVariable(WEBDRIVERIO_WORKER_ENV)
59
+ let jasmineWorkerRequestId = 0
46
60
 
47
61
  const loadCh = channel('dd-trace:instrumentation:load')
48
62
  if (loadCh.hasSubscribers) {
@@ -66,7 +80,7 @@ addHook({
66
80
  * @typedef {object} WebdriverioRunnerConfig
67
81
  * @property {string} framework
68
82
  * @property {string|undefined} rootDir
69
- * @property {NodeJS.ProcessEnv|undefined} runnerEnv
83
+ * @property {typeof process.env|undefined} runnerEnv
70
84
  */
71
85
 
72
86
  /**
@@ -79,6 +93,7 @@ addHook({
79
93
  * @typedef {object} WorkerRecord
80
94
  * @property {object} worker
81
95
  * @property {string[]} specs
96
+ * @property {Map<string, WebdriverioSuiteResult>} reportedSuiteResults
82
97
  * @property {Map<string, WebdriverioSuiteContext>} suiteContexts
83
98
  * @property {string} testSuiteExecutionId
84
99
  * @property {boolean|undefined} hasTests
@@ -89,11 +104,18 @@ addHook({
89
104
  /**
90
105
  * @typedef {object} WebdriverioSuiteContext
91
106
  * @property {object|undefined} currentStore
107
+ * @property {Error|undefined} error
92
108
  * @property {string|undefined} status
93
109
  * @property {string} testSuiteAbsolutePath
94
110
  * @property {string} testSuiteExecutionId
95
111
  */
96
112
 
113
+ /**
114
+ * @typedef {object} WebdriverioSuiteResult
115
+ * @property {{message?: string, stack?: string}|undefined} error
116
+ * @property {string|undefined} status
117
+ */
118
+
97
119
  /**
98
120
  * @typedef {object} CoordinatorState
99
121
  * @property {WebdriverioLocalRunner} localRunner
@@ -112,21 +134,21 @@ addHook({
112
134
  * @property {Set<string>} newTestsWithDynamicNames
113
135
  * @property {number} nextWorkerId
114
136
  * @property {Set<string>} scheduledFiles
137
+ * @property {Map<string, object>} testManagementExecutions
115
138
  * @property {unknown} runError
116
139
  * @property {Set<WorkerRecord>} workers
117
140
  * @property {Map<object, string>} suiteStatuses
118
141
  */
119
142
 
120
143
  /**
121
- * Creates the configuration consumed by Mocha workers.
144
+ * Creates the configuration consumed by WebdriverIO workers.
122
145
  *
123
146
  * @returns {object}
124
147
  */
125
148
  function createWorkerConfiguration () {
126
149
  return {
127
150
  earlyFlakeDetectionFaultyThreshold: 30,
128
- earlyFlakeDetectionNumRetries: 0,
129
- earlyFlakeDetectionSlowTestRetries: {},
151
+ earlyFlakeDetectionRetryPolicy: EMPTY_EFD_RETRY_POLICY,
130
152
  flakyTestRetriesCount: 0,
131
153
  isCodeCoverageEnabled: false,
132
154
  isCoverageReportUploadEnabled: false,
@@ -148,6 +170,105 @@ function createWorkerConfiguration () {
148
170
  }
149
171
  }
150
172
 
173
+ /**
174
+ * Configures a Jasmine worker and waits for its coordinator-owned optimization settings.
175
+ *
176
+ * @param {{_jrunner?: {env?: {addReporter?: (reporter: object) => void}}, _specs?: string[]}} adapter
177
+ * @param {{
178
+ * resolveCallback?: (onDone: () => void) => void,
179
+ * rejectCallback?: (onDone: () => void) => void
180
+ * }} context
181
+ * @returns {void}
182
+ */
183
+ function initializeJasmineWorker (adapter, context) {
184
+ if (!isWebdriverioWorker) {
185
+ return
186
+ }
187
+
188
+ const specs = adapter?._specs || []
189
+
190
+ if (jasmineDoneCh.hasSubscribers) {
191
+ adapter?._jrunner?.env?.addReporter?.({
192
+ /**
193
+ * Publishes run-level failures that are absent from suiteDone.
194
+ *
195
+ * @param {object} result
196
+ * @returns {void}
197
+ */
198
+ jasmineDone (result) {
199
+ jasmineDoneCh.publish({ result })
200
+ },
201
+ })
202
+ }
203
+
204
+ /**
205
+ * Waits until the coordinator has started this worker's parent spans.
206
+ *
207
+ * @param {() => void} onDone
208
+ * @returns {void}
209
+ */
210
+ const waitForCoordinator = onDone => {
211
+ const requestId = `${process.pid}-${++jasmineWorkerRequestId}`
212
+ let finished = false
213
+
214
+ /**
215
+ * Releases Jasmine initialization exactly once.
216
+ *
217
+ * @param {object} [configuration]
218
+ * @returns {void}
219
+ */
220
+ function finish (configuration = createWorkerConfiguration()) {
221
+ if (finished) {
222
+ return
223
+ }
224
+ finished = true
225
+ clearTimeout(timeout)
226
+ process.off('message', onMessage)
227
+ process.off('disconnect', finish)
228
+ workerConfigurationCh.publish({
229
+ libraryConfig: configuration,
230
+ repositoryRoot: configuration.repositoryRoot,
231
+ specs,
232
+ testFramework: TEST_FRAMEWORK,
233
+ testFrameworkAdapter: JASMINE_FRAMEWORK_ADAPTER,
234
+ })
235
+ onDone()
236
+ }
237
+
238
+ /**
239
+ * Receives coordinator readiness for this worker.
240
+ *
241
+ * @param {object} message
242
+ * @returns {void}
243
+ */
244
+ function onMessage (message) {
245
+ if (message?.name === WORKER_READY_RESPONSE && message.content?.requestId === requestId) {
246
+ finish(message.content.configuration)
247
+ }
248
+ }
249
+
250
+ const timeout = setTimeout(finish, 30_000)
251
+ process.on('message', onMessage)
252
+ process.once('disconnect', finish)
253
+ sendWebdriverioWorkerMessage({
254
+ origin: 'datadog',
255
+ name: WORKER_READY,
256
+ content: {
257
+ requestId,
258
+ testFrameworkAdapter: JASMINE_FRAMEWORK_ADAPTER,
259
+ },
260
+ }, error => {
261
+ if (error) {
262
+ log.error('WebdriverIO Test Optimization IPC error', error)
263
+ }
264
+ finish()
265
+ })
266
+ }
267
+
268
+ context.resolveCallback = waitForCoordinator
269
+ context.rejectCallback = waitForCoordinator
270
+ }
271
+
151
272
  /**
152
273
  * Gets the public runner configuration, or the private equivalent used by older releases.
153
274
  *
@@ -187,6 +308,7 @@ function getCoordinatorState (localRunner) {
187
308
  newTestsWithDynamicNames: new Set(),
188
309
  nextWorkerId: 0,
189
310
  scheduledFiles: new Set(),
311
+ testManagementExecutions: new Map(),
190
312
  runError: undefined,
191
313
  workers: new Set(),
192
314
  suiteStatuses: new Map(),
@@ -247,7 +369,7 @@ function includesNodeOptions (workerNodeOptions, launcherNodeOptions) {
247
369
  }
248
370
 
249
371
  /**
250
- * Starts the single Mocha session owned by the WebdriverIO launcher.
372
+ * Starts the single test session owned by the WebdriverIO launcher.
251
373
  *
252
374
  * @param {CoordinatorState} state
253
375
  * @returns {void}
@@ -326,6 +448,18 @@ function getMochaFrameworkData (frameworkData) {
326
448
  return frameworkData?.[TEST_FRAMEWORK] ?? frameworkData?.mocha
327
449
  }
328
450
 
451
+ /**
452
+ * Applies the worker configuration for an EFD session with faulty known-tests data.
453
+ *
454
+ * @param {object} configuration
455
+ * @returns {void}
456
+ */
457
+ function setEarlyFlakeDetectionFaulty (configuration) {
458
+ configuration.isEarlyFlakeDetectionEnabled = false
459
+ configuration.isEarlyFlakeDetectionFaulty = true
460
+ configuration.isKnownTestsEnabled = false
461
+ }
462
+
329
463
  /**
330
464
  * Applies settings and requests the enabled non-TIA datasets once for the whole run.
331
465
  *
@@ -349,8 +483,7 @@ function configureCoordinator (state, response) {
349
483
  }
350
484
 
351
485
  configuration.earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
352
- configuration.earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
353
- configuration.earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
486
+ configuration.earlyFlakeDetectionRetryPolicy = libraryConfig.earlyFlakeDetectionRetryPolicy ?? EMPTY_EFD_RETRY_POLICY
354
487
  configuration.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
355
488
  configuration.isDiEnabled = libraryConfig.isDiEnabled
356
489
  configuration.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
@@ -379,9 +512,11 @@ function configureCoordinator (state, response) {
379
512
  pendingRequests++
380
513
  requestCoordinatorData(state, knownTestsCh, ({ err, knownTests } = {}) => {
381
514
  const mochaKnownTests = getMochaFrameworkData(knownTests)
382
- if (err || !mochaKnownTests) {
515
+ if (err) {
383
516
  configuration.isEarlyFlakeDetectionEnabled = false
384
517
  configuration.isKnownTestsEnabled = false
518
+ } else if (mochaKnownTests === undefined) {
519
+ setEarlyFlakeDetectionFaulty(configuration)
385
520
  } else {
386
521
  configuration.knownTests = { mocha: mochaKnownTests }
387
522
  }
@@ -476,7 +611,10 @@ function startWorkerSuites (workerRecord, files) {
476
611
  continue
477
612
  }
478
613
 
614
+ const reportedResult = workerRecord.reportedSuiteResults.get(file)
479
615
  const suiteContext = {
616
+ error: getWebdriverioSuiteError(reportedResult?.error),
617
+ status: reportedResult?.status,
480
618
  testSuiteAbsolutePath: file,
481
619
  testSuiteExecutionId: workerRecord.testSuiteExecutionId,
482
620
  }
@@ -502,6 +640,9 @@ function finishWorkerSuite (state, workerRecord, rawFile, status) {
502
640
  }
503
641
 
504
642
  state.suiteStatuses.set(suiteContext, status)
643
+ if (suiteContext.error) {
644
+ testSuiteErrorCh.runStores(suiteContext, () => {})
645
+ }
505
646
  testSuiteFinishCh.publish({ status, ...suiteContext.currentStore })
506
647
  }
507
648
 
@@ -552,7 +693,7 @@ function sendWorkerMessage (workerRecord, message) {
552
693
  }
553
694
 
554
695
  /**
555
- * Handles a worker request for its Mocha execution configuration.
696
+ * Handles a worker request for its execution configuration.
556
697
  *
557
698
  * @param {CoordinatorState} state
558
699
  * @param {WorkerRecord} workerRecord
@@ -601,14 +742,30 @@ function updateEarlyFlakeDetectionFaultyState (state, files) {
601
742
  configuration.earlyFlakeDetectionFaultyThreshold
602
743
  )
603
744
  if (isFaulty) {
604
- configuration.isEarlyFlakeDetectionEnabled = false
605
- configuration.isEarlyFlakeDetectionFaulty = true
606
- configuration.isKnownTestsEnabled = false
745
+ setEarlyFlakeDetectionFaulty(configuration)
746
+ }
747
+ }
748
+
749
+ /**
750
+ * Reconstructs an Error received from a WebdriverIO worker.
751
+ *
752
+ * @param {{message?: string, stack?: string}|undefined} error
753
+ * @returns {Error|undefined}
754
+ */
755
+ function getWebdriverioSuiteError (error) {
756
+ if (!error?.message) {
757
+ return
607
758
  }
759
+
760
+ const suiteError = new Error(error.message)
761
+ if (error.stack) {
762
+ suiteError.stack = error.stack
763
+ }
764
+ return suiteError
608
765
  }
609
766
 
610
767
  /**
611
- * Handles suite results reported by a Mocha worker.
768
+ * Handles suite results reported by a WebdriverIO worker.
612
769
  *
613
770
  * @param {WorkerRecord} workerRecord
614
771
  * @param {object} message
@@ -616,9 +773,12 @@ function updateEarlyFlakeDetectionFaultyState (state, files) {
616
773
  */
617
774
  function handleSuiteResults (workerRecord, message) {
618
775
  const { results = [] } = message.content || {}
619
- for (const { file, status } of results) {
620
- const suiteContext = workerRecord.suiteContexts.get(normalizeFile(file))
776
+ for (const { error, file, status } of results) {
777
+ const normalizedFile = normalizeFile(file)
778
+ workerRecord.reportedSuiteResults.set(normalizedFile, { error, status })
779
+ const suiteContext = workerRecord.suiteContexts.get(normalizedFile)
621
780
  if (suiteContext) {
781
+ suiteContext.error = getWebdriverioSuiteError(error)
622
782
  suiteContext.status = status
623
783
  }
624
784
  }
@@ -643,6 +803,7 @@ function handleWorkerMessage (state, workerRecord, message) {
643
803
  collectTestOptimizationSummariesFromTraces(payload, {
644
804
  attemptToFixExecutions: state.attemptToFixExecutions,
645
805
  newTestsWithDynamicNames: state.newTestsWithDynamicNames,
806
+ testManagementExecutions: state.testManagementExecutions,
646
807
  })
647
808
  workerReportTraceCh.publish({
648
809
  traces: payload,
@@ -650,6 +811,8 @@ function handleWorkerMessage (state, workerRecord, message) {
650
811
  })
651
812
  } else if (messageCode === MOCHA_WORKER_LOGS_PAYLOAD_CODE) {
652
813
  workerReportLogsCh.publish(payload)
814
+ } else if (messageCode === MOCHA_WORKER_TELEMETRY_PAYLOAD_CODE) {
815
+ workerReportTelemetryCh.publish(payload)
653
816
  }
654
817
  return
655
818
  }
@@ -659,7 +822,19 @@ function handleWorkerMessage (state, workerRecord, message) {
659
822
  }
660
823
 
661
824
  if (message.name === WORKER_READY) {
662
- initializeCoordinator(state)
825
+ initializeCoordinator(state, configuration => {
826
+ if (state.testFrameworkAdapter === JASMINE_FRAMEWORK_ADAPTER) {
827
+ updateEarlyFlakeDetectionFaultyState(state, workerRecord.specs)
828
+ startWorkerSuites(workerRecord, workerRecord.specs)
829
+ }
830
+ if (message.content?.requestId) {
831
+ sendWorkerMessage(workerRecord, {
832
+ origin: 'datadog',
833
+ name: WORKER_READY_RESPONSE,
834
+ content: { configuration, requestId: message.content.requestId },
835
+ })
836
+ }
837
+ })
663
838
  return
664
839
  }
665
840
  if (message.name === CONFIGURATION_REQUEST) {
@@ -721,6 +896,7 @@ function registerWorker (state, worker, specs) {
721
896
  const workerRecord = {
722
897
  worker,
723
898
  specs: normalizedSpecs,
899
+ reportedSuiteResults: new Map(),
724
900
  suiteContexts: new Map(),
725
901
  testSuiteExecutionId: String(++state.nextWorkerId),
726
902
  hasTests: undefined,
@@ -768,7 +944,7 @@ function getSessionStatus (state) {
768
944
  }
769
945
 
770
946
  /**
771
- * Finishes the single WebdriverIO-owned Mocha session.
947
+ * Finishes the single WebdriverIO-owned test session.
772
948
  *
773
949
  * @param {CoordinatorState} state
774
950
  * @param {unknown} error
@@ -801,6 +977,7 @@ function finishCoordinator (state, error, onDone) {
801
977
  logTestOptimizationSummary({
802
978
  attemptToFixExecutions: state.attemptToFixExecutions,
803
979
  newTestsWithDynamicNames: state.newTestsWithDynamicNames,
980
+ testManagementExecutions: state.testManagementExecutions,
804
981
  })
805
982
  onDone()
806
983
  return
@@ -819,24 +996,37 @@ function finishCoordinator (state, error, onDone) {
819
996
  logTestOptimizationSummary({
820
997
  attemptToFixExecutions: state.attemptToFixExecutions,
821
998
  newTestsWithDynamicNames: state.newTestsWithDynamicNames,
999
+ testManagementExecutions: state.testManagementExecutions,
822
1000
  })
823
1001
  }
824
1002
 
1003
+ // dc-polyfill supports partial tracing-channel subscribers, unlike the Node.js type definition.
1004
+ // @ts-expect-error
1005
+ jasmineAdapterInitCh.subscribe({
1006
+ asyncEnd (context) {
1007
+ initializeJasmineWorker(context.result || context.self, context)
1008
+ },
1009
+ })
1010
+
825
1011
  // dc-polyfill supports partial tracing-channel subscribers, unlike the Node.js type definition.
826
1012
  // @ts-expect-error
827
1013
  launcherStartInstanceCh.subscribe({
828
1014
  start (context) {
829
1015
  const localRunner = context.self?.runner
830
1016
  const runnerConfiguration = localRunner && getRunnerConfiguration(localRunner)
831
- if (!testFinishCh.hasSubscribers || runnerConfiguration?.framework !== 'mocha') {
1017
+ if (!testFinishCh.hasSubscribers || !SUPPORTED_FRAMEWORK_ADAPTERS.has(runnerConfiguration?.framework)) {
832
1018
  return
833
1019
  }
834
1020
 
835
1021
  const state = getCoordinatorState(localRunner)
836
1022
  addScheduledFiles(state, context.arguments?.[0] || [])
837
- for (const schedule of context.self._schedule || []) {
838
- for (const { files } of schedule.specs || []) {
839
- addScheduledFiles(state, files)
1023
+ if (context.self._schedule) {
1024
+ for (const schedule of context.self._schedule) {
1025
+ if (schedule.specs) {
1026
+ for (const { files } of schedule.specs) {
1027
+ addScheduledFiles(state, files)
1028
+ }
1029
+ }
840
1030
  }
841
1031
  }
842
1032
  },
@@ -847,7 +1037,7 @@ launcherStartInstanceCh.subscribe({
847
1037
  localRunnerRunCh.subscribe({
848
1038
  start (context) {
849
1039
  const runnerConfiguration = getRunnerConfiguration(context.self)
850
- if (!testFinishCh.hasSubscribers || runnerConfiguration?.framework !== 'mocha') {
1040
+ if (!testFinishCh.hasSubscribers || !SUPPORTED_FRAMEWORK_ADAPTERS.has(runnerConfiguration?.framework)) {
851
1041
  return
852
1042
  }
853
1043
 
@@ -8,7 +8,7 @@ addHook({
8
8
  name: 'when',
9
9
  file: 'lib/Promise.js',
10
10
  versions: ['>=3'],
11
- }, Promise => {
12
- shimmer.wrap(Promise.prototype, 'then', wrapThen)
13
- return Promise
11
+ }, LibraryPromise => {
12
+ shimmer.wrap(LibraryPromise.prototype, 'then', wrapThen)
13
+ return LibraryPromise
14
14
  })
@@ -49,7 +49,11 @@ const setSocketCh = channel('tracing:ws:server:connect:setSocket')
49
49
  */
50
50
 
51
51
  /**
52
- * @typedef {string | Buffer | ArrayBuffer | ArrayBufferView | Blob | Buffer[]} WebSocketMessageData
52
+ * @typedef {{ buffer: ArrayBuffer | SharedArrayBuffer, byteLength: number, byteOffset: number }} BufferView
53
+ */
54
+
55
+ /**
56
+ * @typedef {string | Buffer | ArrayBuffer | BufferView | Blob | Buffer[]} WebSocketMessageData
53
57
  */
54
58
 
55
59
  /**
@@ -1,6 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const crypto = require('crypto')
4
+ const {
5
+ deleteDatadogParentId,
6
+ readDatadogParentId,
7
+ readDatadogTraceId,
8
+ writeDatadogParentId,
9
+ } = require('../../dd-trace/src/carrier')
4
10
  const log = require('../../dd-trace/src/log')
5
11
  const TextMapPropagator = require('../../dd-trace/src/opentracing/propagation/text_map')
6
12
 
@@ -37,7 +43,7 @@ function getDatadogOnlyPropagator (tracer) {
37
43
  * @returns {Record<string, string>}
38
44
  */
39
45
  function injectHeaders (tracer, span) {
40
- const headers = {}
46
+ const headers = /** @type {Record<string, string>} */ ({})
41
47
  const propagator = getDatadogOnlyPropagator(tracer)
42
48
  const ctx = typeof span?.context === 'function' ? span.context() : span
43
49
  propagator.inject(ctx, headers)
@@ -51,8 +57,8 @@ function injectHeaders (tracer, span) {
51
57
  */
52
58
  function overrideParentId (headers, parentId) {
53
59
  if (!parentId) return
54
- if (headers['x-datadog-trace-id']) {
55
- headers['x-datadog-parent-id'] = String(parentId)
60
+ if (readDatadogTraceId(headers)) {
61
+ writeDatadogParentId(headers, String(parentId))
56
62
  }
57
63
  }
58
64
 
@@ -192,7 +198,7 @@ async function saveTraceContextCheckpointIfUpdated (
192
198
  if (typeof checkpointManager?.checkpoint !== 'function') return
193
199
 
194
200
  const currentHeaders = injectHeaders(tracer, span)
195
- if (currentHeaders['x-datadog-trace-id'] === undefined) return
201
+ if (readDatadogTraceId(currentHeaders) === undefined) return
196
202
 
197
203
  const latest = findLastCheckpoint(event)
198
204
 
@@ -204,8 +210,8 @@ async function saveTraceContextCheckpointIfUpdated (
204
210
  // x-datadog-parent-id reflects the active span at save time and always differs, so exclude it
205
211
  // from the comparison. Capture the previous anchor first to carry it forward on a real update.
206
212
  // needsCheckpointUpdate only reads currentHeaders' keys, so deleting it from there is enough.
207
- const anchoredSpanId = previousHeaders['x-datadog-parent-id']
208
- delete currentHeaders['x-datadog-parent-id']
213
+ const anchoredSpanId = readDatadogParentId(previousHeaders)
214
+ deleteDatadogParentId(currentHeaders)
209
215
  if (!needsCheckpointUpdate(currentHeaders, previousHeaders)) return
210
216
 
211
217
  newNumber = latest.checkpointNumber + 1