dd-trace 5.35.0 → 5.37.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/LICENSE-3rdparty.csv +2 -1
- package/index.d.ts +8 -7
- package/loader-hook.mjs +0 -4
- package/package.json +15 -14
- package/packages/datadog-core/index.js +1 -1
- package/packages/datadog-core/src/storage.js +76 -31
- package/packages/datadog-instrumentations/src/cucumber.js +54 -1
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +2 -2
- package/packages/datadog-instrumentations/src/jest.js +105 -11
- package/packages/datadog-instrumentations/src/mocha/main.js +46 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +35 -2
- package/packages/datadog-instrumentations/src/mocha/worker.js +7 -0
- package/packages/datadog-instrumentations/src/mysql2.js +3 -3
- package/packages/datadog-instrumentations/src/openai.js +8 -0
- package/packages/datadog-instrumentations/src/playwright.js +70 -22
- package/packages/datadog-instrumentations/src/vitest.js +60 -6
- package/packages/datadog-plugin-aerospike/src/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -4
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +2 -2
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +31 -14
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +72 -7
- package/packages/datadog-plugin-cypress/src/support.js +36 -29
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
- package/packages/datadog-plugin-graphql/src/utils.js +8 -1
- package/packages/datadog-plugin-grpc/src/client.js +1 -1
- package/packages/datadog-plugin-grpc/src/server.js +1 -1
- package/packages/datadog-plugin-hapi/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +3 -3
- package/packages/datadog-plugin-http2/src/server.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +17 -12
- package/packages/datadog-plugin-langchain/src/tracing.js +1 -1
- package/packages/datadog-plugin-mariadb/src/index.js +3 -3
- package/packages/datadog-plugin-mocha/src/index.js +35 -16
- package/packages/datadog-plugin-mongodb-core/src/index.js +28 -2
- package/packages/datadog-plugin-next/src/index.js +4 -4
- package/packages/datadog-plugin-openai/src/tracing.js +2 -3
- package/packages/datadog-plugin-playwright/src/index.js +35 -9
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +2 -2
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +36 -12
- package/packages/dd-trace/src/appsec/graphql.js +6 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +3 -7
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +15 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +17 -30
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -11
- package/packages/dd-trace/src/appsec/iast/analyzers/stored-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +2 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +24 -4
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +2 -2
- package/packages/dd-trace/src/appsec/iast/index.js +4 -2
- package/packages/dd-trace/src/appsec/iast/security-controls/index.js +187 -0
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +96 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/constants.js +6 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +2 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +8 -8
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +65 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +14 -5
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +80 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks.js +28 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +5 -0
- package/packages/dd-trace/src/appsec/iast/utils.js +24 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +8 -13
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +5 -5
- package/packages/dd-trace/src/appsec/rasp/lfi.js +3 -3
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +4 -4
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +3 -3
- package/packages/dd-trace/src/appsec/reporter.js +3 -3
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/index.js +1 -1
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +31 -56
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +20 -2
- package/packages/dd-trace/src/ci-visibility/quarantined-tests/get-quarantined-tests.js +62 -0
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -2
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +3 -3
- package/packages/dd-trace/src/config.js +18 -3
- package/packages/dd-trace/src/data_streams_context.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +14 -7
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +50 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +38 -10
- package/packages/dd-trace/src/exporters/common/agents.js +1 -1
- package/packages/dd-trace/src/exporters/common/request.js +3 -3
- package/packages/dd-trace/src/iitm.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +12 -2
- package/packages/dd-trace/src/log/writer.js +3 -3
- package/packages/dd-trace/src/noop/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +5 -4
- package/packages/dd-trace/src/opentracing/span.js +3 -3
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/apollo.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +51 -4
- package/packages/dd-trace/src/plugins/database.js +14 -4
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +8 -8
- package/packages/dd-trace/src/plugins/tracing.js +3 -3
- package/packages/dd-trace/src/plugins/util/git.js +3 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +1 -3
- package/packages/dd-trace/src/plugins/util/test.js +10 -4
- package/packages/dd-trace/src/profiling/exporters/agent.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/proxy.js +5 -1
- package/packages/dd-trace/src/ritm.js +2 -1
- package/packages/dd-trace/src/scope.js +5 -5
- package/packages/dd-trace/src/spanleak.js +0 -1
- package/packages/dd-trace/src/tracer.js +0 -14
- package/packages/memwatch/package.json +0 -9
|
@@ -9,6 +9,7 @@ const testPassCh = channel('ci:vitest:test:pass')
|
|
|
9
9
|
const testErrorCh = channel('ci:vitest:test:error')
|
|
10
10
|
const testSkipCh = channel('ci:vitest:test:skip')
|
|
11
11
|
const isNewTestCh = channel('ci:vitest:test:is-new')
|
|
12
|
+
const isQuarantinedCh = channel('ci:vitest:test:is-quarantined')
|
|
12
13
|
|
|
13
14
|
// test suite hooks
|
|
14
15
|
const testSuiteStartCh = channel('ci:vitest:test-suite:start')
|
|
@@ -21,10 +22,12 @@ const testSessionFinishCh = channel('ci:vitest:session:finish')
|
|
|
21
22
|
const libraryConfigurationCh = channel('ci:vitest:library-configuration')
|
|
22
23
|
const knownTestsCh = channel('ci:vitest:known-tests')
|
|
23
24
|
const isEarlyFlakeDetectionFaultyCh = channel('ci:vitest:is-early-flake-detection-faulty')
|
|
25
|
+
const quarantinedTestsCh = channel('ci:vitest:quarantined-tests')
|
|
24
26
|
|
|
25
27
|
const taskToAsync = new WeakMap()
|
|
26
28
|
const taskToStatuses = new WeakMap()
|
|
27
29
|
const newTasks = new WeakSet()
|
|
30
|
+
const quarantinedTasks = new WeakSet()
|
|
28
31
|
let isRetryReasonEfd = false
|
|
29
32
|
const switchedStatuses = new WeakSet()
|
|
30
33
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
@@ -46,7 +49,9 @@ function getProvidedContext () {
|
|
|
46
49
|
_ddIsDiEnabled,
|
|
47
50
|
_ddKnownTests: knownTests,
|
|
48
51
|
_ddEarlyFlakeDetectionNumRetries: numRepeats,
|
|
49
|
-
_ddIsKnownTestsEnabled: isKnownTestsEnabled
|
|
52
|
+
_ddIsKnownTestsEnabled: isKnownTestsEnabled,
|
|
53
|
+
_ddIsQuarantinedTestsEnabled: isQuarantinedTestsEnabled,
|
|
54
|
+
_ddQuarantinedTests: quarantinedTests
|
|
50
55
|
} = globalThis.__vitest_worker__.providedContext
|
|
51
56
|
|
|
52
57
|
return {
|
|
@@ -54,7 +59,9 @@ function getProvidedContext () {
|
|
|
54
59
|
isEarlyFlakeDetectionEnabled: _ddIsEarlyFlakeDetectionEnabled,
|
|
55
60
|
knownTests,
|
|
56
61
|
numRepeats,
|
|
57
|
-
isKnownTestsEnabled
|
|
62
|
+
isKnownTestsEnabled,
|
|
63
|
+
isQuarantinedTestsEnabled,
|
|
64
|
+
quarantinedTests
|
|
58
65
|
}
|
|
59
66
|
} catch (e) {
|
|
60
67
|
log.error('Vitest workers could not parse provided context, so some features will not work.')
|
|
@@ -63,7 +70,9 @@ function getProvidedContext () {
|
|
|
63
70
|
isEarlyFlakeDetectionEnabled: false,
|
|
64
71
|
knownTests: {},
|
|
65
72
|
numRepeats: 0,
|
|
66
|
-
isKnownTestsEnabled: false
|
|
73
|
+
isKnownTestsEnabled: false,
|
|
74
|
+
isQuarantinedTestsEnabled: false,
|
|
75
|
+
quarantinedTests: {}
|
|
67
76
|
}
|
|
68
77
|
}
|
|
69
78
|
}
|
|
@@ -158,8 +167,10 @@ function getSortWrapper (sort) {
|
|
|
158
167
|
let earlyFlakeDetectionNumRetries = 0
|
|
159
168
|
let isEarlyFlakeDetectionFaulty = false
|
|
160
169
|
let isKnownTestsEnabled = false
|
|
170
|
+
let isQuarantinedTestsEnabled = false
|
|
161
171
|
let isDiEnabled = false
|
|
162
172
|
let knownTests = {}
|
|
173
|
+
let quarantinedTests = {}
|
|
163
174
|
|
|
164
175
|
try {
|
|
165
176
|
const { err, libraryConfig } = await getChannelPromise(libraryConfigurationCh)
|
|
@@ -170,6 +181,7 @@ function getSortWrapper (sort) {
|
|
|
170
181
|
earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
171
182
|
isDiEnabled = libraryConfig.isDiEnabled
|
|
172
183
|
isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
|
|
184
|
+
isQuarantinedTestsEnabled = libraryConfig.isQuarantinedTestsEnabled
|
|
173
185
|
}
|
|
174
186
|
} catch (e) {
|
|
175
187
|
isFlakyTestRetriesEnabled = false
|
|
@@ -229,6 +241,23 @@ function getSortWrapper (sort) {
|
|
|
229
241
|
}
|
|
230
242
|
}
|
|
231
243
|
|
|
244
|
+
if (isQuarantinedTestsEnabled) {
|
|
245
|
+
const { err, quarantinedTests: receivedQuarantinedTests } = await getChannelPromise(quarantinedTestsCh)
|
|
246
|
+
if (!err) {
|
|
247
|
+
quarantinedTests = receivedQuarantinedTests
|
|
248
|
+
try {
|
|
249
|
+
const workspaceProject = this.ctx.getCoreWorkspaceProject()
|
|
250
|
+
workspaceProject._provided._ddIsQuarantinedTestsEnabled = isQuarantinedTestsEnabled
|
|
251
|
+
workspaceProject._provided._ddQuarantinedTests = quarantinedTests
|
|
252
|
+
} catch (e) {
|
|
253
|
+
log.warn('Could not send quarantined tests to workers so Quarantine will not work.')
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
isQuarantinedTestsEnabled = false
|
|
257
|
+
log.error('Could not get quarantined tests.')
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
232
261
|
let testCodeCoverageLinesTotal
|
|
233
262
|
|
|
234
263
|
if (this.ctx.coverageProvider?.generateCoverage) {
|
|
@@ -263,6 +292,7 @@ function getSortWrapper (sort) {
|
|
|
263
292
|
error,
|
|
264
293
|
isEarlyFlakeDetectionEnabled,
|
|
265
294
|
isEarlyFlakeDetectionFaulty,
|
|
295
|
+
isQuarantinedTestsEnabled,
|
|
266
296
|
onFinish
|
|
267
297
|
})
|
|
268
298
|
})
|
|
@@ -332,7 +362,7 @@ addHook({
|
|
|
332
362
|
|
|
333
363
|
// `onAfterRunTask` is run after all repetitions or attempts are run
|
|
334
364
|
shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => async function (task) {
|
|
335
|
-
const { isEarlyFlakeDetectionEnabled } = getProvidedContext()
|
|
365
|
+
const { isEarlyFlakeDetectionEnabled, isQuarantinedTestsEnabled } = getProvidedContext()
|
|
336
366
|
|
|
337
367
|
if (isEarlyFlakeDetectionEnabled && taskToStatuses.has(task)) {
|
|
338
368
|
const statuses = taskToStatuses.get(task)
|
|
@@ -345,6 +375,12 @@ addHook({
|
|
|
345
375
|
}
|
|
346
376
|
}
|
|
347
377
|
|
|
378
|
+
if (isQuarantinedTestsEnabled) {
|
|
379
|
+
if (quarantinedTasks.has(task)) {
|
|
380
|
+
task.result.state = 'pass'
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
348
384
|
return onAfterRunTask.apply(this, arguments)
|
|
349
385
|
})
|
|
350
386
|
|
|
@@ -356,17 +392,34 @@ addHook({
|
|
|
356
392
|
}
|
|
357
393
|
const testName = getTestName(task)
|
|
358
394
|
let isNew = false
|
|
395
|
+
let isQuarantined = false
|
|
359
396
|
|
|
360
397
|
const {
|
|
361
398
|
isKnownTestsEnabled,
|
|
362
399
|
isEarlyFlakeDetectionEnabled,
|
|
363
|
-
isDiEnabled
|
|
400
|
+
isDiEnabled,
|
|
401
|
+
isQuarantinedTestsEnabled,
|
|
402
|
+
quarantinedTests
|
|
364
403
|
} = getProvidedContext()
|
|
365
404
|
|
|
366
405
|
if (isKnownTestsEnabled) {
|
|
367
406
|
isNew = newTasks.has(task)
|
|
368
407
|
}
|
|
369
408
|
|
|
409
|
+
if (isQuarantinedTestsEnabled) {
|
|
410
|
+
isQuarantinedCh.publish({
|
|
411
|
+
quarantinedTests,
|
|
412
|
+
testSuiteAbsolutePath: task.file.filepath,
|
|
413
|
+
testName,
|
|
414
|
+
onDone: (isTestQuarantined) => {
|
|
415
|
+
isQuarantined = isTestQuarantined
|
|
416
|
+
if (isTestQuarantined) {
|
|
417
|
+
quarantinedTasks.add(task)
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
})
|
|
421
|
+
}
|
|
422
|
+
|
|
370
423
|
const { retry: numAttempt, repeats: numRepetition } = retryInfo
|
|
371
424
|
|
|
372
425
|
// We finish the previous test here because we know it has failed already
|
|
@@ -448,7 +501,8 @@ addHook({
|
|
|
448
501
|
isRetry: numAttempt > 0 || numRepetition > 0,
|
|
449
502
|
isRetryReasonEfd,
|
|
450
503
|
isNew,
|
|
451
|
-
mightHitProbe: isDiEnabled && numAttempt > 0
|
|
504
|
+
mightHitProbe: isDiEnabled && numAttempt > 0,
|
|
505
|
+
isQuarantined
|
|
452
506
|
})
|
|
453
507
|
})
|
|
454
508
|
return onBeforeTryTask.apply(this, arguments)
|
|
@@ -20,7 +20,7 @@ class AerospikePlugin extends DatabasePlugin {
|
|
|
20
20
|
bindStart (ctx) {
|
|
21
21
|
const { commandName, commandArgs } = ctx
|
|
22
22
|
const resourceName = commandName.slice(0, commandName.indexOf('Command'))
|
|
23
|
-
const store = storage.getStore()
|
|
23
|
+
const store = storage('legacy').getStore()
|
|
24
24
|
const childOf = store ? store.span : null
|
|
25
25
|
const meta = getMeta(resourceName, commandArgs)
|
|
26
26
|
|
|
@@ -25,7 +25,7 @@ class ApolloGatewayPlugin extends CompositePlugin {
|
|
|
25
25
|
constructor (...args) {
|
|
26
26
|
super(...args)
|
|
27
27
|
this.addSub('apm:apollo:gateway:general:error', (ctx) => {
|
|
28
|
-
const store = storage.getStore()
|
|
28
|
+
const store = storage('legacy').getStore()
|
|
29
29
|
const span = store?.span
|
|
30
30
|
if (!span) return
|
|
31
31
|
span.setTag('error', ctx.error)
|
|
@@ -67,13 +67,13 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
67
67
|
span.addTags(requestTags)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const store = storage.getStore()
|
|
70
|
+
const store = storage('legacy').getStore()
|
|
71
71
|
|
|
72
72
|
this.enter(span, store)
|
|
73
73
|
})
|
|
74
74
|
|
|
75
75
|
this.addSub(`apm:aws:request:region:${this.serviceIdentifier}`, region => {
|
|
76
|
-
const store = storage.getStore()
|
|
76
|
+
const store = storage('legacy').getStore()
|
|
77
77
|
if (!store) return
|
|
78
78
|
const { span } = store
|
|
79
79
|
if (!span) return
|
|
@@ -82,7 +82,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
82
82
|
})
|
|
83
83
|
|
|
84
84
|
this.addSub(`apm:aws:request:complete:${this.serviceIdentifier}`, ({ response, cbExists = false }) => {
|
|
85
|
-
const store = storage.getStore()
|
|
85
|
+
const store = storage('legacy').getStore()
|
|
86
86
|
if (!store) return
|
|
87
87
|
const { span } = store
|
|
88
88
|
if (!span) return
|
|
@@ -21,7 +21,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
21
21
|
|
|
22
22
|
this.addSub('apm:aws:response:start:kinesis', obj => {
|
|
23
23
|
const { request, response } = obj
|
|
24
|
-
const store = storage.getStore()
|
|
24
|
+
const store = storage('legacy').getStore()
|
|
25
25
|
const plugin = this
|
|
26
26
|
|
|
27
27
|
// if we have either of these operations, we want to store the streamName param
|
|
@@ -49,7 +49,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// get the stream name that should have been stored previously
|
|
52
|
-
const { streamName } = storage.getStore()
|
|
52
|
+
const { streamName } = storage('legacy').getStore()
|
|
53
53
|
|
|
54
54
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
55
55
|
this.responseExtractDSMContext(
|
|
@@ -59,7 +59,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
this.addSub('apm:aws:response:finish:kinesis', err => {
|
|
62
|
-
const { span } = storage.getStore()
|
|
62
|
+
const { span } = storage('legacy').getStore()
|
|
63
63
|
this.finish(span, null, err)
|
|
64
64
|
})
|
|
65
65
|
}
|
|
@@ -79,7 +79,7 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
79
79
|
if (!params || !params.StreamName) return
|
|
80
80
|
|
|
81
81
|
const streamName = params.StreamName
|
|
82
|
-
storage.enterWith({ ...store, streamName })
|
|
82
|
+
storage('legacy').enterWith({ ...store, streamName })
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
responseExtract (params, operation, response) {
|
|
@@ -20,7 +20,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
20
20
|
|
|
21
21
|
this.addSub('apm:aws:response:start:sqs', obj => {
|
|
22
22
|
const { request, response } = obj
|
|
23
|
-
const store = storage.getStore()
|
|
23
|
+
const store = storage('legacy').getStore()
|
|
24
24
|
const plugin = this
|
|
25
25
|
const contextExtraction = this.responseExtract(request.params, request.operation, response)
|
|
26
26
|
let span
|
|
@@ -47,7 +47,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
this.addSub('apm:aws:response:finish:sqs', err => {
|
|
50
|
-
const { span } = storage.getStore()
|
|
50
|
+
const { span } = storage('legacy').getStore()
|
|
51
51
|
this.finish(span, null, err)
|
|
52
52
|
})
|
|
53
53
|
}
|
|
@@ -24,7 +24,7 @@ class AzureFunctionsPlugin extends TracingPlugin {
|
|
|
24
24
|
|
|
25
25
|
bindStart (ctx) {
|
|
26
26
|
const { functionName, methodName } = ctx
|
|
27
|
-
const store = storage.getStore()
|
|
27
|
+
const store = storage('legacy').getStore()
|
|
28
28
|
|
|
29
29
|
const span = this.startSpan(this.operationName(), {
|
|
30
30
|
service: this.serviceName(),
|
|
@@ -42,7 +42,7 @@ class CouchBasePlugin extends StoragePlugin {
|
|
|
42
42
|
super(...args)
|
|
43
43
|
|
|
44
44
|
this.addSubs('query', ({ resource, bucket, seedNodes }) => {
|
|
45
|
-
const store = storage.getStore()
|
|
45
|
+
const store = storage('legacy').getStore()
|
|
46
46
|
const span = this.startSpan(
|
|
47
47
|
'query', {
|
|
48
48
|
'span.type': 'sql',
|
|
@@ -64,7 +64,7 @@ class CouchBasePlugin extends StoragePlugin {
|
|
|
64
64
|
|
|
65
65
|
_addCommandSubs (name) {
|
|
66
66
|
this.addSubs(name, ({ bucket, collection, seedNodes }) => {
|
|
67
|
-
const store = storage.getStore()
|
|
67
|
+
const store = storage('legacy').getStore()
|
|
68
68
|
const span = this.startSpan(name, {}, store, { bucket, collection, seedNodes })
|
|
69
69
|
this.enter(span, store)
|
|
70
70
|
})
|
|
@@ -27,7 +27,9 @@ const {
|
|
|
27
27
|
TEST_MODULE_ID,
|
|
28
28
|
TEST_SUITE,
|
|
29
29
|
CUCUMBER_IS_PARALLEL,
|
|
30
|
-
TEST_RETRY_REASON
|
|
30
|
+
TEST_RETRY_REASON,
|
|
31
|
+
TEST_MANAGEMENT_ENABLED,
|
|
32
|
+
TEST_MANAGEMENT_IS_QUARANTINED
|
|
31
33
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
32
34
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
33
35
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -47,6 +49,7 @@ const {
|
|
|
47
49
|
const id = require('../../dd-trace/src/id')
|
|
48
50
|
|
|
49
51
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
52
|
+
const BREAKPOINT_SET_GRACE_PERIOD_MS = 200
|
|
50
53
|
const isCucumberWorker = !!process.env.CUCUMBER_WORKER_ID
|
|
51
54
|
|
|
52
55
|
function getTestSuiteTags (testSuiteSpan) {
|
|
@@ -83,6 +86,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
83
86
|
hasForcedToRunSuites,
|
|
84
87
|
isEarlyFlakeDetectionEnabled,
|
|
85
88
|
isEarlyFlakeDetectionFaulty,
|
|
89
|
+
isQuarantinedTestsEnabled,
|
|
86
90
|
isParallel
|
|
87
91
|
}) => {
|
|
88
92
|
const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.libraryConfig || {}
|
|
@@ -109,6 +113,9 @@ class CucumberPlugin extends CiPlugin {
|
|
|
109
113
|
if (isParallel) {
|
|
110
114
|
this.testSessionSpan.setTag(CUCUMBER_IS_PARALLEL, 'true')
|
|
111
115
|
}
|
|
116
|
+
if (isQuarantinedTestsEnabled) {
|
|
117
|
+
this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
|
|
118
|
+
}
|
|
112
119
|
|
|
113
120
|
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
114
121
|
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
@@ -213,7 +220,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
213
220
|
isParallel,
|
|
214
221
|
promises
|
|
215
222
|
}) => {
|
|
216
|
-
const store = storage.getStore()
|
|
223
|
+
const store = storage('legacy').getStore()
|
|
217
224
|
const testSuite = getTestSuitePath(testFileAbsolutePath, this.sourceRoot)
|
|
218
225
|
const testSourceFile = getTestSuitePath(testFileAbsolutePath, this.repositoryRoot)
|
|
219
226
|
|
|
@@ -231,7 +238,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
231
238
|
|
|
232
239
|
this.activeTestSpan = testSpan
|
|
233
240
|
// Time we give the breakpoint to be hit
|
|
234
|
-
if (promises && this.
|
|
241
|
+
if (promises && this.runningTestProbe) {
|
|
235
242
|
promises.hitBreakpointPromise = new Promise((resolve) => {
|
|
236
243
|
setTimeout(resolve, BREAKPOINT_HIT_GRACE_PERIOD_MS)
|
|
237
244
|
})
|
|
@@ -239,7 +246,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
239
246
|
})
|
|
240
247
|
|
|
241
248
|
this.addSub('ci:cucumber:test:retry', ({ isFirstAttempt, error }) => {
|
|
242
|
-
const store = storage.getStore()
|
|
249
|
+
const store = storage('legacy').getStore()
|
|
243
250
|
const span = store.span
|
|
244
251
|
if (!isFirstAttempt) {
|
|
245
252
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
@@ -248,10 +255,15 @@ class CucumberPlugin extends CiPlugin {
|
|
|
248
255
|
if (isFirstAttempt && this.di && error && this.libraryConfig?.isDiEnabled) {
|
|
249
256
|
const probeInformation = this.addDiProbe(error)
|
|
250
257
|
if (probeInformation) {
|
|
251
|
-
const {
|
|
252
|
-
this.
|
|
258
|
+
const { file, line, stackIndex } = probeInformation
|
|
259
|
+
this.runningTestProbe = { file, line }
|
|
253
260
|
this.testErrorStackIndex = stackIndex
|
|
254
|
-
|
|
261
|
+
const waitUntil = Date.now() + BREAKPOINT_SET_GRACE_PERIOD_MS
|
|
262
|
+
while (Date.now() < waitUntil) {
|
|
263
|
+
// TODO: To avoid a race condition, we should wait until `probeInformation.setProbePromise` has resolved.
|
|
264
|
+
// However, Cucumber doesn't have a mechanism for waiting asyncrounously here, so for now, we'll have to
|
|
265
|
+
// fall back to a fixed syncronous delay.
|
|
266
|
+
}
|
|
255
267
|
}
|
|
256
268
|
}
|
|
257
269
|
span.setTag(TEST_STATUS, 'fail')
|
|
@@ -260,7 +272,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
260
272
|
})
|
|
261
273
|
|
|
262
274
|
this.addSub('ci:cucumber:test-step:start', ({ resource }) => {
|
|
263
|
-
const store = storage.getStore()
|
|
275
|
+
const store = storage('legacy').getStore()
|
|
264
276
|
const childOf = store ? store.span : store
|
|
265
277
|
const span = this.tracer.startSpan('cucumber.step', {
|
|
266
278
|
childOf,
|
|
@@ -311,9 +323,10 @@ class CucumberPlugin extends CiPlugin {
|
|
|
311
323
|
errorMessage,
|
|
312
324
|
isNew,
|
|
313
325
|
isEfdRetry,
|
|
314
|
-
isFlakyRetry
|
|
326
|
+
isFlakyRetry,
|
|
327
|
+
isQuarantined
|
|
315
328
|
}) => {
|
|
316
|
-
const span = storage.getStore().span
|
|
329
|
+
const span = storage('legacy').getStore().span
|
|
317
330
|
const statusTag = isStep ? 'step.status' : TEST_STATUS
|
|
318
331
|
|
|
319
332
|
span.setTag(statusTag, status)
|
|
@@ -340,6 +353,10 @@ class CucumberPlugin extends CiPlugin {
|
|
|
340
353
|
span.setTag(TEST_IS_RETRY, 'true')
|
|
341
354
|
}
|
|
342
355
|
|
|
356
|
+
if (isQuarantined) {
|
|
357
|
+
span.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
|
|
358
|
+
}
|
|
359
|
+
|
|
343
360
|
span.finish()
|
|
344
361
|
if (!isStep) {
|
|
345
362
|
const spanTags = span.context()._tags
|
|
@@ -359,16 +376,16 @@ class CucumberPlugin extends CiPlugin {
|
|
|
359
376
|
this.tracer._exporter.flush()
|
|
360
377
|
}
|
|
361
378
|
this.activeTestSpan = null
|
|
362
|
-
if (this.
|
|
363
|
-
this.removeDiProbe(this.
|
|
364
|
-
this.
|
|
379
|
+
if (this.runningTestProbe) {
|
|
380
|
+
this.removeDiProbe(this.runningTestProbe)
|
|
381
|
+
this.runningTestProbe = null
|
|
365
382
|
}
|
|
366
383
|
}
|
|
367
384
|
})
|
|
368
385
|
|
|
369
386
|
this.addSub('ci:cucumber:error', (err) => {
|
|
370
387
|
if (err) {
|
|
371
|
-
const span = storage.getStore().span
|
|
388
|
+
const span = storage('legacy').getStore().span
|
|
372
389
|
span.setTag('error', err)
|
|
373
390
|
}
|
|
374
391
|
})
|
|
@@ -32,7 +32,10 @@ const {
|
|
|
32
32
|
getTestSessionName,
|
|
33
33
|
TEST_SESSION_NAME,
|
|
34
34
|
TEST_LEVEL_EVENT_TYPES,
|
|
35
|
-
TEST_RETRY_REASON
|
|
35
|
+
TEST_RETRY_REASON,
|
|
36
|
+
DD_TEST_IS_USER_PROVIDED_SERVICE,
|
|
37
|
+
TEST_MANAGEMENT_IS_QUARANTINED,
|
|
38
|
+
TEST_MANAGEMENT_ENABLED
|
|
36
39
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
37
40
|
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
38
41
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
@@ -151,6 +154,20 @@ function getKnownTests (tracer, testConfiguration) {
|
|
|
151
154
|
})
|
|
152
155
|
}
|
|
153
156
|
|
|
157
|
+
function getQuarantinedTests (tracer, testConfiguration) {
|
|
158
|
+
return new Promise(resolve => {
|
|
159
|
+
if (!tracer._tracer._exporter?.getQuarantinedTests) {
|
|
160
|
+
return resolve({ err: new Error('Test Optimization was not initialized correctly') })
|
|
161
|
+
}
|
|
162
|
+
tracer._tracer._exporter.getQuarantinedTests(testConfiguration, (err, quarantinedTests) => {
|
|
163
|
+
resolve({
|
|
164
|
+
err,
|
|
165
|
+
quarantinedTests
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
154
171
|
function getSuiteStatus (suiteStats) {
|
|
155
172
|
if (!suiteStats) {
|
|
156
173
|
return 'skip'
|
|
@@ -222,6 +239,10 @@ class CypressPlugin {
|
|
|
222
239
|
this.tracer = tracer
|
|
223
240
|
this.cypressConfig = cypressConfig
|
|
224
241
|
|
|
242
|
+
// we have to do it here because the tracer is not initialized in the constructor
|
|
243
|
+
this.testEnvironmentMetadata[DD_TEST_IS_USER_PROVIDED_SERVICE] =
|
|
244
|
+
tracer._tracer._config.isServiceUserProvided ? 'true' : 'false'
|
|
245
|
+
|
|
225
246
|
this.libraryConfigurationPromise = getLibraryConfiguration(this.tracer, this.testConfiguration)
|
|
226
247
|
.then((libraryConfigurationResponse) => {
|
|
227
248
|
if (libraryConfigurationResponse.err) {
|
|
@@ -235,7 +256,8 @@ class CypressPlugin {
|
|
|
235
256
|
earlyFlakeDetectionNumRetries,
|
|
236
257
|
isFlakyTestRetriesEnabled,
|
|
237
258
|
flakyTestRetriesCount,
|
|
238
|
-
isKnownTestsEnabled
|
|
259
|
+
isKnownTestsEnabled,
|
|
260
|
+
isQuarantinedTestsEnabled
|
|
239
261
|
}
|
|
240
262
|
} = libraryConfigurationResponse
|
|
241
263
|
this.isSuitesSkippingEnabled = isSuitesSkippingEnabled
|
|
@@ -246,12 +268,24 @@ class CypressPlugin {
|
|
|
246
268
|
if (isFlakyTestRetriesEnabled) {
|
|
247
269
|
this.cypressConfig.retries.runMode = flakyTestRetriesCount
|
|
248
270
|
}
|
|
271
|
+
this.isQuarantinedTestsEnabled = isQuarantinedTestsEnabled
|
|
249
272
|
}
|
|
250
273
|
return this.cypressConfig
|
|
251
274
|
})
|
|
252
275
|
return this.libraryConfigurationPromise
|
|
253
276
|
}
|
|
254
277
|
|
|
278
|
+
getIsQuarantinedTest (testSuite, testName) {
|
|
279
|
+
return this.quarantinedTests
|
|
280
|
+
?.cypress
|
|
281
|
+
?.suites
|
|
282
|
+
?.[testSuite]
|
|
283
|
+
?.tests
|
|
284
|
+
?.[testName]
|
|
285
|
+
?.properties
|
|
286
|
+
?.quarantined
|
|
287
|
+
}
|
|
288
|
+
|
|
255
289
|
getTestSuiteSpan ({ testSuite, testSuiteAbsolutePath }) {
|
|
256
290
|
const testSuiteSpanMetadata =
|
|
257
291
|
getTestSuiteCommonTags(this.command, this.frameworkVersion, testSuite, TEST_FRAMEWORK_NAME)
|
|
@@ -346,10 +380,6 @@ class CypressPlugin {
|
|
|
346
380
|
})
|
|
347
381
|
}
|
|
348
382
|
|
|
349
|
-
isNewTest (testName, testSuite) {
|
|
350
|
-
return !this.knownTestsByTestSuite?.[testSuite]?.includes(testName)
|
|
351
|
-
}
|
|
352
|
-
|
|
353
383
|
async beforeRun (details) {
|
|
354
384
|
// We need to make sure that the plugin is initialized before running the tests
|
|
355
385
|
// This is for the case where the user has not returned the promise from the init function
|
|
@@ -388,6 +418,19 @@ class CypressPlugin {
|
|
|
388
418
|
}
|
|
389
419
|
}
|
|
390
420
|
|
|
421
|
+
if (this.isQuarantinedTestsEnabled) {
|
|
422
|
+
const quarantinedTestsResponse = await getQuarantinedTests(
|
|
423
|
+
this.tracer,
|
|
424
|
+
this.testConfiguration
|
|
425
|
+
)
|
|
426
|
+
if (quarantinedTestsResponse.err) {
|
|
427
|
+
log.error('Cypress quarantined tests response error', quarantinedTestsResponse.err)
|
|
428
|
+
this.isQuarantinedTestsEnabled = false
|
|
429
|
+
} else {
|
|
430
|
+
this.quarantinedTests = quarantinedTestsResponse.quarantinedTests
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
391
434
|
// `details.specs` are test files
|
|
392
435
|
details.specs?.forEach(({ absolute, relative }) => {
|
|
393
436
|
const isUnskippableSuite = isMarkedAsUnskippable({ path: absolute })
|
|
@@ -466,6 +509,10 @@ class CypressPlugin {
|
|
|
466
509
|
}
|
|
467
510
|
)
|
|
468
511
|
|
|
512
|
+
if (this.isQuarantinedTestsEnabled) {
|
|
513
|
+
this.testSessionSpan.setTag(TEST_MANAGEMENT_ENABLED, 'true')
|
|
514
|
+
}
|
|
515
|
+
|
|
469
516
|
this.testModuleSpan.finish()
|
|
470
517
|
this.ciVisEvent(TELEMETRY_EVENT_FINISHED, 'module')
|
|
471
518
|
this.testSessionSpan.finish()
|
|
@@ -540,6 +587,13 @@ class CypressPlugin {
|
|
|
540
587
|
if (this.itrCorrelationId) {
|
|
541
588
|
skippedTestSpan.setTag(ITR_CORRELATION_ID, this.itrCorrelationId)
|
|
542
589
|
}
|
|
590
|
+
|
|
591
|
+
const isQuarantined = this.getIsQuarantinedTest(spec.relative, cypressTestName)
|
|
592
|
+
|
|
593
|
+
if (isQuarantined) {
|
|
594
|
+
skippedTestSpan.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
|
|
595
|
+
}
|
|
596
|
+
|
|
543
597
|
skippedTestSpan.finish()
|
|
544
598
|
})
|
|
545
599
|
|
|
@@ -643,6 +697,7 @@ class CypressPlugin {
|
|
|
643
697
|
})
|
|
644
698
|
const isUnskippable = this.unskippableSuites.includes(testSuite)
|
|
645
699
|
const isForcedToRun = shouldSkip && isUnskippable
|
|
700
|
+
const isQuarantined = this.getIsQuarantinedTest(testSuite, testName)
|
|
646
701
|
|
|
647
702
|
// skip test
|
|
648
703
|
if (shouldSkip && !isUnskippable) {
|
|
@@ -651,6 +706,12 @@ class CypressPlugin {
|
|
|
651
706
|
return { shouldSkip: true }
|
|
652
707
|
}
|
|
653
708
|
|
|
709
|
+
// TODO: I haven't found a way to trick cypress into ignoring a test
|
|
710
|
+
// The way we'll implement quarantine in cypress is by skipping the test altogether
|
|
711
|
+
if (isQuarantined) {
|
|
712
|
+
return { shouldSkip: true }
|
|
713
|
+
}
|
|
714
|
+
|
|
654
715
|
if (!this.activeTestSpan) {
|
|
655
716
|
this.activeTestSpan = this.getTestSpan({
|
|
656
717
|
testName,
|
|
@@ -676,7 +737,8 @@ class CypressPlugin {
|
|
|
676
737
|
testSuiteAbsolutePath,
|
|
677
738
|
testName,
|
|
678
739
|
isNew,
|
|
679
|
-
isEfdRetry
|
|
740
|
+
isEfdRetry,
|
|
741
|
+
isQuarantined
|
|
680
742
|
} = test
|
|
681
743
|
if (coverage && this.isCodeCoverageEnabled && this.tracer._tracer._exporter?.exportCoverage) {
|
|
682
744
|
const coverageFiles = getCoveredFilenamesFromCoverage(coverage)
|
|
@@ -715,6 +777,9 @@ class CypressPlugin {
|
|
|
715
777
|
this.activeTestSpan.setTag(TEST_RETRY_REASON, 'efd')
|
|
716
778
|
}
|
|
717
779
|
}
|
|
780
|
+
if (isQuarantined) {
|
|
781
|
+
this.activeTestSpan.setTag(TEST_MANAGEMENT_IS_QUARANTINED, 'true')
|
|
782
|
+
}
|
|
718
783
|
const finishedTest = {
|
|
719
784
|
testName,
|
|
720
785
|
testStatus,
|