dd-trace 5.110.0 → 5.111.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 (115) hide show
  1. package/README.md +13 -8
  2. package/ci/init.js +21 -2
  3. package/ci/vitest-no-worker-init-setup.mjs +430 -0
  4. package/ext/tags.js +2 -0
  5. package/index.d.ts +13 -0
  6. package/initialize.mjs +5 -6
  7. package/loader-hook.mjs +76 -55
  8. package/package.json +9 -9
  9. package/packages/datadog-instrumentations/src/fs.js +8 -6
  10. package/packages/datadog-instrumentations/src/graphql.js +26 -495
  11. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/graphql.js +201 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  13. package/packages/datadog-instrumentations/src/mongoose.js +14 -2
  14. package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +1293 -0
  15. package/packages/datadog-instrumentations/src/vitest-main.js +1567 -0
  16. package/packages/datadog-instrumentations/src/vitest-util.js +249 -0
  17. package/packages/datadog-instrumentations/src/vitest-worker.js +753 -0
  18. package/packages/datadog-instrumentations/src/vitest.js +11 -1855
  19. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +2 -2
  20. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +18 -10
  21. package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +47 -11
  22. package/packages/datadog-plugin-cucumber/src/index.js +1 -1
  23. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +10 -4
  24. package/packages/datadog-plugin-cypress/src/support.js +45 -1
  25. package/packages/datadog-plugin-express/src/code_origin.js +1 -1
  26. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -1
  27. package/packages/datadog-plugin-graphql/src/execute.js +627 -11
  28. package/packages/datadog-plugin-graphql/src/index.js +20 -8
  29. package/packages/datadog-plugin-graphql/src/parse.js +24 -4
  30. package/packages/datadog-plugin-graphql/src/validate.js +16 -5
  31. package/packages/datadog-plugin-http/src/index.js +6 -8
  32. package/packages/datadog-plugin-jest/src/index.js +1 -1
  33. package/packages/datadog-plugin-mocha/src/index.js +1 -1
  34. package/packages/datadog-plugin-openai/src/services.js +2 -2
  35. package/packages/datadog-plugin-playwright/src/index.js +1 -1
  36. package/packages/datadog-plugin-vitest/src/index.js +69 -63
  37. package/packages/datadog-shimmer/src/shimmer.js +37 -16
  38. package/packages/dd-trace/src/aiguard/sdk.js +2 -2
  39. package/packages/dd-trace/src/appsec/api_security/sampler.js +3 -3
  40. package/packages/dd-trace/src/appsec/channels.js +3 -1
  41. package/packages/dd-trace/src/appsec/downstream_requests.js +4 -4
  42. package/packages/dd-trace/src/appsec/graphql.js +5 -5
  43. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +26 -19
  44. package/packages/dd-trace/src/appsec/iast/security-controls/index.js +2 -2
  45. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +2 -1
  46. package/packages/dd-trace/src/appsec/index.js +10 -1
  47. package/packages/dd-trace/src/appsec/lambda.js +135 -0
  48. package/packages/dd-trace/src/appsec/reporter.js +49 -10
  49. package/packages/dd-trace/src/appsec/telemetry/index.js +1 -1
  50. package/packages/dd-trace/src/appsec/waf/index.js +16 -4
  51. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
  52. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +21 -6
  53. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +2 -2
  54. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
  55. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +1 -1
  56. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -2
  57. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +1 -1
  58. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +55 -13
  59. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +2 -2
  60. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +17 -0
  61. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +47 -26
  62. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +2 -2
  63. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +64 -53
  64. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +3 -3
  65. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +23 -5
  66. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache-schema.js +128 -0
  67. package/packages/dd-trace/src/ci-visibility/test-optimization-http-cache.js +287 -0
  68. package/packages/dd-trace/src/config/defaults.js +3 -2
  69. package/packages/dd-trace/src/config/generated-config-types.d.ts +61 -57
  70. package/packages/dd-trace/src/config/helper.js +1 -0
  71. package/packages/dd-trace/src/config/index.js +35 -22
  72. package/packages/dd-trace/src/config/major-overrides.js +4 -2
  73. package/packages/dd-trace/src/config/remote_config.js +1 -1
  74. package/packages/dd-trace/src/config/supported-configurations.json +90 -56
  75. package/packages/dd-trace/src/constants.js +7 -0
  76. package/packages/dd-trace/src/datastreams/processor.js +11 -3
  77. package/packages/dd-trace/src/exporters/agent/index.js +1 -1
  78. package/packages/dd-trace/src/exporters/agentless/writer.js +4 -4
  79. package/packages/dd-trace/src/llmobs/index.js +1 -1
  80. package/packages/dd-trace/src/llmobs/plugins/base.js +4 -4
  81. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
  82. package/packages/dd-trace/src/llmobs/sdk.js +3 -3
  83. package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
  84. package/packages/dd-trace/src/llmobs/tagger.js +3 -3
  85. package/packages/dd-trace/src/llmobs/writers/base.js +1 -1
  86. package/packages/dd-trace/src/opentelemetry/metrics/index.js +54 -5
  87. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +40 -0
  88. package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +169 -0
  89. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +38 -39
  90. package/packages/dd-trace/src/opentelemetry/trace/index.js +4 -0
  91. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +1 -1
  92. package/packages/dd-trace/src/opentracing/tracer.js +6 -1
  93. package/packages/dd-trace/src/plugin_manager.js +7 -7
  94. package/packages/dd-trace/src/plugins/ci_plugin.js +12 -3
  95. package/packages/dd-trace/src/plugins/util/llm.js +6 -1
  96. package/packages/dd-trace/src/plugins/util/test.js +11 -9
  97. package/packages/dd-trace/src/profiling/exporter_cli.js +2 -2
  98. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +3 -3
  99. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  100. package/packages/dd-trace/src/proxy.js +8 -8
  101. package/packages/dd-trace/src/span_processor.js +5 -6
  102. package/packages/dd-trace/src/span_stats.js +96 -78
  103. package/packages/dd-trace/src/startup-log.js +2 -1
  104. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  105. package/packages/dd-trace/src/telemetry/endpoints.js +6 -4
  106. package/packages/dd-trace/src/telemetry/index.js +2 -2
  107. package/packages/dd-trace/src/telemetry/logs/index.js +1 -1
  108. package/packages/dd-trace/src/telemetry/send-data.js +8 -8
  109. package/packages/dd-trace/src/telemetry/session-propagation.js +1 -1
  110. package/packages/dd-trace/src/telemetry/telemetry.js +9 -9
  111. package/vendor/dist/@datadog/sketches-js/index.js +1 -1
  112. package/vendor/dist/protobufjs/index.js +1 -1
  113. package/vendor/dist/protobufjs/minimal/index.js +1 -1
  114. package/vendor/dist/shell-quote/index.js +1 -1
  115. package/packages/datadog-plugin-graphql/src/resolve.js +0 -170
@@ -7,6 +7,8 @@ const { getSkippableSuites: getSkippableSuitesRequest } = require('../intelligen
7
7
  const { getKnownTests: getKnownTestsRequest } = require('../early-flake-detection/get-known-tests')
8
8
  const { getTestManagementTests: getTestManagementTestsRequest } =
9
9
  require('../test-management/get-test-management-tests')
10
+ const { writeSettingsToCache } = require('../test-optimization-cache')
11
+ const { CACHE_MISS, TestOptimizationHttpCache } = require('../test-optimization-http-cache')
10
12
  const { uploadCoverageReport: uploadCoverageReportRequest } = require('../requests/upload-coverage-report')
11
13
  const log = require('../../log')
12
14
  const BufferingExporter = require('../../exporters/common/buffering-exporter')
@@ -42,6 +44,7 @@ class CiVisibilityExporter extends BufferingExporter {
42
44
  this._coverageTimer = undefined
43
45
  this._logsTimer = undefined
44
46
  this._coverageBuffer = []
47
+ this._testOptimizationHttpCache = new TestOptimizationHttpCache()
45
48
  // The library can use new features like ITR and test suite level visibility
46
49
  // AKA CI Vis Protocol
47
50
  this._canUseCiVisProtocol = false
@@ -86,7 +89,7 @@ class CiVisibilityExporter extends BufferingExporter {
86
89
  }
87
90
 
88
91
  shouldRequestSkippableSuites () {
89
- return !!(this._config.isIntelligentTestRunnerEnabled &&
92
+ return !!(this._config.testOptimization.DD_CIVISIBILITY_ITR_ENABLED &&
90
93
  this._canUseCiVisProtocol &&
91
94
  this._libraryConfig?.isSuitesSkippingEnabled)
92
95
  }
@@ -101,7 +104,7 @@ class CiVisibilityExporter extends BufferingExporter {
101
104
  shouldRequestTestManagementTests () {
102
105
  return !!(
103
106
  this._canUseCiVisProtocol &&
104
- this._config.isTestManagementEnabled &&
107
+ this._config.testOptimization.DD_TEST_MANAGEMENT_ENABLED &&
105
108
  this._libraryConfig?.isTestManagementEnabled
106
109
  )
107
110
  }
@@ -133,11 +136,21 @@ class CiVisibilityExporter extends BufferingExporter {
133
136
  if (!this.shouldRequestSkippableSuites()) {
134
137
  return callback(null, [])
135
138
  }
139
+ const requestConfiguration = this.getRequestConfiguration(testConfiguration)
140
+ const cachedSkippableSuites = this._testOptimizationHttpCache.readSkippableSuites({
141
+ testLevel: requestConfiguration.testLevel,
142
+ isCoverageReportUploadEnabled: requestConfiguration.isCoverageReportUploadEnabled,
143
+ })
144
+ if (cachedSkippableSuites !== CACHE_MISS) {
145
+ const { skippableSuites, correlationId, coverage } = cachedSkippableSuites
146
+ return callback(null, skippableSuites, correlationId, coverage)
147
+ }
148
+
136
149
  this._gitUploadPromise.then(gitUploadError => {
137
150
  if (gitUploadError) {
138
151
  return callback(gitUploadError, [])
139
152
  }
140
- getSkippableSuitesRequest(this.getRequestConfiguration(testConfiguration), callback)
153
+ getSkippableSuitesRequest(requestConfiguration, callback)
141
154
  })
142
155
  }
143
156
 
@@ -145,6 +158,10 @@ class CiVisibilityExporter extends BufferingExporter {
145
158
  if (!this.shouldRequestKnownTests()) {
146
159
  return callback(null)
147
160
  }
161
+ const cachedKnownTests = this._testOptimizationHttpCache.readKnownTests()
162
+ if (cachedKnownTests !== CACHE_MISS) {
163
+ return callback(null, cachedKnownTests)
164
+ }
148
165
  getKnownTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
149
166
  }
150
167
 
@@ -152,6 +169,10 @@ class CiVisibilityExporter extends BufferingExporter {
152
169
  if (!this.shouldRequestTestManagementTests()) {
153
170
  return callback(null)
154
171
  }
172
+ const cachedTestManagementTests = this._testOptimizationHttpCache.readTestManagementTests()
173
+ if (cachedTestManagementTests !== CACHE_MISS) {
174
+ return callback(null, cachedTestManagementTests)
175
+ }
155
176
  getTestManagementTestsRequest(this.getRequestConfiguration(testConfiguration), callback)
156
177
  }
157
178
 
@@ -161,13 +182,30 @@ class CiVisibilityExporter extends BufferingExporter {
161
182
  */
162
183
  getLibraryConfiguration (testConfiguration, callback) {
163
184
  const { repositoryUrl } = testConfiguration
164
- this.sendGitMetadata(repositoryUrl)
165
185
  this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
166
186
  if (!canUseCiVisProtocol) {
167
187
  return callback(null, {})
168
188
  }
169
189
  const configuration = this.getRequestConfiguration(testConfiguration)
190
+ const cachedLibraryConfig = this._testOptimizationHttpCache.readSettings()
191
+ if (cachedLibraryConfig !== CACHE_MISS) {
192
+ log.debug('Test Optimization HTTP cache settings found, skipping settings request')
193
+ writeSettingsToCache(cachedLibraryConfig)
194
+ this._libraryConfig = this.filterConfiguration(cachedLibraryConfig)
195
+ const canUseCachedSkippableSuites = !this.shouldRequestSkippableSuites() ||
196
+ this._testOptimizationHttpCache.hasValidSkippableSuites({
197
+ testLevel: configuration.testLevel,
198
+ isCoverageReportUploadEnabled: configuration.isCoverageReportUploadEnabled,
199
+ })
200
+ if (this._libraryConfig.requireGit && !canUseCachedSkippableSuites) {
201
+ this.sendGitMetadata(repositoryUrl)
202
+ } else {
203
+ this._resolveGit()
204
+ }
205
+ return callback(null, this._libraryConfig)
206
+ }
170
207
 
208
+ this.sendGitMetadata(repositoryUrl)
171
209
  getLibraryConfigurationRequest(configuration, (err, libraryConfig) => {
172
210
  /**
173
211
  * **Important**: this._libraryConfig remains empty in testing frameworks
@@ -218,29 +256,32 @@ class CiVisibilityExporter extends BufferingExporter {
218
256
  isImpactedTestsEnabled,
219
257
  isCoverageReportUploadEnabled,
220
258
  } = remoteConfiguration
259
+ const { testOptimization } = this._config
221
260
  return {
222
261
  isCodeCoverageEnabled,
223
262
  isSuitesSkippingEnabled,
224
263
  isItrEnabled,
225
264
  requireGit,
226
- isEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled && this._config.isEarlyFlakeDetectionEnabled,
265
+ isEarlyFlakeDetectionEnabled:
266
+ isEarlyFlakeDetectionEnabled && testOptimization.DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED,
227
267
  earlyFlakeDetectionNumRetries,
228
268
  earlyFlakeDetectionSlowTestRetries,
229
269
  earlyFlakeDetectionFaultyThreshold,
230
- isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
231
- flakyTestRetriesCount: this._config.flakyTestRetriesCount,
232
- isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled,
270
+ isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && testOptimization.DD_CIVISIBILITY_FLAKY_RETRY_ENABLED,
271
+ flakyTestRetriesCount: testOptimization.DD_CIVISIBILITY_FLAKY_RETRY_COUNT,
272
+ isDiEnabled: isDiEnabled && testOptimization.DD_TEST_FAILED_TEST_REPLAY_ENABLED,
233
273
  isKnownTestsEnabled,
234
- isTestManagementEnabled: isTestManagementEnabled && this._config.isTestManagementEnabled,
274
+ isTestManagementEnabled: isTestManagementEnabled && testOptimization.DD_TEST_MANAGEMENT_ENABLED,
235
275
  testManagementAttemptToFixRetries:
236
- testManagementAttemptToFixRetries ?? this._config.testManagementAttemptToFixRetries,
237
- isImpactedTestsEnabled: isImpactedTestsEnabled && this._config.isImpactedTestsEnabled,
276
+ testManagementAttemptToFixRetries ?? testOptimization.DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES,
277
+ isImpactedTestsEnabled:
278
+ isImpactedTestsEnabled && testOptimization.DD_CIVISIBILITY_IMPACTED_TESTS_DETECTION_ENABLED,
238
279
  isCoverageReportUploadEnabled,
239
280
  }
240
281
  }
241
282
 
242
283
  sendGitMetadata (repositoryUrl) {
243
- if (!this._config.isGitUploadEnabled) {
284
+ if (!this._config.testOptimization.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED) {
244
285
  return
245
286
  }
246
287
  this._canUseCiVisProtocolPromise.then((canUseCiVisProtocol) => {
@@ -318,7 +359,8 @@ class CiVisibilityExporter extends BufferingExporter {
318
359
  // DI logs
319
360
  exportDiLogs (testEnvironmentMetadata, logMessage) {
320
361
  // TODO: could we lose logs if it's not initialized?
321
- if (!this._config.isTestDynamicInstrumentationEnabled || !this._isInitialized || !this._canForwardLogs) {
362
+ if (!this._config.testOptimization.DD_TEST_FAILED_TEST_REPLAY_ENABLED ||
363
+ !this._isInitialized || !this._canForwardLogs) {
322
364
  return
323
365
  }
324
366
 
@@ -50,7 +50,7 @@ function getCommonRequestOptions (url) {
50
50
  return {
51
51
  method: 'POST',
52
52
  headers: {
53
- 'dd-api-key': getConfig().apiKey,
53
+ 'dd-api-key': getConfig().DD_API_KEY,
54
54
  },
55
55
  timeout: 15_000,
56
56
  url,
@@ -287,7 +287,7 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
287
287
  }
288
288
  // Otherwise we unshallow and get commits to upload again
289
289
  log.debug('It is shallow clone, unshallowing...')
290
- if (getConfig().DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED) {
290
+ if (getConfig().testOptimization.DD_CIVISIBILITY_GIT_UNSHALLOW_ENABLED) {
291
291
  unshallowRepository(false)
292
292
  }
293
293
 
@@ -3,6 +3,11 @@ const { JSONEncoder } = require('../../encode/json-encoder')
3
3
  const { getEnvironmentVariable } = require('../../../config/helper')
4
4
  const log = require('../../../log')
5
5
 
6
+ function getVitestWorkerPort () {
7
+ const port = globalThis.__vitest_worker__?.ctx?.port
8
+ return typeof port?.postMessage === 'function' ? port : undefined
9
+ }
10
+
6
11
  class Writer {
7
12
  constructor (interprocessCode) {
8
13
  this._encoder = new JSONEncoder()
@@ -37,6 +42,18 @@ class Writer {
37
42
  ? { __tinypool_worker_message__: true, interprocessCode: this._interprocessCode, data }
38
43
  : [this._interprocessCode, data]
39
44
 
45
+ const vitestWorkerPort = getVitestWorkerPort()
46
+ if (vitestWorkerPort) {
47
+ try {
48
+ vitestWorkerPort.postMessage(payload)
49
+ } catch (error) {
50
+ log.error('Error posting message to vitest worker port', error)
51
+ } finally {
52
+ onDone()
53
+ }
54
+ return
55
+ }
56
+
40
57
  // child_process workers (jest default, cucumber)
41
58
  if (process.send) {
42
59
  process.send(payload, () => {
@@ -14,6 +14,42 @@ const {
14
14
  TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES,
15
15
  } = require('../../ci-visibility/telemetry')
16
16
  const { buildCacheKey, writeToCache, withCache } = require('../requests/fs-cache')
17
+ const { validateSkippableTestsResponse } = require('../test-optimization-http-cache-schema')
18
+
19
+ function parseJsonResponse (rawJson) {
20
+ return typeof rawJson === 'string' ? JSON.parse(rawJson) : rawJson
21
+ }
22
+
23
+ function parseSkippableSuitesResponse (
24
+ rawJson,
25
+ { testLevel = 'suite', isCoverageReportUploadEnabled = false, validateRequiredFields = false } = {}
26
+ ) {
27
+ const parsedResponse = parseJsonResponse(rawJson)
28
+ if (validateRequiredFields) {
29
+ validateSkippableTestsResponse(parsedResponse)
30
+ }
31
+ const coverage = parsedResponse.meta?.coverage || {}
32
+
33
+ const skippableItems = parsedResponse
34
+ .data
35
+ .filter(({ type }) => type === testLevel)
36
+ const skippableSuites = []
37
+ for (const {
38
+ attributes: {
39
+ suite,
40
+ name,
41
+ _is_missing_line_code_coverage: isMissingLineCodeCoverage,
42
+ },
43
+ } of skippableItems) {
44
+ // Only reject candidates without backend line coverage when we need that coverage to backfill reports.
45
+ if (isCoverageReportUploadEnabled && isMissingLineCodeCoverage) continue
46
+
47
+ skippableSuites.push(testLevel === 'suite' ? suite : { suite, name })
48
+ }
49
+ const correlationId = parsedResponse.meta?.correlation_id
50
+
51
+ return { skippableSuites, correlationId, coverage }
52
+ }
17
53
 
18
54
  function getSkippableSuites ({
19
55
  url,
@@ -124,12 +160,12 @@ function fetchFromApi ({
124
160
  options.path = `${evpProxyPrefix}/api/v2/ci/tests/skippable`
125
161
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
126
162
  } else {
127
- const { apiKey } = getConfig()
128
- if (!apiKey) {
163
+ const { DD_API_KEY } = getConfig()
164
+ if (!DD_API_KEY) {
129
165
  return done(new Error('Skippable suites were not fetched because Datadog API key is not defined.'))
130
166
  }
131
167
 
132
- options.headers['dd-api-key'] = apiKey
168
+ options.headers['dd-api-key'] = DD_API_KEY
133
169
  }
134
170
 
135
171
  const data = JSON.stringify({
@@ -163,26 +199,12 @@ function fetchFromApi ({
163
199
  done(err)
164
200
  } else {
165
201
  try {
166
- const parsedResponse = JSON.parse(res)
167
- const coverage = parsedResponse.meta?.coverage || {}
168
-
169
- const skippableItems = parsedResponse
170
- .data
171
- .filter(({ type }) => type === testLevel)
172
- const skippableSuites = []
173
- for (const {
174
- attributes: {
175
- suite,
176
- name,
177
- _is_missing_line_code_coverage: isMissingLineCodeCoverage,
178
- },
179
- } of skippableItems) {
180
- // Only reject candidates without backend line coverage when we need that coverage to backfill reports.
181
- if (isCoverageReportUploadEnabled && isMissingLineCodeCoverage) continue
182
-
183
- skippableSuites.push(testLevel === 'suite' ? suite : { suite, name })
184
- }
185
- const correlationId = parsedResponse.meta?.correlation_id
202
+ const parsedResponse = parseJsonResponse(res)
203
+ const result = parseSkippableSuitesResponse(parsedResponse, {
204
+ testLevel,
205
+ isCoverageReportUploadEnabled,
206
+ })
207
+ const skippableItems = parsedResponse.data.filter(({ type }) => type === testLevel)
186
208
  incrementCountMetric(
187
209
  testLevel === 'test'
188
210
  ? TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS
@@ -191,9 +213,8 @@ function fetchFromApi ({
191
213
  skippableItems.length
192
214
  )
193
215
  distributionMetric(TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES, {}, res.length)
194
- log.debug('Number of received skippable %ss:', testLevel, skippableSuites.length)
216
+ log.debug('Number of received skippable %ss:', testLevel, result.skippableSuites.length)
195
217
 
196
- const result = { skippableSuites, correlationId, coverage }
197
218
  writeToCache(cacheKey, result)
198
219
 
199
220
  done(null, result)
@@ -204,4 +225,4 @@ function fetchFromApi ({
204
225
  })
205
226
  }
206
227
 
207
- module.exports = { getSkippableSuites }
228
+ module.exports = { getSkippableSuites, parseSkippableSuitesResponse }
@@ -4,14 +4,14 @@ const Plugin = require('../../plugins/plugin')
4
4
  const log = require('../../log')
5
5
 
6
6
  function getWinstonLogSubmissionParameters (config) {
7
- const { site, service, apiKey, DD_AGENTLESS_LOG_SUBMISSION_URL } = config
7
+ const { site, service, DD_API_KEY, DD_AGENTLESS_LOG_SUBMISSION_URL } = config
8
8
 
9
9
  const defaultParameters = {
10
10
  host: `http-intake.logs.${site}`,
11
11
  path: `/api/v2/logs?ddsource=winston&service=${service}`,
12
12
  ssl: true,
13
13
  headers: {
14
- 'DD-API-KEY': apiKey,
14
+ 'DD-API-KEY': DD_API_KEY,
15
15
  },
16
16
  }
17
17
 
@@ -12,12 +12,72 @@ const {
12
12
  TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE,
13
13
  } = require('../telemetry')
14
14
  const { writeSettingsToCache } = require('../test-optimization-cache')
15
+ const { validateSettingsResponse } = require('../test-optimization-http-cache-schema')
15
16
  const request = require('./request')
16
17
 
17
18
  const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
18
19
  const DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES = { '5s': 10, '10s': 5, '30s': 3, '5m': 2 }
19
20
  const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30
20
21
 
22
+ function parseJsonResponse (rawJson) {
23
+ return typeof rawJson === 'string' ? JSON.parse(rawJson) : rawJson
24
+ }
25
+
26
+ function parseLibraryConfigurationResponse (rawJson, config = getConfig(), options = {}) {
27
+ const parsedResponse = parseJsonResponse(rawJson)
28
+ if (options.validateRequiredFields) {
29
+ validateSettingsResponse(parsedResponse)
30
+ }
31
+ const {
32
+ code_coverage: isCodeCoverageEnabled,
33
+ tests_skipping: isSuitesSkippingEnabled,
34
+ itr_enabled: isItrEnabled,
35
+ require_git: requireGit,
36
+ early_flake_detection: earlyFlakeDetectionConfig,
37
+ flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
38
+ di_enabled: isDiEnabled,
39
+ known_tests_enabled: isKnownTestsEnabled,
40
+ test_management: testManagementConfig,
41
+ impacted_tests_enabled: isImpactedTestsEnabled,
42
+ coverage_report_upload_enabled: isCoverageReportUploadEnabled,
43
+ } = parsedResponse?.data?.attributes ?? parsedResponse
44
+
45
+ const settings = {
46
+ isCodeCoverageEnabled,
47
+ isSuitesSkippingEnabled,
48
+ isItrEnabled,
49
+ requireGit,
50
+ isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
51
+ earlyFlakeDetectionNumRetries:
52
+ earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
53
+ earlyFlakeDetectionSlowTestRetries:
54
+ earlyFlakeDetectionConfig?.slow_test_retries ?? DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
55
+ earlyFlakeDetectionFaultyThreshold:
56
+ earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
57
+ isFlakyTestRetriesEnabled,
58
+ isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
59
+ isKnownTestsEnabled,
60
+ isTestManagementEnabled: (testManagementConfig?.enabled ?? false),
61
+ testManagementAttemptToFixRetries:
62
+ testManagementConfig?.attempt_to_fix_retries,
63
+ isImpactedTestsEnabled,
64
+ isCoverageReportUploadEnabled: isCoverageReportUploadEnabled ?? false,
65
+ }
66
+
67
+ log.debug('Remote settings: %j', settings)
68
+
69
+ if (config.testOptimization.DD_CIVISIBILITY_DANGEROUSLY_FORCE_COVERAGE) {
70
+ settings.isCodeCoverageEnabled = true
71
+ log.debug('Dangerously set code coverage to true')
72
+ }
73
+ if (config.testOptimization.DD_CIVISIBILITY_DANGEROUSLY_FORCE_TEST_SKIPPING) {
74
+ settings.isSuitesSkippingEnabled = true
75
+ log.debug('Dangerously set test skipping to true')
76
+ }
77
+
78
+ return settings
79
+ }
80
+
21
81
  function getLibraryConfiguration ({
22
82
  url,
23
83
  isEvpProxy,
@@ -51,10 +111,10 @@ function getLibraryConfiguration ({
51
111
  options.path = `${evpProxyPrefix}/api/v2/libraries/tests/services/setting`
52
112
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
53
113
  } else {
54
- if (!config.apiKey) {
114
+ if (!config.DD_API_KEY) {
55
115
  return done(new Error('Request to settings endpoint was not done because Datadog API key is not defined.'))
56
116
  }
57
- options.headers['dd-api-key'] = config.apiKey
117
+ options.headers['dd-api-key'] = config.DD_API_KEY
58
118
  }
59
119
 
60
120
  const data = JSON.stringify({
@@ -90,56 +150,7 @@ function getLibraryConfiguration ({
90
150
  done(err)
91
151
  } else {
92
152
  try {
93
- const {
94
- data: {
95
- attributes: {
96
- code_coverage: isCodeCoverageEnabled,
97
- tests_skipping: isSuitesSkippingEnabled,
98
- itr_enabled: isItrEnabled,
99
- require_git: requireGit,
100
- early_flake_detection: earlyFlakeDetectionConfig,
101
- flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
102
- di_enabled: isDiEnabled,
103
- known_tests_enabled: isKnownTestsEnabled,
104
- test_management: testManagementConfig,
105
- impacted_tests_enabled: isImpactedTestsEnabled,
106
- coverage_report_upload_enabled: isCoverageReportUploadEnabled,
107
- },
108
- },
109
- } = JSON.parse(res)
110
-
111
- const settings = {
112
- isCodeCoverageEnabled,
113
- isSuitesSkippingEnabled,
114
- isItrEnabled,
115
- requireGit,
116
- isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
117
- earlyFlakeDetectionNumRetries:
118
- earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
119
- earlyFlakeDetectionSlowTestRetries:
120
- earlyFlakeDetectionConfig?.slow_test_retries ?? DEFAULT_EARLY_FLAKE_DETECTION_SLOW_TEST_RETRIES,
121
- earlyFlakeDetectionFaultyThreshold:
122
- earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
123
- isFlakyTestRetriesEnabled,
124
- isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
125
- isKnownTestsEnabled,
126
- isTestManagementEnabled: (testManagementConfig?.enabled ?? false),
127
- testManagementAttemptToFixRetries:
128
- testManagementConfig?.attempt_to_fix_retries,
129
- isImpactedTestsEnabled,
130
- isCoverageReportUploadEnabled: isCoverageReportUploadEnabled ?? false,
131
- }
132
-
133
- log.debug('Remote settings: %j', settings)
134
-
135
- if (config.DD_CIVISIBILITY_DANGEROUSLY_FORCE_COVERAGE) {
136
- settings.isCodeCoverageEnabled = true
137
- log.debug('Dangerously set code coverage to true')
138
- }
139
- if (config.DD_CIVISIBILITY_DANGEROUSLY_FORCE_TEST_SKIPPING) {
140
- settings.isSuitesSkippingEnabled = true
141
- log.debug('Dangerously set test skipping to true')
142
- }
153
+ const settings = parseLibraryConfigurationResponse(res, config)
143
154
 
144
155
  incrementCountMetric(TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE, settings)
145
156
 
@@ -153,4 +164,4 @@ function getLibraryConfiguration ({
153
164
  })
154
165
  }
155
166
 
156
- module.exports = { getLibraryConfiguration }
167
+ module.exports = { getLibraryConfiguration, parseLibraryConfigurationResponse }
@@ -34,9 +34,9 @@ function uploadCoverageReport (
34
34
  { filePath, format, testEnvironmentMetadata, url, isEvpProxy, evpProxyPrefix },
35
35
  callback
36
36
  ) {
37
- const apiKey = getConfig().apiKey
37
+ const { DD_API_KEY } = getConfig()
38
38
 
39
- if (!apiKey && !isEvpProxy) {
39
+ if (!DD_API_KEY && !isEvpProxy) {
40
40
  return callback(new Error('DD_API_KEY is required for coverage report upload'))
41
41
  }
42
42
 
@@ -82,7 +82,7 @@ function uploadCoverageReport (
82
82
  options.headers['X-Datadog-EVP-Subdomain'] = 'ci-intake'
83
83
  } else {
84
84
  options.path = '/api/v2/cicovreprt'
85
- options.headers['dd-api-key'] = apiKey
85
+ options.headers['dd-api-key'] = DD_API_KEY
86
86
  }
87
87
 
88
88
  log.debug('Uploading coverage report %s to %s%s', filePath, url, options.path)
@@ -16,6 +16,7 @@ const {
16
16
  } = require('../telemetry')
17
17
 
18
18
  const { buildCacheKey, writeToCache, withCache } = require('../requests/fs-cache')
19
+ const { validateTestManagementTestsResponse } = require('../test-optimization-http-cache-schema')
19
20
 
20
21
  // Calculate the number of tests from the test management tests response, which has a shape like:
21
22
  // { module: { suites: { suite: { tests: { testName: { properties: {...} } } } } } }
@@ -39,6 +40,19 @@ function getNumFromTestManagementTests (testManagementTests) {
39
40
  return totalNumTests
40
41
  }
41
42
 
43
+ function parseJsonResponse (rawJson) {
44
+ return typeof rawJson === 'string' ? JSON.parse(rawJson) : rawJson
45
+ }
46
+
47
+ function parseTestManagementTestsResponse (rawJson, options = {}) {
48
+ const parsedResponse = parseJsonResponse(rawJson)
49
+ if (options.validateRequiredFields) {
50
+ validateTestManagementTestsResponse(parsedResponse)
51
+ }
52
+ const { data: { attributes: { modules: testManagementTests } } } = parsedResponse
53
+ return testManagementTests
54
+ }
55
+
42
56
  function getTestManagementTests ({
43
57
  url,
44
58
  isEvpProxy,
@@ -121,12 +135,12 @@ function fetchFromApi ({
121
135
  options.path = `${evpProxyPrefix}/api/v2/test/libraries/test-management/tests`
122
136
  options.headers['X-Datadog-EVP-Subdomain'] = 'api'
123
137
  } else {
124
- const { apiKey } = getConfig()
125
- if (!apiKey) {
138
+ const { DD_API_KEY } = getConfig()
139
+ if (!DD_API_KEY) {
126
140
  return done(new Error('Test management tests were not fetched because Datadog API key is not defined.'))
127
141
  }
128
142
 
129
- options.headers['dd-api-key'] = apiKey
143
+ options.headers['dd-api-key'] = DD_API_KEY
130
144
  }
131
145
 
132
146
  const data = JSON.stringify({
@@ -155,7 +169,7 @@ function fetchFromApi ({
155
169
  done(err)
156
170
  } else {
157
171
  try {
158
- const { data: { attributes: { modules: testManagementTests } } } = JSON.parse(res)
172
+ const testManagementTests = parseTestManagementTestsResponse(res)
159
173
 
160
174
  const numTests = getNumFromTestManagementTests(testManagementTests)
161
175
 
@@ -174,4 +188,8 @@ function fetchFromApi ({
174
188
  })
175
189
  }
176
190
 
177
- module.exports = { getTestManagementTests }
191
+ module.exports = {
192
+ getNumFromTestManagementTests, // Exported for later use in the cache
193
+ getTestManagementTests,
194
+ parseTestManagementTestsResponse,
195
+ }