dd-trace 6.5.0 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "6.5.0",
3
+ "version": "6.6.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -179,7 +179,7 @@
179
179
  "@datadog/native-iast-taint-tracking": "4.2.0",
180
180
  "@datadog/native-metrics": "3.1.2",
181
181
  "@datadog/openfeature-node-server": "2.0.0",
182
- "@datadog/pprof": "5.15.1",
182
+ "@datadog/pprof": "5.17.0",
183
183
  "@datadog/wasm-js-rewriter": "5.0.1",
184
184
  "@opentelemetry/api": ">=1.0.0 <1.10.0",
185
185
  "@opentelemetry/api-logs": "<1.0.0",
@@ -28,6 +28,7 @@ const {
28
28
  } = require('../../dd-trace/src/plugins/util/test')
29
29
  const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
30
30
  const satisfies = require('../../../vendor/dist/semifies')
31
+ const { getChannelPromise } = require('./helpers/channel')
31
32
  const { addHook, channel } = require('./helpers/instrument')
32
33
 
33
34
  const cucumberWorkerThreadsPatchModule = require.resolve('./cucumber-worker-threads')
@@ -563,12 +564,6 @@ function getErrorFromCucumberResult (cucumberResult) {
563
564
  return error
564
565
  }
565
566
 
566
- function getChannelPromise (channelToPublishTo, frameworkVersion = null) {
567
- return new Promise(resolve => {
568
- channelToPublishTo.publish({ onDone: resolve, frameworkVersion })
569
- })
570
- }
571
-
572
567
  function getShouldBeSkippedSuite (pickle, suitesToSkip) {
573
568
  const testSuitePath = getTestSuitePath(pickle.uri, process.cwd())
574
569
  const isUnskippable = isMarkedAsUnskippable(pickle)
@@ -1056,7 +1051,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1056
1051
  }
1057
1052
  let errorSkippableRequest
1058
1053
 
1059
- const configurationResponse = await getChannelPromise(libraryConfigurationCh, frameworkVersion)
1054
+ const configurationResponse = await getChannelPromise(libraryConfigurationCh, { frameworkVersion }) || {}
1060
1055
 
1061
1056
  repositoryRoot = configurationResponse.repositoryRoot
1062
1057
  isItrEnabled = configurationResponse.libraryConfig?.isItrEnabled
@@ -1089,7 +1084,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1089
1084
 
1090
1085
  if (isKnownTestsEnabled) {
1091
1086
  const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
1092
- if (currentKnownTestsResponse.err) {
1087
+ if (!currentKnownTestsResponse || currentKnownTestsResponse.err) {
1093
1088
  isEarlyFlakeDetectionEnabled = false
1094
1089
  isKnownTestsEnabled = false
1095
1090
  } else {
@@ -1098,7 +1093,9 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1098
1093
  }
1099
1094
 
1100
1095
  if (isSuitesSkippingEnabled) {
1101
- const skippableResponse = skippableSuitesResponse || await getChannelPromise(skippableSuitesCh)
1096
+ const skippableResponse = skippableSuitesResponse ||
1097
+ await getChannelPromise(skippableSuitesCh) ||
1098
+ { err: true }
1102
1099
 
1103
1100
  errorSkippableRequest = skippableResponse.err
1104
1101
  skippableSuites = skippableResponse.skippableSuites ?? []
@@ -1147,7 +1144,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1147
1144
  if (isTestManagementTestsEnabled) {
1148
1145
  const currentTestManagementTestsResponse =
1149
1146
  testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
1150
- if (currentTestManagementTestsResponse.err) {
1147
+ if (!currentTestManagementTestsResponse || currentTestManagementTestsResponse.err) {
1151
1148
  isTestManagementTestsEnabled = false
1152
1149
  } else {
1153
1150
  testManagementTests = currentTestManagementTestsResponse.testManagementTests
@@ -1156,7 +1153,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1156
1153
 
1157
1154
  if (isImpactedTestsEnabled) {
1158
1155
  const impactedTestsResponse = await getChannelPromise(modifiedFilesCh)
1159
- if (!impactedTestsResponse.err) {
1156
+ if (impactedTestsResponse && !impactedTestsResponse.err) {
1160
1157
  modifiedFiles = impactedTestsResponse.modifiedFiles
1161
1158
  }
1162
1159
  }
@@ -1215,7 +1212,7 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1215
1212
  global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
1216
1213
  }
1217
1214
 
1218
- sessionFinishCh.publish({
1215
+ const flushPromise = getChannelPromise(sessionFinishCh, {
1219
1216
  status: success ? 'pass' : 'fail',
1220
1217
  isSuitesSkipped,
1221
1218
  testCodeCoverageLinesTotal,
@@ -1228,9 +1225,11 @@ function getWrappedStart (start, frameworkVersion, isParallel = false, isCoordin
1228
1225
  isTestManagementTestsEnabled,
1229
1226
  isParallel,
1230
1227
  })
1228
+
1231
1229
  logTestOptimizationSummary({ attemptToFixExecutions })
1232
1230
  loggedAttemptToFixTests.clear()
1233
1231
  eventDataCollector = null
1232
+ await flushPromise
1234
1233
  return result
1235
1234
  }
1236
1235
  }
@@ -0,0 +1,74 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * @template {unknown[]} T
5
+ * @param {(...args: T) => void} onDone
6
+ * @returns {(...args: T) => void}
7
+ */
8
+ function getCompletion (onDone) {
9
+ let hasCompleted = false
10
+ return (...args) => {
11
+ if (hasCompleted) return
12
+
13
+ hasCompleted = true
14
+ onDone(...args)
15
+ }
16
+ }
17
+
18
+ /**
19
+ * @template {unknown[]} T
20
+ * @param {import('node:diagnostics_channel').Channel} channel
21
+ * @param {Record<string, unknown>} payload
22
+ * @param {(...args: T) => void} onDone
23
+ * @returns {void}
24
+ */
25
+ function publishWithCompletion (channel, payload, onDone) {
26
+ const complete = getCompletion(onDone)
27
+ channel.publish({ ...payload, onDone: complete })
28
+ if (!channel.hasSubscribers) complete()
29
+ }
30
+
31
+ /**
32
+ * @template {unknown[]} T
33
+ * @param {import('node:diagnostics_channel').Channel} channel
34
+ * @param {Record<string, unknown> & { onDone?: (...args: T) => void }} payload
35
+ * @param {(...args: T) => void} onDone
36
+ * @returns {void}
37
+ */
38
+ function runStoresWithCompletion (channel, payload, onDone) {
39
+ const complete = getCompletion(onDone)
40
+ payload.onDone = complete
41
+ channel.runStores(payload, () => {})
42
+ if (!channel.hasSubscribers) complete()
43
+ }
44
+
45
+ /**
46
+ * @template T
47
+ * @param {import('node:diagnostics_channel').Channel} channel
48
+ * @param {Record<string, unknown>} [payload]
49
+ * @returns {Promise<T>}
50
+ */
51
+ function getChannelPromise (channel, payload = {}) {
52
+ return new Promise(resolve => {
53
+ publishWithCompletion(channel, payload, resolve)
54
+ })
55
+ }
56
+
57
+ /**
58
+ * @template T
59
+ * @param {import('node:diagnostics_channel').Channel} channel
60
+ * @param {Record<string, unknown>} [payload]
61
+ * @returns {Promise<T>}
62
+ */
63
+ function getRunStoresPromise (channel, payload = {}) {
64
+ return new Promise(resolve => {
65
+ runStoresWithCompletion(channel, { ...payload }, resolve)
66
+ })
67
+ }
68
+
69
+ module.exports = {
70
+ getChannelPromise,
71
+ getRunStoresPromise,
72
+ publishWithCompletion,
73
+ runStoresWithCompletion,
74
+ }
@@ -46,6 +46,10 @@ const {
46
46
  addCoverageBackfillUntestedFiles,
47
47
  getCoverageBackfillFiles,
48
48
  } = require('./jest/coverage-backfill')
49
+ const {
50
+ getChannelPromise,
51
+ publishWithCompletion,
52
+ } = require('./helpers/channel')
49
53
  const { addHook, channel } = require('./helpers/instrument')
50
54
 
51
55
  const testSessionStartCh = channel('ci:jest:session:start')
@@ -1971,6 +1975,9 @@ function shouldFinishBailTestSession (globalConfig, results) {
1971
1975
  return !!globalConfig?.bail && getNumBailFailures(results) >= globalConfig.bail
1972
1976
  }
1973
1977
 
1978
+ /**
1979
+ * @param {Record<string, unknown> & { onDone?: () => void }} payload
1980
+ */
1974
1981
  async function waitForTestSessionFinish (payload) {
1975
1982
  if (!testSessionFinishCh.hasSubscribers || hasFinishedTestSession) return
1976
1983
 
@@ -1978,8 +1985,9 @@ async function waitForTestSessionFinish (payload) {
1978
1985
 
1979
1986
  let timeoutId
1980
1987
 
1988
+ let onDone
1981
1989
  const flushPromise = new Promise((resolve) => {
1982
- payload.onDone = () => {
1990
+ onDone = () => {
1983
1991
  clearTimeout(timeoutId)
1984
1992
  resolve()
1985
1993
  }
@@ -1992,7 +2000,7 @@ async function waitForTestSessionFinish (payload) {
1992
2000
  timeoutId.unref?.()
1993
2001
  })
1994
2002
 
1995
- testSessionFinishCh.publish(payload)
2003
+ publishWithCompletion(testSessionFinishCh, payload, onDone)
1996
2004
 
1997
2005
  const waitingResult = await Promise.race([flushPromise, timeoutPromise])
1998
2006
 
@@ -2157,12 +2165,6 @@ function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
2157
2165
  }
2158
2166
  }
2159
2167
 
2160
- function getChannelPromise (channelToPublishTo, payload = {}) {
2161
- return new Promise(resolve => {
2162
- channelToPublishTo.publish({ ...payload, onDone: resolve })
2163
- })
2164
- }
2165
-
2166
2168
  function searchSourceWrapper (searchSourcePackage, frameworkVersion) {
2167
2169
  const SearchSource = searchSourcePackage.default ?? searchSourcePackage
2168
2170
 
@@ -2517,9 +2519,7 @@ function getCliWrapper (isNewJestVersion) {
2517
2519
 
2518
2520
  if (codeCoverageReportCh.hasSubscribers) {
2519
2521
  const rootDir = result.globalConfig?.rootDir || process.cwd()
2520
- await new Promise((resolve) => {
2521
- codeCoverageReportCh.publish({ rootDir, onDone: resolve })
2522
- })
2522
+ await getChannelPromise(codeCoverageReportCh, { rootDir })
2523
2523
  }
2524
2524
 
2525
2525
  logSessionSummary(ignoredFailuresSummary, getAttemptToFixExecutionsFromJestResults(result))
@@ -2537,6 +2537,10 @@ function shouldWaitForTestSuiteFinish (environment) {
2537
2537
  return isJestWorker && environment.globalConfig?.workerIdleMemoryLimit !== undefined
2538
2538
  }
2539
2539
 
2540
+ /**
2541
+ * @param {Record<string, unknown>} payload
2542
+ * @param {boolean} waitForFinish
2543
+ */
2540
2544
  function publishTestSuiteFinish (payload, waitForFinish) {
2541
2545
  if (!testSuiteFinishCh.hasSubscribers) return
2542
2546
 
@@ -2545,12 +2549,9 @@ function publishTestSuiteFinish (payload, waitForFinish) {
2545
2549
  return
2546
2550
  }
2547
2551
 
2548
- return new Promise(resolve => {
2549
- testSuiteFinishCh.publish({
2550
- ...payload,
2551
- waitForFinish,
2552
- onDone: resolve,
2553
- })
2552
+ return getChannelPromise(testSuiteFinishCh, {
2553
+ ...payload,
2554
+ waitForFinish,
2554
2555
  })
2555
2556
  }
2556
2557
 
@@ -3,6 +3,11 @@
3
3
  const { createCoverageMap } = require('../../../../vendor/dist/istanbul-lib-coverage')
4
4
  const satisfies = require('../../../../vendor/dist/semifies')
5
5
  const { DD_MAJOR } = require('../../../../version')
6
+ const {
7
+ getRunStoresPromise,
8
+ publishWithCompletion,
9
+ runStoresWithCompletion,
10
+ } = require('../helpers/channel')
6
11
  const { addHook, channel } = require('../helpers/instrument')
7
12
  const shimmer = require('../../../datadog-shimmer')
8
13
  const { isMarkedAsUnskippable } = require('../../../datadog-plugin-jest/src/util')
@@ -240,6 +245,41 @@ function resetSuiteSkippingRunState () {
240
245
  writeCoverageBackfillToCache({})
241
246
  }
242
247
 
248
+ /**
249
+ * @param {((failures: number) => void) | undefined} callback
250
+ * @returns {{ onRunDone: (failures: number) => void, onFlushDone: () => void }}
251
+ */
252
+ function getRunCompletionCallbacks (callback) {
253
+ let failures
254
+ let hasRunFinished = false
255
+ let hasFlushFinished = false
256
+ let hasCompleted = false
257
+ const onDone = callback || (() => {})
258
+
259
+ const completeIfReady = () => {
260
+ if (hasCompleted || !hasRunFinished || !hasFlushFinished) return
261
+
262
+ hasCompleted = true
263
+ onDone(failures)
264
+ }
265
+
266
+ return {
267
+ onRunDone: (runFailures) => {
268
+ if (hasRunFinished) return
269
+
270
+ failures = runFailures
271
+ hasRunFinished = true
272
+ completeIfReady()
273
+ },
274
+ onFlushDone: () => {
275
+ if (hasFlushFinished) return
276
+
277
+ hasFlushFinished = true
278
+ completeIfReady()
279
+ },
280
+ }
281
+ }
282
+
243
283
  function getOnStartHandler (frameworkVersion) {
244
284
  return function () {
245
285
  const processArgv = process.argv.slice(2).join(' ')
@@ -251,7 +291,12 @@ function getOnStartHandler (frameworkVersion) {
251
291
  }
252
292
  }
253
293
 
254
- function getOnEndHandler (isParallel) {
294
+ /**
295
+ * @param {boolean} isParallel
296
+ * @param {() => void} onDone
297
+ * @returns {() => void}
298
+ */
299
+ function getOnEndHandler (isParallel, onDone) {
255
300
  return function () {
256
301
  let status = 'pass'
257
302
  let error
@@ -337,7 +382,7 @@ function getOnEndHandler (isParallel) {
337
382
  global.__coverage__ = fromCoverageMapToCoverage(originalCoverageMap)
338
383
  }
339
384
 
340
- testSessionFinishCh.publish({
385
+ publishWithCompletion(testSessionFinishCh, {
341
386
  status,
342
387
  isSuitesSkipped,
343
388
  testCodeCoverageLinesTotal,
@@ -350,19 +395,13 @@ function getOnEndHandler (isParallel) {
350
395
  isEarlyFlakeDetectionFaulty: config.isEarlyFlakeDetectionFaulty,
351
396
  isTestManagementEnabled: config.isTestManagementTestsEnabled,
352
397
  isParallel,
353
- })
398
+ }, onDone)
354
399
 
355
400
  logTestOptimizationSummary({ attemptToFixExecutions, newTestsWithDynamicNames })
356
401
  loggedAttemptToFixTests.clear()
357
402
  }
358
403
  }
359
404
 
360
- function getRunStoresPromise (channelToPublishTo, ctx) {
361
- return new Promise(resolve => {
362
- channelToPublishTo.runStores({ ...ctx, onDone: resolve }, () => {})
363
- })
364
- }
365
-
366
405
  function applyKnownTestsResponse ({ err, knownTests }) {
367
406
  if (err) {
368
407
  config.knownTests = []
@@ -395,13 +434,14 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
395
434
  let skippableSuitesResponse
396
435
  resetSuiteSkippingRunState()
397
436
 
398
- const onReceivedSkippableSuites = ({
399
- err,
400
- skippableSuites,
401
- itrCorrelationId: responseItrCorrelationId,
402
- skippableSuitesCoverage: responseSkippableSuitesCoverage,
403
- }) => {
404
- if (err) {
437
+ const onReceivedSkippableSuites = (response) => {
438
+ const {
439
+ err,
440
+ skippableSuites,
441
+ itrCorrelationId: responseItrCorrelationId,
442
+ skippableSuitesCoverage: responseSkippableSuitesCoverage,
443
+ } = response || {}
444
+ if (!response || err) {
405
445
  suitesToSkip = []
406
446
  skippableSuitesCoverage = {}
407
447
  } else {
@@ -443,12 +483,12 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
443
483
  return
444
484
  }
445
485
 
446
- ctx.onDone = onReceivedSkippableSuites
447
- skippableSuitesCh.runStores(ctx, () => {})
486
+ runStoresWithCompletion(skippableSuitesCh, ctx, onReceivedSkippableSuites)
448
487
  }
449
488
 
450
- const onReceivedImpactedTests = ({ err, modifiedFiles: receivedModifiedFiles }) => {
451
- if (err) {
489
+ const onReceivedImpactedTests = (response) => {
490
+ const { err, modifiedFiles: receivedModifiedFiles } = response || {}
491
+ if (!response || err) {
452
492
  config.modifiedFiles = []
453
493
  config.isImpactedTestsEnabled = false
454
494
  } else {
@@ -465,8 +505,7 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
465
505
 
466
506
  const continueAfterTestRequests = () => {
467
507
  if (config.isImpactedTestsEnabled) {
468
- ctx.onDone = onReceivedImpactedTests
469
- modifiedFilesCh.runStores(ctx, () => {})
508
+ runStoresWithCompletion(modifiedFilesCh, ctx, onReceivedImpactedTests)
470
509
  } else if (config.isSuitesSkippingEnabled) {
471
510
  requestSkippableSuites()
472
511
  } else {
@@ -476,8 +515,14 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
476
515
  }
477
516
  }
478
517
 
479
- const onReceivedConfiguration = ({ err, isTestDynamicInstrumentationEnabled, libraryConfig, repositoryRoot }) => {
480
- if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
518
+ const onReceivedConfiguration = (response) => {
519
+ const {
520
+ err,
521
+ isTestDynamicInstrumentationEnabled,
522
+ libraryConfig,
523
+ repositoryRoot,
524
+ } = response || {}
525
+ if (!response || err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
481
526
  return mochaGlobalRunCh.runStores(ctx, () => {
482
527
  onFinishRequest()
483
528
  })
@@ -526,9 +571,7 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
526
571
  })
527
572
  }
528
573
 
529
- ctx.onDone = onReceivedConfiguration
530
-
531
- libraryConfigurationCh.runStores(ctx, () => {})
574
+ runStoresWithCompletion(libraryConfigurationCh, ctx, onReceivedConfiguration)
532
575
  }
533
576
 
534
577
  // In this hook we delay the execution with options.delay to grab library configuration,
@@ -641,6 +684,9 @@ addHook({
641
684
  return run.apply(this, args)
642
685
  }
643
686
 
687
+ const { onRunDone, onFlushDone } = getRunCompletionCallbacks(args[0])
688
+ args[0] = onRunDone
689
+
644
690
  const { suitesByTestFile, numSuitesByTestFile } = getSuitesByTestFile(this.suite)
645
691
  // Root-level tests (direct children of root, no describe wrapper) keyed by file.
646
692
  // Populated during the root 'suite' event so the normal finish path can include them
@@ -752,7 +798,7 @@ addHook({
752
798
  finishRootSuiteForFile(test.file)
753
799
  }
754
800
 
755
- const onEnd = getOnEndHandler(false)
801
+ const onEnd = getOnEndHandler(false, onFlushDone)
756
802
 
757
803
  this.once('start', getOnStartHandler(frameworkVersion))
758
804
 
@@ -1041,8 +1087,11 @@ addHook({
1041
1087
  return run.apply(this, arguments)
1042
1088
  }
1043
1089
 
1090
+ const { onRunDone, onFlushDone } = getRunCompletionCallbacks(cb)
1091
+ arguments[0] = onRunDone
1092
+
1044
1093
  this.once('start', getOnStartHandler(frameworkVersion))
1045
- this.once('end', getOnEndHandler(true))
1094
+ this.once('end', getOnEndHandler(true, onFlushDone))
1046
1095
 
1047
1096
  // Populate unskippable suites before config is fetched (matches serial mode at Mocha.prototype.run)
1048
1097
  for (const filePath of files) {
@@ -1082,7 +1131,7 @@ addHook({
1082
1131
  skippedSuites = skippedFiles
1083
1132
  skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
1084
1133
  writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
1085
- run.apply(this, [cb, { files: filteredFiles }])
1134
+ run.apply(this, [onRunDone, { files: filteredFiles }])
1086
1135
  } else {
1087
1136
  run.apply(this, arguments)
1088
1137
  }
@@ -29,6 +29,7 @@ const {
29
29
  RUM_TEST_EXECUTION_ID_COOKIE_NAME: RUM_COOKIE_NAME,
30
30
  } = require('../../dd-trace/src/ci-visibility/rum')
31
31
  const { DD_MAJOR } = require('../../../version')
32
+ const { getChannelPromise } = require('./helpers/channel')
32
33
  const { addHook, channel, tracingChannel } = require('./helpers/instrument')
33
34
 
34
35
  const testStartCh = channel('ci:playwright:test:start')
@@ -614,12 +615,6 @@ function getTestByTestId (dispatcher, testId) {
614
615
  }
615
616
  }
616
617
 
617
- function getChannelPromise (channelToPublishTo, params) {
618
- return new Promise(resolve => {
619
- channelToPublishTo.publish({ onDone: resolve, ...params })
620
- })
621
- }
622
-
623
618
  // Inspired by https://github.com/microsoft/playwright/blob/2b77ed4d7aafa85a600caa0b0d101b72c8437eeb/packages/playwright/src/reporters/base.ts#L293
624
619
  // We can't use test.outcome() directly because it's set on follow up handlers:
625
620
  // our `testEndHandler` is called before the outcome is set.
@@ -1206,8 +1201,6 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
1206
1201
  function runAllTestsWrapper (runAllTests, playwrightVersion) {
1207
1202
  // Config parameter is only available from >=1.55.0
1208
1203
  return async function (config) {
1209
- let onDone
1210
-
1211
1204
  rootDir = getRootDir(this, config)
1212
1205
  const projects = getProjectsFromRunner(this, config)
1213
1206
  const isFailureScreenshotEnabled = isFailureScreenshotCaptureEnabled(projects)
@@ -1379,17 +1372,12 @@ function runAllTestsWrapper (runAllTests, playwrightVersion) {
1379
1372
  logTestOptimizationSummary({ attemptToFixExecutions, newTestsWithDynamicNames })
1380
1373
  loggedAttemptToFixTests.clear()
1381
1374
 
1382
- const flushWait = new Promise(resolve => {
1383
- onDone = resolve
1384
- })
1385
- testSessionFinishCh.publish({
1375
+ await getChannelPromise(testSessionFinishCh, {
1386
1376
  status: preventedToFail ? 'pass' : STATUS_TO_TEST_STATUS[sessionStatus],
1387
1377
  isEarlyFlakeDetectionEnabled,
1388
1378
  isEarlyFlakeDetectionFaulty,
1389
1379
  isTestManagementTestsEnabled,
1390
- onDone,
1391
1380
  })
1392
- await flushWait
1393
1381
 
1394
1382
  startedSuites = []
1395
1383
  remainingTestsByFile = {}
@@ -2112,12 +2100,6 @@ function instrumentWorkerMainMethods (workerMain) {
2112
2100
  annotationTags = parseAnnotations(annotations)
2113
2101
  }
2114
2102
 
2115
- let onDone
2116
-
2117
- const flushPromise = new Promise(resolve => {
2118
- onDone = resolve
2119
- })
2120
-
2121
2103
  // Wait for the properties to be received, but do not block the worker forever if IPC fails.
2122
2104
  const ddPropertiesTimeoutPromise = new Promise(resolve => {
2123
2105
  const ddPropertiesTimeout = realSetTimeout(() => {
@@ -2143,7 +2125,7 @@ function instrumentWorkerMainMethods (workerMain) {
2143
2125
  testStatus: STATUS_TO_TEST_STATUS[status],
2144
2126
  })
2145
2127
 
2146
- testFinishCh.publish({
2128
+ await getChannelPromise(testFinishCh, {
2147
2129
  testStatus: STATUS_TO_TEST_STATUS[status],
2148
2130
  steps: steps.filter(step => step.testId === testId),
2149
2131
  error,
@@ -2161,14 +2143,11 @@ function instrumentWorkerMainMethods (workerMain) {
2161
2143
  hasFailedAttemptToFixRetries: test._ddHasFailedAttemptToFixRetries,
2162
2144
  isAtrRetry: test._ddIsAtrRetry,
2163
2145
  isModified: test._ddIsModified,
2164
- onDone,
2165
2146
  finalStatus,
2166
2147
  earlyFlakeAbortReason: test._ddEarlyFlakeAbortReason,
2167
2148
  ...testCtx.currentStore,
2168
2149
  })
2169
2150
 
2170
- await flushPromise
2171
-
2172
2151
  return res
2173
2152
  })
2174
2153
 
@@ -419,7 +419,7 @@ function createMainProcessReporter (reporterState) {
419
419
  testSuiteFinishCh.publish({
420
420
  status: getDatadogStatus(testSuiteResult),
421
421
  deferFlush: true,
422
- onFinish: noop,
422
+ onDone: noop,
423
423
  ...testSuiteCtx.currentStore,
424
424
  })
425
425
  testSuiteContexts.delete(testModuleId)
@@ -16,6 +16,7 @@ const {
16
16
  getTestSuitePath,
17
17
  isModifiedTest,
18
18
  } = require('../../dd-trace/src/plugins/util/test')
19
+ const { getChannelPromise } = require('./helpers/channel')
19
20
  const { addHook } = require('./helpers/instrument')
20
21
  const noWorkerInit = require('./vitest-main-no-worker-init')
21
22
  const {
@@ -38,7 +39,6 @@ const {
38
39
  workerReportLogsCh,
39
40
  codeCoverageReportCh,
40
41
  findExportByName,
41
- getChannelPromise,
42
42
  getTypeTasks,
43
43
  getWorkspaceProject,
44
44
  setProvidedContext,
@@ -433,7 +433,8 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, s
433
433
  err,
434
434
  libraryConfig,
435
435
  requestErrorTags: receivedRequestErrorTags = {},
436
- } = await getChannelPromise(libraryConfigurationCh, frameworkVersion, {
436
+ } = await getChannelPromise(libraryConfigurationCh, {
437
+ frameworkVersion,
437
438
  isVitestNoWorkerInitActive: shouldInstallNoWorkerInit,
438
439
  })
439
440
  requestErrorTags = receivedRequestErrorTags
@@ -450,7 +451,7 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, s
450
451
  resetMainProcessProvidedContext(ctx)
451
452
 
452
453
  if (testSessionConfigurationCh.hasSubscribers) {
453
- testSessionConfiguration = await getChannelPromise(testSessionConfigurationCh, frameworkVersion)
454
+ testSessionConfiguration = await getChannelPromise(testSessionConfigurationCh, { frameworkVersion }) || {}
454
455
  const {
455
456
  testSessionId,
456
457
  testModuleId,
@@ -494,7 +495,7 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, s
494
495
 
495
496
  if (isKnownTestsEnabled) {
496
497
  const currentKnownTestsResponse = knownTestsResponse || await getChannelPromise(knownTestsCh)
497
- if (currentKnownTestsResponse.err) {
498
+ if (!currentKnownTestsResponse || currentKnownTestsResponse.err) {
498
499
  isEarlyFlakeDetectionEnabled = false
499
500
  } else {
500
501
  knownTests = currentKnownTestsResponse.knownTests
@@ -538,12 +539,13 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, s
538
539
  }
539
540
 
540
541
  if (isTestManagementTestsEnabled) {
541
- const { err, testManagementTests: receivedTestManagementTests } =
542
+ const testManagementResponse =
542
543
  testManagementTestsResponse || await getChannelPromise(testManagementTestsCh)
543
- if (err) {
544
+ if (!testManagementResponse || testManagementResponse.err) {
544
545
  isTestManagementTestsEnabled = false
545
546
  log.error('Could not get test management tests.')
546
547
  } else {
548
+ const { testManagementTests: receivedTestManagementTests } = testManagementResponse
547
549
  testManagementTests = receivedTestManagementTests
548
550
  testManagementTestsBySuite = getTestManagementTestsBySuite(receivedTestManagementTests)
549
551
  shouldSendTestProperties = true
@@ -558,8 +560,7 @@ async function runMainProcessSetup (ctx, frameworkVersion, testSpecifications, s
558
560
 
559
561
  if (isImpactedTestsEnabled) {
560
562
  const modifiedFilesResponse = await getChannelPromise(modifiedFilesCh)
561
- const { err } = modifiedFilesResponse
562
- if (err) {
563
+ if (!modifiedFilesResponse || modifiedFilesResponse.err) {
563
564
  log.error('Could not get modified tests.')
564
565
  } else {
565
566
  modifiedFiles = modifiedFilesResponse.modifiedFiles
@@ -812,18 +813,13 @@ function getFinishWrapper (exitOrClose) {
812
813
  return exitOrClose.apply(this, arguments)
813
814
  }
814
815
 
815
- let onFinish
816
-
817
- const flushPromise = new Promise(resolve => {
818
- onFinish = resolve
819
- })
820
816
  const failedSuites = this.state.getFailedFilepaths()
821
817
  let error
822
818
  if (failedSuites.length) {
823
819
  error = new Error(`Test suites failed: ${failedSuites.length}.`)
824
820
  }
825
821
 
826
- testSessionFinishCh.publish({
822
+ const flushPromise = getChannelPromise(testSessionFinishCh, {
827
823
  status: getSessionStatus(this.state),
828
824
  testCodeCoverageLinesTotal,
829
825
  error,
@@ -833,7 +829,6 @@ function getFinishWrapper (exitOrClose) {
833
829
  requestErrorTags,
834
830
  vitestPool,
835
831
  isVitestNoWorkerInitActive,
836
- onFinish,
837
832
  })
838
833
 
839
834
  logTestOptimizationSummary({ attemptToFixExecutions, newTestsWithDynamicNames })
@@ -842,9 +837,7 @@ function getFinishWrapper (exitOrClose) {
842
837
 
843
838
  // If coverage was generated, publish coverage report channel for upload
844
839
  if (coverageRootDir && codeCoverageReportCh.hasSubscribers) {
845
- await new Promise((resolve) => {
846
- codeCoverageReportCh.publish({ rootDir: coverageRootDir, onDone: resolve })
847
- })
840
+ await getChannelPromise(codeCoverageReportCh, { rootDir: coverageRootDir })
848
841
  }
849
842
 
850
843
  return exitOrClose.apply(this, arguments)
@@ -1213,16 +1206,11 @@ async function reportTypecheckFile (file, sessionConfiguration, frameworkVersion
1213
1206
  testSuiteErrorCh.runStores(testSuiteCtx, () => {})
1214
1207
  }
1215
1208
 
1216
- let onFinish
1217
- const onFinishPromise = new Promise(resolve => {
1218
- onFinish = resolve
1219
- })
1220
- testSuiteFinishCh.publish({
1209
+ await getChannelPromise(testSuiteFinishCh, {
1210
+ frameworkVersion,
1221
1211
  status: getTypecheckTaskStatus(file),
1222
- onFinish,
1223
1212
  ...testSuiteCtx.currentStore,
1224
1213
  })
1225
- await onFinishPromise
1226
1214
  }
1227
1215
 
1228
1216
  async function reportTypecheckResults (result, frameworkVersion, ctx, typechecker) {
@@ -1234,7 +1222,7 @@ async function reportTypecheckResults (result, frameworkVersion, ctx, typechecke
1234
1222
  }
1235
1223
  const providedContext = getMainProcessProvidedContext(ctx)
1236
1224
  const sessionConfiguration = testSessionConfigurationCh.hasSubscribers
1237
- ? await getChannelPromise(testSessionConfigurationCh, frameworkVersion)
1225
+ ? await getChannelPromise(testSessionConfigurationCh, { frameworkVersion }) || {}
1238
1226
  : {}
1239
1227
 
1240
1228
  await Promise.all(result.files.map(file => reportTypecheckFile(
@@ -39,12 +39,6 @@ function findExportByName (pkg, name) {
39
39
  }
40
40
  }
41
41
 
42
- function getChannelPromise (channelToPublishTo, frameworkVersion, payload) {
43
- return new Promise(resolve => {
44
- channelToPublishTo.publish({ ...payload, onDone: resolve, frameworkVersion })
45
- })
46
- }
47
-
48
42
  function getTestRunnerExport (testPackage) {
49
43
  return findExportByName(testPackage, 'VitestTestRunner') || findExportByName(testPackage, 'TestRunner')
50
44
  }
@@ -239,7 +233,6 @@ module.exports = {
239
233
  workerReportLogsCh,
240
234
  codeCoverageReportCh,
241
235
  findExportByName,
242
- getChannelPromise,
243
236
  getTestRunnerExport,
244
237
  getTypeTasks,
245
238
  getTestName,
@@ -9,6 +9,7 @@ const {
9
9
  recordAttemptToFixExecution,
10
10
  logAttemptToFixTestExecution,
11
11
  } = require('../../dd-trace/src/plugins/util/test')
12
+ const { getChannelPromise } = require('./helpers/channel')
12
13
  const { addHook } = require('./helpers/instrument')
13
14
  const {
14
15
  testStartCh,
@@ -661,11 +662,6 @@ addHook({
661
662
  testSuiteStartCh.runStores(testSuiteCtx, () => {})
662
663
  const startTestsResponse = await startTests.apply(this, arguments)
663
664
 
664
- let onFinish = null
665
- const onFinishPromise = new Promise(resolve => {
666
- onFinish = resolve
667
- })
668
-
669
665
  const testTasks = getTypeTasks(startTestsResponse[0].tasks)
670
666
  const testEventPromises = []
671
667
 
@@ -811,9 +807,10 @@ addHook({
811
807
  testSuiteErrorCh.runStores(testSuiteCtx, () => {})
812
808
  }
813
809
 
814
- testSuiteFinishCh.publish({ status: testSuiteResult.state, onFinish, ...testSuiteCtx.currentStore })
815
-
816
- await onFinishPromise
810
+ await getChannelPromise(testSuiteFinishCh, {
811
+ status: testSuiteResult.state,
812
+ ...testSuiteCtx.currentStore,
813
+ })
817
814
 
818
815
  return startTestsResponse
819
816
  })
@@ -72,6 +72,7 @@ class CucumberPlugin extends CiPlugin {
72
72
  isEarlyFlakeDetectionFaulty,
73
73
  isTestManagementTestsEnabled,
74
74
  isParallel,
75
+ onDone,
75
76
  }) => {
76
77
  this._exportPendingWorkerTraces()
77
78
  const {
@@ -127,7 +128,7 @@ class CucumberPlugin extends CiPlugin {
127
128
  })
128
129
 
129
130
  this.libraryConfig = null
130
- this.tracer._exporter.flush()
131
+ this.tracer._exporter.flush(onDone)
131
132
  })
132
133
 
133
134
  this.addSub('ci:cucumber:test-suite:start', ({
@@ -390,6 +390,7 @@ class MochaPlugin extends CiPlugin {
390
390
  isEarlyFlakeDetectionFaulty,
391
391
  isTestManagementEnabled,
392
392
  isParallel,
393
+ onDone,
393
394
  }) => {
394
395
  this._exportPendingWorkerTraces()
395
396
  if (this.testSessionSpan) {
@@ -456,7 +457,7 @@ class MochaPlugin extends CiPlugin {
456
457
  })
457
458
  }
458
459
  this.libraryConfig = null
459
- this.tracer._exporter.flush()
460
+ this.tracer._exporter.flush(onDone)
460
461
  })
461
462
 
462
463
  this.addBind('ci:mocha:global:run', (ctx) => {
@@ -388,7 +388,10 @@ class PlaywrightPlugin extends CiPlugin {
388
388
  earlyFlakeAbortReason,
389
389
  onDone,
390
390
  }) => {
391
- if (!span) return
391
+ if (!span) {
392
+ onDone?.()
393
+ return
394
+ }
392
395
 
393
396
  const isRUMActive = span.context().getTag(TEST_IS_RUM_ACTIVE)
394
397
 
@@ -400,7 +400,7 @@ class VitestPlugin extends CiPlugin {
400
400
  return ctx.currentStore
401
401
  })
402
402
 
403
- this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onFinish }) => {
403
+ this.addSub('ci:vitest:test-suite:finish', ({ testSuiteSpan, status, deferFlush, onDone }) => {
404
404
  if (testSuiteSpan) {
405
405
  testSuiteSpan.setTag(TEST_STATUS, status)
406
406
  testSuiteSpan.finish()
@@ -408,10 +408,10 @@ class VitestPlugin extends CiPlugin {
408
408
  }
409
409
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'suite')
410
410
  if (deferFlush) {
411
- onFinish()
411
+ onDone()
412
412
  return
413
413
  }
414
- this.tracer._exporter.flush(onFinish)
414
+ this.tracer._exporter.flush(onDone)
415
415
  if (this.runningTestProbe) {
416
416
  this.removeDiProbe(this.runningTestProbe)
417
417
  }
@@ -442,7 +442,7 @@ class VitestPlugin extends CiPlugin {
442
442
  requestErrorTags,
443
443
  vitestPool,
444
444
  isVitestNoWorkerInitActive,
445
- onFinish,
445
+ onDone,
446
446
  }) => {
447
447
  for (const [tag, value] of Object.entries(requestErrorTags || {})) {
448
448
  this.testSessionSpan.setTag(tag, value)
@@ -481,7 +481,7 @@ class VitestPlugin extends CiPlugin {
481
481
  provider: this.ciProviderName,
482
482
  autoInjected: !!this._tracerConfig.testOptimization.DD_CIVISIBILITY_AUTO_INSTRUMENTATION_PROVIDER,
483
483
  })
484
- this.tracer._exporter.flush(onFinish)
484
+ this.tracer._exporter.flush(onDone)
485
485
  })
486
486
 
487
487
  this.addSub('ci:vitest:coverage-report', ({ rootDir, onDone }) => {
@@ -59,7 +59,7 @@ class NativeSpaceProfiler {
59
59
  }
60
60
 
61
61
  profile (restart) {
62
- const profile = this.#pprof.heap.profile(undefined, this.#mapper, getThreadLabels)
62
+ const profile = this.#pprof.heap.profile(undefined, this.#mapper, getThreadLabels, 'pack')
63
63
  if (!restart) {
64
64
  this.stop()
65
65
  }
@@ -187,6 +187,7 @@ class NativeWallProfiler {
187
187
 
188
188
  this.#pprof.time.start({
189
189
  collectCpuTime: this.#cpuProfilingEnabled,
190
+ columnNumbers: 'pack',
190
191
  durationMillis: this.#flushIntervalMillis,
191
192
  intervalMicros: this.#samplingIntervalMicros,
192
193
  lineNumbers: false,