dd-trace 5.105.0 → 5.106.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": "5.105.0",
3
+ "version": "5.106.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -233,13 +233,14 @@ function wrapSmithySend (send) {
233
233
  }
234
234
 
235
235
  function handleCompletion (result, ctx, channels) {
236
- const iterator = result?.body?.[Symbol.asyncIterator]
236
+ const streamable = result?.body ?? result?.stream
237
+ const iterator = streamable?.[Symbol.asyncIterator]
237
238
  if (!iterator) {
238
239
  channels.complete.publish(ctx)
239
240
  return
240
241
  }
241
242
 
242
- shimmer.wrap(result.body, Symbol.asyncIterator, function (asyncIterator) {
243
+ shimmer.wrap(streamable, Symbol.asyncIterator, function (asyncIterator) {
243
244
  return function (...args) {
244
245
  const iterator = asyncIterator.apply(this, args)
245
246
  shimmer.wrap(iterator, 'next', function (next) {
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const { createRequire } = require('node:module')
4
+ const path = require('node:path')
5
+
6
+ const { patchCucumberWorkerRunTestCase } = require('./cucumber')
7
+
8
+ const appRequire = createRequire(path.join(process.cwd(), 'package.json'))
9
+
10
+ try {
11
+ // Cucumber v13 parallel workers start from an ESM worker.mjs entrypoint, which
12
+ // statically imports the internal runtime Worker before it runs support-code
13
+ // requireModules. The regular module hook does not patch that internal worker
14
+ // import, so this preload is injected into requireModules to patch the cached Worker
15
+ // prototype before Cucumber constructs the worker instance.
16
+ patchCucumberWorkerRunTestCase(appRequire('@cucumber/cucumber/lib/runtime/worker'), true)
17
+ } catch {
18
+ // Ignore preload failures so cucumber can keep running if its internals change.
19
+ }
@@ -30,6 +30,8 @@ const { writeCoverageBackfillToCache } = require('../../dd-trace/src/ci-visibili
30
30
  const satisfies = require('../../../vendor/dist/semifies')
31
31
  const { addHook, channel } = require('./helpers/instrument')
32
32
 
33
+ const cucumberWorkerThreadsPatchModule = require.resolve('./cucumber-worker-threads')
34
+
33
35
  const testStartCh = channel('ci:cucumber:test:start')
34
36
  const testRetryCh = channel('ci:cucumber:test:retry')
35
37
  const testFinishCh = channel('ci:cucumber:test:finish') // used for test steps too
@@ -69,6 +71,7 @@ const originalCoverageMap = createCoverageMap()
69
71
 
70
72
  // TODO: remove in a later major version
71
73
  const patched = new WeakSet()
74
+ const patchedCucumberWorkers = new WeakSet()
72
75
 
73
76
  const lastStatusByPickleId = new Map()
74
77
  /** For ATR: statuses keyed by stable scenario id (uri:name) so retries accumulate correctly */
@@ -180,22 +183,270 @@ function getConfiguredEfdRetryCount () {
180
183
  }
181
184
 
182
185
  function publishWorkerEfdRetryCount (pickle, retryCount) {
183
- if (typeof process.send !== 'function') return
186
+ const message = {
187
+ [DD_EFD_RETRY_COUNT_MESSAGE]: {
188
+ pickleId: pickle.id,
189
+ retryCount,
190
+ testFileAbsolutePath: pickle.uri,
191
+ testName: pickle.name,
192
+ },
193
+ }
194
+
195
+ if (typeof process.send === 'function') {
196
+ try {
197
+ process.send(message)
198
+ } catch {
199
+ // ignore IPC errors
200
+ }
201
+ return
202
+ }
184
203
 
185
204
  try {
186
- process.send({
187
- [DD_EFD_RETRY_COUNT_MESSAGE]: {
188
- pickleId: pickle.id,
189
- retryCount,
190
- testFileAbsolutePath: pickle.uri,
191
- testName: pickle.name,
192
- },
193
- })
205
+ const { isMainThread, parentPort } = require('node:worker_threads')
206
+ if (isMainThread || !parentPort) return
207
+
208
+ parentPort.postMessage(message)
194
209
  } catch {
195
210
  // ignore IPC errors
196
211
  }
197
212
  }
198
213
 
214
+ function configureParallelWorkerWorldParameters (options) {
215
+ options.worldParameters ??= {}
216
+
217
+ if (isKnownTestsEnabled && isValidKnownTests(knownTests)) {
218
+ options.worldParameters._ddIsKnownTestsEnabled = true
219
+ options.worldParameters._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
220
+ options.worldParameters._ddKnownTests = knownTests
221
+ options.worldParameters._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
222
+ options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = earlyFlakeDetectionSlowTestRetries
223
+ } else {
224
+ isEarlyFlakeDetectionEnabled = false
225
+ isKnownTestsEnabled = false
226
+ options.worldParameters._ddIsEarlyFlakeDetectionEnabled = false
227
+ options.worldParameters._ddIsKnownTestsEnabled = false
228
+ options.worldParameters._ddEarlyFlakeDetectionNumRetries = 0
229
+ options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = {}
230
+ }
231
+
232
+ if (isImpactedTestsEnabled) {
233
+ options.worldParameters._ddImpactedTestsEnabled = isImpactedTestsEnabled
234
+ options.worldParameters._ddModifiedFiles = modifiedFiles
235
+ }
236
+
237
+ options.worldParameters._ddIsFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
238
+ options.worldParameters._ddNumTestRetries = numTestRetries
239
+
240
+ if (isTestManagementTestsEnabled) {
241
+ options.worldParameters._ddIsTestManagementTestsEnabled = true
242
+ options.worldParameters._ddTestManagementTests = testManagementTests
243
+ options.worldParameters._ddTestManagementAttemptToFixRetries = testManagementAttemptToFixRetries
244
+ }
245
+ }
246
+
247
+ function readParallelWorkerWorldParameters (options) {
248
+ const worldParameters = options?.worldParameters
249
+ if (!worldParameters) return
250
+
251
+ isKnownTestsEnabled = !!worldParameters._ddIsKnownTestsEnabled
252
+ if (isKnownTestsEnabled) {
253
+ knownTests = worldParameters._ddKnownTests
254
+ // if for whatever reason the worker does not receive valid known tests, we disable EFD and known tests
255
+ if (!isValidKnownTests(knownTests)) {
256
+ isKnownTestsEnabled = false
257
+ knownTests = {}
258
+ }
259
+ }
260
+ isEarlyFlakeDetectionEnabled = !!worldParameters._ddIsEarlyFlakeDetectionEnabled
261
+ if (isEarlyFlakeDetectionEnabled) {
262
+ earlyFlakeDetectionNumRetries = worldParameters._ddEarlyFlakeDetectionNumRetries
263
+ earlyFlakeDetectionSlowTestRetries = worldParameters._ddEarlyFlakeDetectionSlowTestRetries ?? {}
264
+ }
265
+ isImpactedTestsEnabled = !!worldParameters._ddImpactedTestsEnabled
266
+ if (isImpactedTestsEnabled) {
267
+ modifiedFiles = worldParameters._ddModifiedFiles
268
+ }
269
+ isFlakyTestRetriesEnabled = !!worldParameters._ddIsFlakyTestRetriesEnabled
270
+ numTestRetries = worldParameters._ddNumTestRetries ?? 0
271
+ isTestManagementTestsEnabled = !!worldParameters._ddIsTestManagementTestsEnabled
272
+ if (isTestManagementTestsEnabled) {
273
+ testManagementTests = worldParameters._ddTestManagementTests
274
+ testManagementAttemptToFixRetries = worldParameters._ddTestManagementAttemptToFixRetries
275
+ }
276
+ }
277
+
278
+ function handleDdWorkerMessage (message) {
279
+ if (Array.isArray(message)) {
280
+ const [messageCode, payload] = message
281
+ if (messageCode === CUCUMBER_WORKER_TRACE_PAYLOAD_CODE) {
282
+ collectAttemptToFixExecutionsFromTraces(payload, attemptToFixExecutions)
283
+ workerReportTraceCh.publish(payload)
284
+ return true
285
+ }
286
+ }
287
+
288
+ if (message?.[DD_EFD_RETRY_COUNT_MESSAGE]) {
289
+ handleEfdRetryCountMessage(message[DD_EFD_RETRY_COUNT_MESSAGE])
290
+ return true
291
+ }
292
+
293
+ return false
294
+ }
295
+
296
+ function onCucumberWorkerThreadMessage (message) {
297
+ if (!testSuiteFinishCh.hasSubscribers) return
298
+
299
+ handleDdWorkerMessage(message)
300
+ }
301
+
302
+ function registerWorkerThreadMessageHandlers (workers) {
303
+ if (!workers) return
304
+
305
+ for (const worker of workers) {
306
+ worker.workerThread.on('message', onCucumberWorkerThreadMessage)
307
+ }
308
+ }
309
+
310
+ function registerWorkerThreadPatchModule (supportCodeLibrary) {
311
+ const requireModules = supportCodeLibrary?.originalCoordinates?.requireModules
312
+ if (!Array.isArray(requireModules) || requireModules.includes(cucumberWorkerThreadsPatchModule)) return
313
+
314
+ requireModules.unshift(cucumberWorkerThreadsPatchModule)
315
+ }
316
+
317
+ function getRunningAssembledTestCase (adapter, worker) {
318
+ const command = adapter.running?.get(worker)
319
+ return command?.assembledTestCase
320
+ }
321
+
322
+ function maybeStartParallelSuite (pickle) {
323
+ if (!pickle) return
324
+
325
+ const testFileAbsolutePath = pickle.uri
326
+ if (pickleResultByFile[testFileAbsolutePath]) return
327
+
328
+ pickleResultByFile[testFileAbsolutePath] = []
329
+ testSuiteStartCh.publish({
330
+ testFileAbsolutePath,
331
+ })
332
+ }
333
+
334
+ function handleParallelTestCaseFinished (pickle, worstTestStepResult) {
335
+ const { status } = getStatusFromResultLatest(worstTestStepResult)
336
+ let isNew = false
337
+
338
+ if (isKnownTestsEnabled) {
339
+ isNew = isNewTest(pickle.uri, pickle.name)
340
+ }
341
+
342
+ const testFileAbsolutePath = pickle.uri
343
+ const finished = pickleResultByFile[testFileAbsolutePath] || (pickleResultByFile[testFileAbsolutePath] = [])
344
+
345
+ if (isEarlyFlakeDetectionEnabled && isNew) {
346
+ const testFullname = `${pickle.uri}:${pickle.name}`
347
+ let testStatuses = newTestsByTestFullname.get(testFullname)
348
+ if (testStatuses) {
349
+ testStatuses.push(status)
350
+ } else {
351
+ testStatuses = [status]
352
+ newTestsByTestFullname.set(testFullname, testStatuses)
353
+ }
354
+ let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
355
+ if (efdRetryCount === undefined) {
356
+ efdRetryCount = status === 'skip'
357
+ ? 0
358
+ : getConfiguredEfdRetryCount()
359
+ efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
360
+ if (efdRetryCount === 0 && status !== 'skip') {
361
+ efdSlowAbortedPickleIds.add(pickle.id)
362
+ }
363
+ }
364
+ maybeRecordFinalParallelEfdStatus({ pickleId: pickle.id, testFileAbsolutePath, testFullname })
365
+ } else if (
366
+ isTestManagementTestsEnabled &&
367
+ getTestProperties(getTestSuitePath(testFileAbsolutePath, process.cwd()), pickle.name).attemptToFix
368
+ ) {
369
+ const testFullname = `${pickle.uri}:${pickle.name}`
370
+ let testStatuses = attemptToFixTestsByTestFullname.get(testFullname)
371
+ if (testStatuses) {
372
+ testStatuses.push(status)
373
+ } else {
374
+ testStatuses = [status]
375
+ attemptToFixTestsByTestFullname.set(testFullname, testStatuses)
376
+ }
377
+
378
+ if (status === 'skip' || testStatuses.length === testManagementAttemptToFixRetries + 1) {
379
+ finished.push(getTestStatusFromAttemptToFixExecutions(testStatuses))
380
+ attemptToFixTestsByTestFullname.delete(testFullname)
381
+ }
382
+ } else {
383
+ // TODO: can we get error message?
384
+ finished.push(status)
385
+ }
386
+
387
+ finishParallelSuiteIfDone(testFileAbsolutePath)
388
+ }
389
+
390
+ function getWrappedHandleWorkerThreadEvent (handleEventFromWorker) {
391
+ return function (worker, event) {
392
+ if (!testSuiteFinishCh.hasSubscribers) {
393
+ return handleEventFromWorker.apply(this, arguments)
394
+ }
395
+
396
+ if (handleDdWorkerMessage(event)) return
397
+
398
+ const envelope = event?.type === 'ENVELOPE' && event.envelope
399
+ if (!envelope) {
400
+ return handleEventFromWorker.apply(this, arguments)
401
+ }
402
+
403
+ const assembledTestCase = getRunningAssembledTestCase(this, worker)
404
+
405
+ if (envelope.testCaseStarted) {
406
+ maybeStartParallelSuite(assembledTestCase?.pickle)
407
+ }
408
+
409
+ const result = handleEventFromWorker.apply(this, arguments)
410
+
411
+ if (envelope.testCaseFinished && assembledTestCase?.pickle && eventDataCollector) {
412
+ const worstTestStepResult =
413
+ eventDataCollector.getTestCaseAttempt(envelope.testCaseFinished.testCaseStartedId).worstTestStepResult
414
+ handleParallelTestCaseFinished(assembledTestCase.pickle, worstTestStepResult)
415
+ }
416
+
417
+ return result
418
+ }
419
+ }
420
+
421
+ function getWrappedWorkerThreadsSetup (setup) {
422
+ return async function () {
423
+ if (testSuiteFinishCh.hasSubscribers) {
424
+ configureParallelWorkerWorldParameters(this.options)
425
+ registerWorkerThreadPatchModule(this.supportCodeLibrary)
426
+ }
427
+
428
+ const result = await setup.apply(this, arguments)
429
+
430
+ if (testSuiteFinishCh.hasSubscribers) {
431
+ registerWorkerThreadMessageHandlers(this.workers)
432
+ }
433
+
434
+ return result
435
+ }
436
+ }
437
+
438
+ function getWrappedWorkerThreadsTeardown (teardown) {
439
+ return function () {
440
+ if (testSuiteFinishCh.hasSubscribers && this.workers) {
441
+ for (const worker of this.workers) {
442
+ worker.workerThread.removeListener('message', onCucumberWorkerThreadMessage)
443
+ }
444
+ }
445
+
446
+ return teardown.apply(this, arguments)
447
+ }
448
+ }
449
+
199
450
  function finishParallelSuiteIfDone (testFileAbsolutePath) {
200
451
  const finished = pickleResultByFile[testFileAbsolutePath]
201
452
  const expectedPickles = pickleByFile[testFileAbsolutePath]
@@ -929,6 +1180,9 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
929
1180
  if (!testSuiteFinishCh.hasSubscribers) {
930
1181
  return runTestCaseFunction.apply(this, arguments)
931
1182
  }
1183
+ if (isWorker) {
1184
+ readParallelWorkerWorldParameters(this.options)
1185
+ }
932
1186
  const pickle = isNewerCucumberVersion
933
1187
  ? arguments[0].pickle
934
1188
  : this.eventDataCollector.getPickle(arguments[0])
@@ -1113,26 +1367,25 @@ function getWrappedRunTestCase (runTestCaseFunction, isNewerCucumberVersion = fa
1113
1367
  }
1114
1368
  }
1115
1369
 
1370
+ function patchCucumberWorkerRunTestCase (workerPackage, isWorker) {
1371
+ const workerPrototype = workerPackage?.Worker?.prototype
1372
+ if (!workerPrototype || patchedCucumberWorkers.has(workerPrototype)) return
1373
+
1374
+ patchedCucumberWorkers.add(workerPrototype)
1375
+ shimmer.wrap(
1376
+ workerPrototype,
1377
+ 'runTestCase',
1378
+ runTestCase => getWrappedRunTestCase(runTestCase, true, isWorker)
1379
+ )
1380
+ }
1381
+
1116
1382
  function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion) {
1117
1383
  return function (worker, message) {
1118
1384
  if (!testSuiteFinishCh.hasSubscribers) {
1119
1385
  return parseWorkerMessageFunction.apply(this, arguments)
1120
1386
  }
1121
- // If the message is an array, it's a dd-trace message, so we need to stop cucumber processing,
1122
- // or cucumber will throw an error
1123
- // TODO: identify the message better
1124
- if (Array.isArray(message)) {
1125
- const [messageCode, payload] = message
1126
- if (messageCode === CUCUMBER_WORKER_TRACE_PAYLOAD_CODE) {
1127
- collectAttemptToFixExecutionsFromTraces(payload, attemptToFixExecutions)
1128
- workerReportTraceCh.publish(payload)
1129
- return
1130
- }
1131
- }
1132
- if (message[DD_EFD_RETRY_COUNT_MESSAGE]) {
1133
- handleEfdRetryCountMessage(message[DD_EFD_RETRY_COUNT_MESSAGE])
1134
- return
1135
- }
1387
+ // If it's a dd-trace message, stop cucumber processing or cucumber will throw an error.
1388
+ if (handleDdWorkerMessage(message)) return
1136
1389
 
1137
1390
  const envelope = isNewVersion ? message.envelope : message.jsonEnvelope
1138
1391
 
@@ -1149,10 +1402,7 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1149
1402
  return parseWorkerMessageFunction.apply(this, arguments)
1150
1403
  }
1151
1404
  }
1152
- if (parsed[DD_EFD_RETRY_COUNT_MESSAGE]) {
1153
- handleEfdRetryCountMessage(parsed[DD_EFD_RETRY_COUNT_MESSAGE])
1154
- return
1155
- }
1405
+ if (handleDdWorkerMessage(parsed)) return
1156
1406
  let pickle
1157
1407
 
1158
1408
  if (parsed.testCaseStarted) {
@@ -1162,15 +1412,7 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1162
1412
  const { pickleId } = this.eventDataCollector.testCaseMap[parsed.testCaseStarted.testCaseId]
1163
1413
  pickle = this.eventDataCollector.getPickle(pickleId)
1164
1414
  }
1165
- // THIS FAILS IN PARALLEL MODE
1166
- const testFileAbsolutePath = pickle.uri
1167
- // First test in suite
1168
- if (!pickleResultByFile[testFileAbsolutePath]) {
1169
- pickleResultByFile[testFileAbsolutePath] = []
1170
- testSuiteStartCh.publish({
1171
- testFileAbsolutePath,
1172
- })
1173
- }
1415
+ maybeStartParallelSuite(pickle)
1174
1416
  }
1175
1417
 
1176
1418
  const parseWorkerResponse = parseWorkerMessageFunction.apply(this, arguments)
@@ -1188,66 +1430,15 @@ function getWrappedParseWorkerMessage (parseWorkerMessageFunction, isNewVersion)
1188
1430
  pickle = testCase.pickle
1189
1431
  }
1190
1432
 
1191
- const { status } = getStatusFromResultLatest(worstTestStepResult)
1192
- let isNew = false
1193
-
1194
- if (isKnownTestsEnabled) {
1195
- isNew = isNewTest(pickle.uri, pickle.name)
1196
- }
1197
-
1198
- const testFileAbsolutePath = pickle.uri
1199
- const finished = pickleResultByFile[testFileAbsolutePath]
1200
-
1201
- if (isEarlyFlakeDetectionEnabled && isNew) {
1202
- const testFullname = `${pickle.uri}:${pickle.name}`
1203
- let testStatuses = newTestsByTestFullname.get(testFullname)
1204
- if (testStatuses) {
1205
- testStatuses.push(status)
1206
- } else {
1207
- testStatuses = [status]
1208
- newTestsByTestFullname.set(testFullname, testStatuses)
1209
- }
1210
- let efdRetryCount = efdRetryCountByPickleId.get(pickle.id)
1211
- if (efdRetryCount === undefined) {
1212
- efdRetryCount = status === 'skip'
1213
- ? 0
1214
- : getConfiguredEfdRetryCount()
1215
- efdRetryCountByPickleId.set(pickle.id, efdRetryCount)
1216
- if (efdRetryCount === 0 && status !== 'skip') {
1217
- efdSlowAbortedPickleIds.add(pickle.id)
1218
- }
1219
- }
1220
- maybeRecordFinalParallelEfdStatus({ pickleId: pickle.id, testFileAbsolutePath, testFullname })
1221
- } else if (
1222
- isTestManagementTestsEnabled &&
1223
- getTestProperties(getTestSuitePath(testFileAbsolutePath, process.cwd()), pickle.name).attemptToFix
1224
- ) {
1225
- const testFullname = `${pickle.uri}:${pickle.name}`
1226
- let testStatuses = attemptToFixTestsByTestFullname.get(testFullname)
1227
- if (testStatuses) {
1228
- testStatuses.push(status)
1229
- } else {
1230
- testStatuses = [status]
1231
- attemptToFixTestsByTestFullname.set(testFullname, testStatuses)
1232
- }
1233
-
1234
- if (status === 'skip' || testStatuses.length === testManagementAttemptToFixRetries + 1) {
1235
- finished.push(getTestStatusFromAttemptToFixExecutions(testStatuses))
1236
- attemptToFixTestsByTestFullname.delete(testFullname)
1237
- }
1238
- } else {
1239
- // TODO: can we get error message?
1240
- const finished = pickleResultByFile[testFileAbsolutePath]
1241
- finished.push(status)
1242
- }
1243
-
1244
- finishParallelSuiteIfDone(testFileAbsolutePath)
1433
+ handleParallelTestCaseFinished(pickle, worstTestStepResult)
1245
1434
  }
1246
1435
 
1247
1436
  return parseWorkerResponse
1248
1437
  }
1249
1438
  }
1250
1439
 
1440
+ module.exports.patchCucumberWorkerRunTestCase = patchCucumberWorkerRunTestCase
1441
+
1251
1442
  // Test start / finish for older versions. The only hook executed in workers when in parallel mode
1252
1443
  addHook({
1253
1444
  name: '@cucumber/cucumber',
@@ -1319,11 +1510,7 @@ addHook({
1319
1510
  versions: ['>=11.0.0'],
1320
1511
  file: 'lib/runtime/worker.js',
1321
1512
  }, (workerPackage) => {
1322
- shimmer.wrap(
1323
- workerPackage.Worker.prototype,
1324
- 'runTestCase',
1325
- runTestCase => getWrappedRunTestCase(runTestCase, true, !!getEnvironmentVariable('CUCUMBER_WORKER_ID'))
1326
- )
1513
+ patchCucumberWorkerRunTestCase(workerPackage, !!getEnvironmentVariable('CUCUMBER_WORKER_ID'))
1327
1514
  return workerPackage
1328
1515
  })
1329
1516
 
@@ -1359,7 +1546,7 @@ addHook({
1359
1546
  // In `startWorker` we pass early flake detection info to the worker.
1360
1547
  addHook({
1361
1548
  name: '@cucumber/cucumber',
1362
- versions: ['>=11.0.0'],
1549
+ versions: ['>=11.0.0 <13.0.0'],
1363
1550
  file: 'lib/runtime/parallel/adapter.js',
1364
1551
  }, (adapterPackage) => {
1365
1552
  shimmer.wrap(
@@ -1369,46 +1556,43 @@ addHook({
1369
1556
  )
1370
1557
  // EFD in parallel mode only supported in >=11.0.0
1371
1558
  shimmer.wrap(adapterPackage.ChildProcessAdapter.prototype, 'startWorker', startWorker => function (...args) {
1372
- if (isKnownTestsEnabled && isValidKnownTests(knownTests)) {
1373
- this.options.worldParameters._ddIsKnownTestsEnabled = true
1374
- this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
1375
- this.options.worldParameters._ddKnownTests = knownTests
1376
- this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
1377
- this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = earlyFlakeDetectionSlowTestRetries
1378
- } else {
1379
- isEarlyFlakeDetectionEnabled = false
1380
- isKnownTestsEnabled = false
1381
- this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled = false
1382
- this.options.worldParameters._ddIsKnownTestsEnabled = false
1383
- this.options.worldParameters._ddEarlyFlakeDetectionNumRetries = 0
1384
- this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries = {}
1385
- }
1386
-
1387
- if (isImpactedTestsEnabled) {
1388
- this.options.worldParameters._ddImpactedTestsEnabled = isImpactedTestsEnabled
1389
- this.options.worldParameters._ddModifiedFiles = modifiedFiles
1390
- }
1391
-
1392
- this.options.worldParameters._ddIsFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
1393
- this.options.worldParameters._ddNumTestRetries = numTestRetries
1394
-
1395
- if (isTestManagementTestsEnabled) {
1396
- this.options.worldParameters._ddIsTestManagementTestsEnabled = true
1397
- this.options.worldParameters._ddTestManagementTests = testManagementTests
1398
- this.options.worldParameters._ddTestManagementAttemptToFixRetries = testManagementAttemptToFixRetries
1399
- }
1400
-
1559
+ configureParallelWorkerWorldParameters(this.options)
1401
1560
  return startWorker.apply(this, args)
1402
1561
  })
1403
1562
  return adapterPackage
1404
1563
  })
1405
1564
 
1565
+ // Only executed in parallel mode for >=13, in the main process.
1566
+ // Cucumber v13 uses worker_threads and receives worker events via MessagePort.
1567
+ addHook({
1568
+ name: '@cucumber/cucumber',
1569
+ versions: ['>=13.0.0'],
1570
+ file: 'lib/runtime/parallel/adapter.js',
1571
+ }, (adapterPackage) => {
1572
+ shimmer.wrap(
1573
+ adapterPackage.WorkerThreadsAdapter.prototype,
1574
+ 'setup',
1575
+ setup => getWrappedWorkerThreadsSetup(setup)
1576
+ )
1577
+ shimmer.wrap(
1578
+ adapterPackage.WorkerThreadsAdapter.prototype,
1579
+ 'handleEventFromWorker',
1580
+ handleEventFromWorker => getWrappedHandleWorkerThreadEvent(handleEventFromWorker)
1581
+ )
1582
+ shimmer.wrap(
1583
+ adapterPackage.WorkerThreadsAdapter.prototype,
1584
+ 'teardown',
1585
+ teardown => getWrappedWorkerThreadsTeardown(teardown)
1586
+ )
1587
+ return adapterPackage
1588
+ })
1589
+
1406
1590
  // Hook executed in the worker process when in parallel mode.
1407
1591
  // In this hook we read the information passed in `worldParameters` and make it available for
1408
1592
  // `getWrappedRunTestCase`.
1409
1593
  addHook({
1410
1594
  name: '@cucumber/cucumber',
1411
- versions: ['>=11.0.0'],
1595
+ versions: ['>=11.0.0 <13.0.0'],
1412
1596
  file: 'lib/runtime/parallel/worker.js',
1413
1597
  }, (workerPackage) => {
1414
1598
  shimmer.wrap(
@@ -1416,31 +1600,7 @@ addHook({
1416
1600
  'initialize',
1417
1601
  initialize => async function () {
1418
1602
  await initialize.apply(this, arguments)
1419
- isKnownTestsEnabled = !!this.options.worldParameters._ddIsKnownTestsEnabled
1420
- if (isKnownTestsEnabled) {
1421
- knownTests = this.options.worldParameters._ddKnownTests
1422
- // if for whatever reason the worker does not receive valid known tests, we disable EFD and known tests
1423
- if (!isValidKnownTests(knownTests)) {
1424
- isKnownTestsEnabled = false
1425
- knownTests = {}
1426
- }
1427
- }
1428
- isEarlyFlakeDetectionEnabled = !!this.options.worldParameters._ddIsEarlyFlakeDetectionEnabled
1429
- if (isEarlyFlakeDetectionEnabled) {
1430
- earlyFlakeDetectionNumRetries = this.options.worldParameters._ddEarlyFlakeDetectionNumRetries
1431
- earlyFlakeDetectionSlowTestRetries = this.options.worldParameters._ddEarlyFlakeDetectionSlowTestRetries ?? {}
1432
- }
1433
- isImpactedTestsEnabled = !!this.options.worldParameters._ddImpactedTestsEnabled
1434
- if (isImpactedTestsEnabled) {
1435
- modifiedFiles = this.options.worldParameters._ddModifiedFiles
1436
- }
1437
- isFlakyTestRetriesEnabled = !!this.options.worldParameters._ddIsFlakyTestRetriesEnabled
1438
- numTestRetries = this.options.worldParameters._ddNumTestRetries ?? 0
1439
- isTestManagementTestsEnabled = !!this.options.worldParameters._ddIsTestManagementTestsEnabled
1440
- if (isTestManagementTestsEnabled) {
1441
- testManagementTests = this.options.worldParameters._ddTestManagementTests
1442
- testManagementAttemptToFixRetries = this.options.worldParameters._ddTestManagementAttemptToFixRetries
1443
- }
1603
+ readParallelWorkerWorldParameters(this.options)
1444
1604
  }
1445
1605
  )
1446
1606
  return workerPackage
@@ -3,7 +3,7 @@
3
3
  const BaseAwsSdkPlugin = require('../../base')
4
4
  const { parseModelId } = require('./utils')
5
5
 
6
- const enabledOperations = new Set(['invokeModel', 'invokeModelWithResponseStream'])
6
+ const enabledOperations = new Set(['invokeModel', 'invokeModelWithResponseStream', 'converse', 'converseStream'])
7
7
 
8
8
  class BedrockRuntime extends BaseAwsSdkPlugin {
9
9
  static id = 'bedrockruntime'