dd-trace 5.31.0 → 5.33.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 (85) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/README.md +17 -14
  3. package/index.d.ts +11 -1
  4. package/package.json +6 -5
  5. package/packages/datadog-instrumentations/src/aws-sdk.js +4 -1
  6. package/packages/datadog-instrumentations/src/cucumber.js +31 -14
  7. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
  8. package/packages/datadog-instrumentations/src/jest.js +105 -56
  9. package/packages/datadog-instrumentations/src/mocha/main.js +9 -4
  10. package/packages/datadog-instrumentations/src/mocha/utils.js +27 -9
  11. package/packages/datadog-instrumentations/src/mocha/worker.js +4 -2
  12. package/packages/datadog-instrumentations/src/node-serialize.js +22 -0
  13. package/packages/datadog-instrumentations/src/openai.js +2 -0
  14. package/packages/datadog-instrumentations/src/playwright.js +8 -3
  15. package/packages/datadog-instrumentations/src/vitest.js +134 -62
  16. package/packages/datadog-instrumentations/src/vm.js +49 -0
  17. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +16 -0
  18. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +63 -0
  19. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +287 -0
  20. package/packages/datadog-plugin-aws-sdk/src/services/index.js +1 -0
  21. package/packages/datadog-plugin-cucumber/src/index.js +31 -31
  22. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -8
  23. package/packages/datadog-plugin-cypress/src/support.js +6 -2
  24. package/packages/datadog-plugin-fetch/src/index.js +3 -3
  25. package/packages/datadog-plugin-http/src/client.js +5 -33
  26. package/packages/datadog-plugin-jest/src/index.js +37 -37
  27. package/packages/datadog-plugin-langchain/src/index.js +12 -80
  28. package/packages/datadog-plugin-langchain/src/tracing.js +89 -0
  29. package/packages/datadog-plugin-mocha/src/index.js +19 -35
  30. package/packages/datadog-plugin-playwright/src/index.js +3 -1
  31. package/packages/datadog-plugin-vitest/src/index.js +33 -35
  32. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  33. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +2 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +3 -3
  35. package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +16 -0
  36. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -24
  37. package/packages/dd-trace/src/appsec/iast/iast-context.js +12 -0
  38. package/packages/dd-trace/src/appsec/iast/path-line.js +19 -23
  39. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +9 -8
  40. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -0
  41. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  42. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +75 -24
  43. package/packages/dd-trace/src/appsec/rasp/utils.js +10 -5
  44. package/packages/dd-trace/src/appsec/stack_trace.js +38 -28
  45. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +37 -0
  46. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +65 -28
  47. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +57 -17
  48. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -4
  49. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +18 -3
  50. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -3
  51. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +20 -3
  52. package/packages/dd-trace/src/config.js +43 -3
  53. package/packages/dd-trace/src/crashtracking/crashtracker.js +9 -0
  54. package/packages/dd-trace/src/crashtracking/noop.js +3 -0
  55. package/packages/dd-trace/src/datastreams/fnv.js +1 -1
  56. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  57. package/packages/dd-trace/src/debugger/devtools_client/config.js +1 -0
  58. package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -0
  59. package/packages/dd-trace/src/debugger/devtools_client/index.js +30 -13
  60. package/packages/dd-trace/src/debugger/devtools_client/send.js +4 -8
  61. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +35 -1
  62. package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +112 -0
  63. package/packages/dd-trace/src/debugger/devtools_client/status.js +12 -10
  64. package/packages/dd-trace/src/debugger/index.js +2 -13
  65. package/packages/dd-trace/src/llmobs/plugins/base.js +40 -11
  66. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +59 -0
  67. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +24 -0
  68. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +111 -0
  69. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +42 -0
  70. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +102 -0
  71. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +32 -0
  72. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +131 -0
  73. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
  74. package/packages/dd-trace/src/llmobs/tagger.js +11 -3
  75. package/packages/dd-trace/src/llmobs/util.js +7 -1
  76. package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +3 -3
  77. package/packages/dd-trace/src/opentelemetry/context_manager.js +43 -3
  78. package/packages/dd-trace/src/plugins/ci_plugin.js +58 -27
  79. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +0 -2
  80. package/packages/dd-trace/src/plugins/util/test.js +44 -12
  81. package/packages/dd-trace/src/priority_sampler.js +4 -1
  82. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +21 -0
  83. package/packages/dd-trace/src/profiling/profiler.js +11 -8
  84. package/packages/dd-trace/src/profiling/profilers/events.js +17 -1
  85. package/packages/dd-trace/src/proxy.js +6 -3
@@ -201,6 +201,7 @@ function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
201
201
  if (err) {
202
202
  config.knownTests = []
203
203
  config.isEarlyFlakeDetectionEnabled = false
204
+ config.isKnownTestsEnabled = false
204
205
  } else {
205
206
  config.knownTests = knownTests
206
207
  }
@@ -222,12 +223,13 @@ function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
222
223
  config.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
223
224
  config.earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
224
225
  config.earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
226
+ config.isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
225
227
  // ITR and auto test retries are not supported in parallel mode yet
226
228
  config.isSuitesSkippingEnabled = !isParallel && libraryConfig.isSuitesSkippingEnabled
227
229
  config.isFlakyTestRetriesEnabled = !isParallel && libraryConfig.isFlakyTestRetriesEnabled
228
230
  config.flakyTestRetriesCount = !isParallel && libraryConfig.flakyTestRetriesCount
229
231
 
230
- if (config.isEarlyFlakeDetectionEnabled) {
232
+ if (config.isKnownTestsEnabled) {
231
233
  knownTestsCh.publish({
232
234
  onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
233
235
  })
@@ -273,7 +275,7 @@ addHook({
273
275
  })
274
276
 
275
277
  getExecutionConfiguration(runner, false, () => {
276
- if (config.isEarlyFlakeDetectionEnabled) {
278
+ if (config.isKnownTestsEnabled) {
277
279
  const testSuites = this.files.map(file => getTestSuitePath(file, process.cwd()))
278
280
  const isFaulty = getIsFaultyEarlyFlakeDetection(
279
281
  testSuites,
@@ -283,6 +285,7 @@ addHook({
283
285
  if (isFaulty) {
284
286
  config.isEarlyFlakeDetectionEnabled = false
285
287
  config.isEarlyFlakeDetectionFaulty = true
288
+ config.isKnownTestsEnabled = false
286
289
  }
287
290
  }
288
291
  if (getCodeCoverageCh.hasSubscribers) {
@@ -537,7 +540,7 @@ addHook({
537
540
  this.once('end', getOnEndHandler(true))
538
541
 
539
542
  getExecutionConfiguration(this, true, () => {
540
- if (config.isEarlyFlakeDetectionEnabled) {
543
+ if (config.isKnownTestsEnabled) {
541
544
  const testSuites = files.map(file => getTestSuitePath(file, process.cwd()))
542
545
  const isFaulty = getIsFaultyEarlyFlakeDetection(
543
546
  testSuites,
@@ -545,6 +548,7 @@ addHook({
545
548
  config.earlyFlakeDetectionFaultyThreshold
546
549
  )
547
550
  if (isFaulty) {
551
+ config.isKnownTestsEnabled = false
548
552
  config.isEarlyFlakeDetectionEnabled = false
549
553
  config.isEarlyFlakeDetectionFaulty = true
550
554
  }
@@ -569,7 +573,7 @@ addHook({
569
573
  const { BufferedWorkerPool } = BufferedWorkerPoolPackage
570
574
 
571
575
  shimmer.wrap(BufferedWorkerPool.prototype, 'run', run => async function (testSuiteAbsolutePath, workerArgs) {
572
- if (!testStartCh.hasSubscribers || !config.isEarlyFlakeDetectionEnabled) {
576
+ if (!testStartCh.hasSubscribers || !config.isKnownTestsEnabled) {
573
577
  return run.apply(this, arguments)
574
578
  }
575
579
 
@@ -584,6 +588,7 @@ addHook({
584
588
  {
585
589
  ...workerArgs,
586
590
  _ddEfdNumRetries: config.earlyFlakeDetectionNumRetries,
591
+ _ddIsEfdEnabled: config.isEarlyFlakeDetectionEnabled,
587
592
  _ddKnownTests: {
588
593
  mocha: {
589
594
  [testPath]: testSuiteKnownTests
@@ -19,6 +19,7 @@ const skipCh = channel('ci:mocha:test:skip')
19
19
  // suite channels
20
20
  const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
21
21
 
22
+ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
22
23
  const testToAr = new WeakMap()
23
24
  const originalFns = new WeakMap()
24
25
  const testToStartLine = new WeakMap()
@@ -73,7 +74,7 @@ function isMochaRetry (test) {
73
74
  return test._currentRetry !== undefined && test._currentRetry !== 0
74
75
  }
75
76
 
76
- function isLastRetry (test) {
77
+ function getIsLastRetry (test) {
77
78
  return test._currentRetry === test._retries
78
79
  }
79
80
 
@@ -203,14 +204,28 @@ function getOnTestHandler (isMain) {
203
204
  }
204
205
 
205
206
  function getOnTestEndHandler () {
206
- return function (test) {
207
+ return async function (test) {
207
208
  const asyncResource = getTestAsyncResource(test)
208
209
  const status = getTestStatus(test)
209
210
 
211
+ // After finishing it might take a bit for the snapshot to be handled.
212
+ // This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
213
+ if (test._ddShouldWaitForHitProbe || test._retriedTest?._ddShouldWaitForHitProbe) {
214
+ await new Promise((resolve) => {
215
+ setTimeout(() => {
216
+ resolve()
217
+ }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
218
+ })
219
+ }
220
+
210
221
  // if there are afterEach to be run, we don't finish the test yet
211
222
  if (asyncResource && !test.parent._afterEach.length) {
212
223
  asyncResource.runInAsyncScope(() => {
213
- testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test) })
224
+ testFinishCh.publish({
225
+ status,
226
+ hasBeenRetried: isMochaRetry(test),
227
+ isLastRetry: getIsLastRetry(test)
228
+ })
214
229
  })
215
230
  }
216
231
  }
@@ -220,16 +235,17 @@ function getOnHookEndHandler () {
220
235
  return function (hook) {
221
236
  const test = hook.ctx.currentTest
222
237
  if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
223
- const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
224
- if (test._retries > 0 && !isLastRetry(test)) {
238
+ const isLastRetry = getIsLastRetry(test)
239
+ if (test._retries > 0 && !isLastRetry) {
225
240
  return
226
241
  }
242
+ const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
227
243
  if (isLastAfterEach) {
228
244
  const status = getTestStatus(test)
229
245
  const asyncResource = getTestAsyncResource(test)
230
246
  if (asyncResource) {
231
247
  asyncResource.runInAsyncScope(() => {
232
- testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test) })
248
+ testFinishCh.publish({ status, hasBeenRetried: isMochaRetry(test), isLastRetry })
233
249
  })
234
250
  }
235
251
  }
@@ -286,7 +302,7 @@ function getOnTestRetryHandler () {
286
302
  const isFirstAttempt = test._currentRetry === 0
287
303
  const willBeRetried = test._currentRetry < test._retries
288
304
  asyncResource.runInAsyncScope(() => {
289
- testRetryCh.publish({ isFirstAttempt, err, willBeRetried })
305
+ testRetryCh.publish({ isFirstAttempt, err, willBeRetried, test })
290
306
  })
291
307
  }
292
308
  const key = getTestToArKey(test)
@@ -333,12 +349,14 @@ function getOnPendingHandler () {
333
349
  // Hook to add retries to tests if EFD is enabled
334
350
  function getRunTestsWrapper (runTests, config) {
335
351
  return function (suite, fn) {
336
- if (config.isEarlyFlakeDetectionEnabled) {
352
+ if (config.isKnownTestsEnabled) {
337
353
  // by the time we reach `this.on('test')`, it is too late. We need to add retries here
338
354
  suite.tests.forEach(test => {
339
355
  if (!test.isPending() && isNewTest(test, config.knownTests)) {
340
356
  test._ddIsNew = true
341
- retryTest(test, config.earlyFlakeDetectionNumRetries)
357
+ if (config.isEarlyFlakeDetectionEnabled) {
358
+ retryTest(test, config.earlyFlakeDetectionNumRetries)
359
+ }
342
360
  }
343
361
  })
344
362
  }
@@ -25,10 +25,12 @@ addHook({
25
25
  }, (Mocha) => {
26
26
  shimmer.wrap(Mocha.prototype, 'run', run => function () {
27
27
  if (this.options._ddKnownTests) {
28
- // EFD is enabled if there's a list of known tests
29
- config.isEarlyFlakeDetectionEnabled = true
28
+ // If there are known tests, it means isKnownTestsEnabled should be true
29
+ config.isKnownTestsEnabled = true
30
+ config.isEarlyFlakeDetectionEnabled = this.options._ddIsEfdEnabled
30
31
  config.knownTests = this.options._ddKnownTests
31
32
  config.earlyFlakeDetectionNumRetries = this.options._ddEfdNumRetries
33
+ delete this.options._ddIsEfdEnabled
32
34
  delete this.options._ddKnownTests
33
35
  delete this.options._ddEfdNumRetries
34
36
  }
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const shimmer = require('../../datadog-shimmer')
4
+ const { channel, addHook } = require('./helpers/instrument')
5
+
6
+ const nodeUnserializeCh = channel('datadog:node-serialize:unserialize:start')
7
+
8
+ function wrapUnserialize (serialize) {
9
+ return function wrappedUnserialize (obj) {
10
+ if (nodeUnserializeCh.hasSubscribers) {
11
+ nodeUnserializeCh.publish({ obj })
12
+ }
13
+
14
+ return serialize.apply(this, arguments)
15
+ }
16
+ }
17
+
18
+ addHook({ name: 'node-serialize', versions: ['0.0.4'] }, serialize => {
19
+ shimmer.wrap(serialize, 'unserialize', wrapUnserialize)
20
+
21
+ return serialize
22
+ })
@@ -338,6 +338,8 @@ for (const shim of V4_PACKAGE_SHIMS) {
338
338
  })
339
339
  })
340
340
 
341
+ ch.end.publish(ctx)
342
+
341
343
  return apiProm
342
344
  })
343
345
  })
@@ -35,6 +35,7 @@ const STATUS_TO_TEST_STATUS = {
35
35
  }
36
36
 
37
37
  let remainingTestsByFile = {}
38
+ let isKnownTestsEnabled = false
38
39
  let isEarlyFlakeDetectionEnabled = false
39
40
  let earlyFlakeDetectionNumRetries = 0
40
41
  let isFlakyTestRetriesEnabled = false
@@ -418,6 +419,7 @@ function runnerHook (runnerExport, playwrightVersion) {
418
419
  try {
419
420
  const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh)
420
421
  if (!err) {
422
+ isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
421
423
  isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
422
424
  earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
423
425
  isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
@@ -425,19 +427,22 @@ function runnerHook (runnerExport, playwrightVersion) {
425
427
  }
426
428
  } catch (e) {
427
429
  isEarlyFlakeDetectionEnabled = false
430
+ isKnownTestsEnabled = false
428
431
  log.error('Playwright session start error', e)
429
432
  }
430
433
 
431
- if (isEarlyFlakeDetectionEnabled && semver.gte(playwrightVersion, MINIMUM_SUPPORTED_VERSION_EFD)) {
434
+ if (isKnownTestsEnabled && semver.gte(playwrightVersion, MINIMUM_SUPPORTED_VERSION_EFD)) {
432
435
  try {
433
436
  const { err, knownTests: receivedKnownTests } = await getChannelPromise(knownTestsCh)
434
437
  if (!err) {
435
438
  knownTests = receivedKnownTests
436
439
  } else {
437
440
  isEarlyFlakeDetectionEnabled = false
441
+ isKnownTestsEnabled = false
438
442
  }
439
443
  } catch (err) {
440
444
  isEarlyFlakeDetectionEnabled = false
445
+ isKnownTestsEnabled = false
441
446
  log.error('Playwright known tests error', err)
442
447
  }
443
448
  }
@@ -553,7 +558,7 @@ addHook({
553
558
 
554
559
  async function newCreateRootSuite () {
555
560
  const rootSuite = await oldCreateRootSuite.apply(this, arguments)
556
- if (!isEarlyFlakeDetectionEnabled) {
561
+ if (!isKnownTestsEnabled) {
557
562
  return rootSuite
558
563
  }
559
564
  const newTests = rootSuite
@@ -562,7 +567,7 @@ addHook({
562
567
 
563
568
  newTests.forEach(newTest => {
564
569
  newTest._ddIsNew = true
565
- if (newTest.expectedStatus !== 'skipped') {
570
+ if (isEarlyFlakeDetectionEnabled && newTest.expectedStatus !== 'skipped') {
566
571
  const fileSuite = getSuiteType(newTest, 'file')
567
572
  const projectSuite = getSuiteType(newTest, 'project')
568
573
  for (let repeatEachIndex = 0; repeatEachIndex < earlyFlakeDetectionNumRetries; repeatEachIndex++) {
@@ -25,9 +25,49 @@ const isEarlyFlakeDetectionFaultyCh = channel('ci:vitest:is-early-flake-detectio
25
25
  const taskToAsync = new WeakMap()
26
26
  const taskToStatuses = new WeakMap()
27
27
  const newTasks = new WeakSet()
28
+ let isRetryReasonEfd = false
28
29
  const switchedStatuses = new WeakSet()
29
30
  const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
30
31
 
32
+ const BREAKPOINT_HIT_GRACE_PERIOD_MS = 400
33
+
34
+ function waitForHitProbe () {
35
+ return new Promise(resolve => {
36
+ setTimeout(() => {
37
+ resolve()
38
+ }, BREAKPOINT_HIT_GRACE_PERIOD_MS)
39
+ })
40
+ }
41
+
42
+ function getProvidedContext () {
43
+ try {
44
+ const {
45
+ _ddIsEarlyFlakeDetectionEnabled,
46
+ _ddIsDiEnabled,
47
+ _ddKnownTests: knownTests,
48
+ _ddEarlyFlakeDetectionNumRetries: numRepeats,
49
+ _ddIsKnownTestsEnabled: isKnownTestsEnabled
50
+ } = globalThis.__vitest_worker__.providedContext
51
+
52
+ return {
53
+ isDiEnabled: _ddIsDiEnabled,
54
+ isEarlyFlakeDetectionEnabled: _ddIsEarlyFlakeDetectionEnabled,
55
+ knownTests,
56
+ numRepeats,
57
+ isKnownTestsEnabled
58
+ }
59
+ } catch (e) {
60
+ log.error('Vitest workers could not parse provided context, so some features will not work.')
61
+ return {
62
+ isDiEnabled: false,
63
+ isEarlyFlakeDetectionEnabled: false,
64
+ knownTests: {},
65
+ numRepeats: 0,
66
+ isKnownTestsEnabled: false
67
+ }
68
+ }
69
+ }
70
+
31
71
  function isReporterPackage (vitestPackage) {
32
72
  return vitestPackage.B?.name === 'BaseSequencer'
33
73
  }
@@ -117,6 +157,7 @@ function getSortWrapper (sort) {
117
157
  let isEarlyFlakeDetectionEnabled = false
118
158
  let earlyFlakeDetectionNumRetries = 0
119
159
  let isEarlyFlakeDetectionFaulty = false
160
+ let isKnownTestsEnabled = false
120
161
  let isDiEnabled = false
121
162
  let knownTests = {}
122
163
 
@@ -128,22 +169,26 @@ function getSortWrapper (sort) {
128
169
  isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
129
170
  earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
130
171
  isDiEnabled = libraryConfig.isDiEnabled
172
+ isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
131
173
  }
132
174
  } catch (e) {
133
175
  isFlakyTestRetriesEnabled = false
134
176
  isEarlyFlakeDetectionEnabled = false
135
177
  isDiEnabled = false
178
+ isKnownTestsEnabled = false
136
179
  }
137
180
 
138
181
  if (isFlakyTestRetriesEnabled && !this.ctx.config.retry && flakyTestRetriesCount > 0) {
139
182
  this.ctx.config.retry = flakyTestRetriesCount
140
183
  }
141
184
 
142
- if (isEarlyFlakeDetectionEnabled) {
185
+ if (isKnownTestsEnabled) {
143
186
  const knownTestsResponse = await getChannelPromise(knownTestsCh)
144
187
  if (!knownTestsResponse.err) {
145
188
  knownTests = knownTestsResponse.knownTests
146
- const testFilepaths = await this.ctx.getTestFilepaths()
189
+ const getFilePaths = this.ctx.getTestFilepaths || this.ctx._globTestFilepaths
190
+
191
+ const testFilepaths = await getFilePaths.call(this.ctx)
147
192
 
148
193
  isEarlyFlakeDetectionFaultyCh.publish({
149
194
  knownTests: knownTests.vitest || {},
@@ -154,13 +199,15 @@ function getSortWrapper (sort) {
154
199
  })
155
200
  if (isEarlyFlakeDetectionFaulty) {
156
201
  isEarlyFlakeDetectionEnabled = false
157
- log.warn('Early flake detection is disabled because the number of new tests is too high.')
202
+ isKnownTestsEnabled = false
203
+ log.warn('New test detection is disabled because the number of new tests is too high.')
158
204
  } else {
159
205
  // TODO: use this to pass session and module IDs to the worker, instead of polluting process.env
160
206
  // Note: setting this.ctx.config.provide directly does not work because it's cached
161
207
  try {
162
208
  const workspaceProject = this.ctx.getCoreWorkspaceProject()
163
- workspaceProject._provided._ddKnownTests = knownTests.vitest
209
+ workspaceProject._provided._ddIsKnownTestsEnabled = isKnownTestsEnabled
210
+ workspaceProject._provided._ddKnownTests = knownTests.vitest || {}
164
211
  workspaceProject._provided._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
165
212
  workspaceProject._provided._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
166
213
  } catch (e) {
@@ -169,6 +216,7 @@ function getSortWrapper (sort) {
169
216
  }
170
217
  } else {
171
218
  isEarlyFlakeDetectionEnabled = false
219
+ isKnownTestsEnabled = false
172
220
  }
173
221
  }
174
222
 
@@ -253,29 +301,30 @@ addHook({
253
301
  // `onBeforeRunTask` is run before any repetition or attempt is run
254
302
  shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => async function (task) {
255
303
  const testName = getTestName(task)
256
- try {
257
- const {
258
- _ddKnownTests: knownTests,
259
- _ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled,
260
- _ddEarlyFlakeDetectionNumRetries: numRepeats
261
- } = globalThis.__vitest_worker__.providedContext
262
-
263
- if (isEarlyFlakeDetectionEnabled) {
264
- isNewTestCh.publish({
265
- knownTests,
266
- testSuiteAbsolutePath: task.file.filepath,
267
- testName,
268
- onDone: (isNew) => {
269
- if (isNew) {
304
+
305
+ const {
306
+ knownTests,
307
+ isEarlyFlakeDetectionEnabled,
308
+ isKnownTestsEnabled,
309
+ numRepeats
310
+ } = getProvidedContext()
311
+
312
+ if (isKnownTestsEnabled) {
313
+ isNewTestCh.publish({
314
+ knownTests,
315
+ testSuiteAbsolutePath: task.file.filepath,
316
+ testName,
317
+ onDone: (isNew) => {
318
+ if (isNew) {
319
+ if (isEarlyFlakeDetectionEnabled) {
320
+ isRetryReasonEfd = task.repeats !== numRepeats
270
321
  task.repeats = numRepeats
271
- newTasks.add(task)
272
- taskToStatuses.set(task, [])
273
322
  }
323
+ newTasks.add(task)
324
+ taskToStatuses.set(task, [])
274
325
  }
275
- })
276
- }
277
- } catch (e) {
278
- log.error('Vitest workers could not parse known tests, so Early Flake Detection will not work.')
326
+ }
327
+ })
279
328
  }
280
329
 
281
330
  return onBeforeRunTask.apply(this, arguments)
@@ -283,9 +332,7 @@ addHook({
283
332
 
284
333
  // `onAfterRunTask` is run after all repetitions or attempts are run
285
334
  shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => async function (task) {
286
- const {
287
- _ddIsEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled
288
- } = globalThis.__vitest_worker__.providedContext
335
+ const { isEarlyFlakeDetectionEnabled } = getProvidedContext()
289
336
 
290
337
  if (isEarlyFlakeDetectionEnabled && taskToStatuses.has(task)) {
291
338
  const statuses = taskToStatuses.get(task)
@@ -309,43 +356,41 @@ addHook({
309
356
  }
310
357
  const testName = getTestName(task)
311
358
  let isNew = false
312
- let isEarlyFlakeDetectionEnabled = false
313
- let isDiEnabled = false
314
359
 
315
- try {
316
- const {
317
- _ddIsEarlyFlakeDetectionEnabled,
318
- _ddIsDiEnabled
319
- } = globalThis.__vitest_worker__.providedContext
320
-
321
- isEarlyFlakeDetectionEnabled = _ddIsEarlyFlakeDetectionEnabled
322
- isDiEnabled = _ddIsDiEnabled
360
+ const {
361
+ isKnownTestsEnabled,
362
+ isEarlyFlakeDetectionEnabled,
363
+ isDiEnabled
364
+ } = getProvidedContext()
323
365
 
324
- if (isEarlyFlakeDetectionEnabled) {
325
- isNew = newTasks.has(task)
326
- }
327
- } catch (e) {
328
- log.error('Vitest workers could not parse known tests, so Early Flake Detection will not work.')
366
+ if (isKnownTestsEnabled) {
367
+ isNew = newTasks.has(task)
329
368
  }
369
+
330
370
  const { retry: numAttempt, repeats: numRepetition } = retryInfo
331
371
 
332
372
  // We finish the previous test here because we know it has failed already
333
373
  if (numAttempt > 0) {
334
- const probe = {}
374
+ const shouldWaitForHitProbe = isDiEnabled && numAttempt > 1
375
+ if (shouldWaitForHitProbe) {
376
+ await waitForHitProbe()
377
+ }
378
+
379
+ const promises = {}
380
+ const shouldSetProbe = isDiEnabled && numAttempt === 1
335
381
  const asyncResource = taskToAsync.get(task)
336
382
  const testError = task.result?.errors?.[0]
337
383
  if (asyncResource) {
338
384
  asyncResource.runInAsyncScope(() => {
339
385
  testErrorCh.publish({
340
386
  error: testError,
341
- willBeRetried: true,
342
- probe,
343
- isDiEnabled
387
+ shouldSetProbe,
388
+ promises
344
389
  })
345
390
  })
346
391
  // We wait for the probe to be set
347
- if (probe.setProbePromise) {
348
- await probe.setProbePromise
392
+ if (promises.setProbePromise) {
393
+ await promises.setProbePromise
349
394
  }
350
395
  }
351
396
  }
@@ -401,7 +446,9 @@ addHook({
401
446
  testName,
402
447
  testSuiteAbsolutePath: task.file.filepath,
403
448
  isRetry: numAttempt > 0 || numRepetition > 0,
404
- isNew
449
+ isRetryReasonEfd,
450
+ isNew,
451
+ mightHitProbe: isDiEnabled && numAttempt > 0
405
452
  })
406
453
  })
407
454
  return onBeforeTryTask.apply(this, arguments)
@@ -418,6 +465,12 @@ addHook({
418
465
  const status = getVitestTestStatus(task, retryCount)
419
466
  const asyncResource = taskToAsync.get(task)
420
467
 
468
+ const { isDiEnabled } = getProvidedContext()
469
+
470
+ if (isDiEnabled && retryCount > 1) {
471
+ await waitForHitProbe()
472
+ }
473
+
421
474
  if (asyncResource) {
422
475
  // We don't finish here because the test might fail in a later hook (afterEach)
423
476
  asyncResource.runInAsyncScope(() => {
@@ -457,15 +510,6 @@ addHook({
457
510
  return vitestPackage
458
511
  })
459
512
 
460
- addHook({
461
- name: 'vitest',
462
- versions: ['>=2.1.0'],
463
- filePattern: 'dist/chunks/RandomSequencer.*'
464
- }, (randomSequencerPackage) => {
465
- shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
466
- return randomSequencerPackage
467
- })
468
-
469
513
  addHook({
470
514
  name: 'vitest',
471
515
  versions: ['>=2.0.5 <2.1.0'],
@@ -478,6 +522,24 @@ addHook({
478
522
  return vitestPackage
479
523
  })
480
524
 
525
+ addHook({
526
+ name: 'vitest',
527
+ versions: ['>=2.1.0 <3.0.0'],
528
+ filePattern: 'dist/chunks/RandomSequencer.*'
529
+ }, (randomSequencerPackage) => {
530
+ shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
531
+ return randomSequencerPackage
532
+ })
533
+
534
+ addHook({
535
+ name: 'vitest',
536
+ versions: ['>=3.0.0'],
537
+ filePattern: 'dist/chunks/resolveConfig.*'
538
+ }, (randomSequencerPackage) => {
539
+ shimmer.wrap(randomSequencerPackage.B.prototype, 'sort', getSortWrapper)
540
+ return randomSequencerPackage
541
+ })
542
+
481
543
  // Can't specify file because compiled vitest includes hashes in their files
482
544
  addHook({
483
545
  name: 'vitest',
@@ -498,15 +560,17 @@ addHook({
498
560
  versions: ['>=1.6.0'],
499
561
  file: 'dist/index.js'
500
562
  }, (vitestPackage, frameworkVersion) => {
501
- shimmer.wrap(vitestPackage, 'startTests', startTests => async function (testPath) {
563
+ shimmer.wrap(vitestPackage, 'startTests', startTests => async function (testPaths) {
502
564
  let testSuiteError = null
503
565
  if (!testSuiteStartCh.hasSubscribers) {
504
566
  return startTests.apply(this, arguments)
505
567
  }
568
+ // From >=3.0.1, the first arguments changes from a string to an object containing the filepath
569
+ const testSuiteAbsolutePath = testPaths[0]?.filepath || testPaths[0]
506
570
 
507
571
  const testSuiteAsyncResource = new AsyncResource('bound-anonymous-fn')
508
572
  testSuiteAsyncResource.runInAsyncScope(() => {
509
- testSuiteStartCh.publish({ testSuiteAbsolutePath: testPath[0], frameworkVersion })
573
+ testSuiteStartCh.publish({ testSuiteAbsolutePath, frameworkVersion })
510
574
  })
511
575
  const startTestsResponse = await startTests.apply(this, arguments)
512
576
 
@@ -528,7 +592,11 @@ addHook({
528
592
  if (result) {
529
593
  const { state, duration, errors } = result
530
594
  if (state === 'skip') { // programmatic skip
531
- testSkipCh.publish({ testName: getTestName(task), testSuiteAbsolutePath: task.file.filepath })
595
+ testSkipCh.publish({
596
+ testName: getTestName(task),
597
+ testSuiteAbsolutePath: task.file.filepath,
598
+ isNew: newTasks.has(task)
599
+ })
532
600
  } else if (state === 'pass' && !isSwitchedStatus) {
533
601
  if (testAsyncResource) {
534
602
  testAsyncResource.runInAsyncScope(() => {
@@ -554,7 +622,11 @@ addHook({
554
622
  }
555
623
  }
556
624
  } else { // test.skip or test.todo
557
- testSkipCh.publish({ testName: getTestName(task), testSuiteAbsolutePath: task.file.filepath })
625
+ testSkipCh.publish({
626
+ testName: getTestName(task),
627
+ testSuiteAbsolutePath: task.file.filepath,
628
+ isNew: newTasks.has(task)
629
+ })
558
630
  }
559
631
  })
560
632
 
@@ -0,0 +1,49 @@
1
+ 'use strict'
2
+
3
+ const { channel, addHook } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+ const names = ['vm', 'node:vm']
6
+
7
+ const runScriptStartChannel = channel('datadog:vm:run-script:start')
8
+ const sourceTextModuleStartChannel = channel('datadog:vm:source-text-module:start')
9
+
10
+ addHook({ name: names }, function (vm) {
11
+ vm.Script = class extends vm.Script {
12
+ constructor (code) {
13
+ super(...arguments)
14
+
15
+ if (runScriptStartChannel.hasSubscribers && code) {
16
+ runScriptStartChannel.publish({ code })
17
+ }
18
+ }
19
+ }
20
+
21
+ if (vm.SourceTextModule && typeof vm.SourceTextModule === 'function') {
22
+ vm.SourceTextModule = class extends vm.SourceTextModule {
23
+ constructor (code) {
24
+ super(...arguments)
25
+
26
+ if (sourceTextModuleStartChannel.hasSubscribers && code) {
27
+ sourceTextModuleStartChannel.publish({ code })
28
+ }
29
+ }
30
+ }
31
+ }
32
+
33
+ shimmer.wrap(vm, 'runInContext', wrapVMMethod)
34
+ shimmer.wrap(vm, 'runInNewContext', wrapVMMethod)
35
+ shimmer.wrap(vm, 'runInThisContext', wrapVMMethod)
36
+ shimmer.wrap(vm, 'compileFunction', wrapVMMethod)
37
+
38
+ return vm
39
+ })
40
+
41
+ function wrapVMMethod (original) {
42
+ return function wrappedVMMethod (code) {
43
+ if (runScriptStartChannel.hasSubscribers && code) {
44
+ runScriptStartChannel.publish({ code })
45
+ }
46
+
47
+ return original.apply(this, arguments)
48
+ }
49
+ }
@@ -0,0 +1,16 @@
1
+ const CompositePlugin = require('../../../../dd-trace/src/plugins/composite')
2
+ const BedrockRuntimeTracing = require('./tracing')
3
+ const BedrockRuntimeLLMObsPlugin = require('../../../../dd-trace/src/llmobs/plugins/bedrockruntime')
4
+ class BedrockRuntimePlugin extends CompositePlugin {
5
+ static get id () {
6
+ return 'bedrockruntime'
7
+ }
8
+
9
+ static get plugins () {
10
+ return {
11
+ llmobs: BedrockRuntimeLLMObsPlugin,
12
+ tracing: BedrockRuntimeTracing
13
+ }
14
+ }
15
+ }
16
+ module.exports = BedrockRuntimePlugin