dd-trace 6.0.0-pre-2b43d31 → 6.0.0-pre-efcd0a3
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.0.0-pre-
|
|
3
|
+
"version": "6.0.0-pre-efcd0a3",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"node": ">=18"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@datadog/native-appsec": "7.1.
|
|
72
|
+
"@datadog/native-appsec": "7.1.1",
|
|
73
73
|
"@datadog/native-iast-rewriter": "2.3.0",
|
|
74
74
|
"@datadog/native-iast-taint-tracking": "1.7.0",
|
|
75
75
|
"@datadog/native-metrics": "^2.0.0",
|
|
@@ -44,11 +44,14 @@ const knownTestsCh = channel('ci:jest:known-tests')
|
|
|
44
44
|
|
|
45
45
|
const itrSkippedSuitesCh = channel('ci:jest:itr:skipped-suites')
|
|
46
46
|
|
|
47
|
+
// Message sent by jest's main process to workers to run a test suite (=test file)
|
|
48
|
+
// https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/types.ts#L37
|
|
49
|
+
const CHILD_MESSAGE_CALL = 1
|
|
47
50
|
// Maximum time we'll wait for the tracer to flush
|
|
48
51
|
const FLUSH_TIMEOUT = 10000
|
|
49
52
|
|
|
50
53
|
let skippableSuites = []
|
|
51
|
-
let knownTests =
|
|
54
|
+
let knownTests = {}
|
|
52
55
|
let isCodeCoverageEnabled = false
|
|
53
56
|
let isSuitesSkippingEnabled = false
|
|
54
57
|
let isUserCodeCoverageEnabled = false
|
|
@@ -73,6 +76,7 @@ const specStatusToTestStatus = {
|
|
|
73
76
|
const asyncResources = new WeakMap()
|
|
74
77
|
const originalTestFns = new WeakMap()
|
|
75
78
|
const retriedTestsToNumAttempts = new Map()
|
|
79
|
+
const newTestsTestStatuses = new Map()
|
|
76
80
|
|
|
77
81
|
// based on https://github.com/facebook/jest/blob/main/packages/jest-circus/src/formatNodeAssertErrors.ts#L41
|
|
78
82
|
function formatJestError (errors) {
|
|
@@ -101,6 +105,13 @@ function getTestEnvironmentOptions (config) {
|
|
|
101
105
|
return {}
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
function getEfdStats (testStatuses) {
|
|
109
|
+
return testStatuses.reduce((acc, testStatus) => {
|
|
110
|
+
acc[testStatus]++
|
|
111
|
+
return acc
|
|
112
|
+
}, { pass: 0, fail: 0 })
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
105
116
|
return class DatadogEnvironment extends BaseEnvironment {
|
|
106
117
|
constructor (config, context) {
|
|
@@ -123,9 +134,12 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
123
134
|
this.isEarlyFlakeDetectionEnabled = this.testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled
|
|
124
135
|
|
|
125
136
|
if (this.isEarlyFlakeDetectionEnabled) {
|
|
137
|
+
const hasKnownTests = !!knownTests.jest
|
|
126
138
|
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
|
|
127
139
|
try {
|
|
128
|
-
this.knownTestsForThisSuite =
|
|
140
|
+
this.knownTestsForThisSuite = hasKnownTests
|
|
141
|
+
? (knownTests.jest[this.testSuite] || [])
|
|
142
|
+
: this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
|
|
129
143
|
} catch (e) {
|
|
130
144
|
// If there has been an error parsing the tests, we'll disable Early Flake Deteciton
|
|
131
145
|
this.isEarlyFlakeDetectionEnabled = false
|
|
@@ -145,7 +159,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
145
159
|
if (typeof knownTestsForSuite === 'string') {
|
|
146
160
|
knownTestsForSuite = JSON.parse(knownTestsForSuite)
|
|
147
161
|
}
|
|
148
|
-
return knownTestsForSuite
|
|
162
|
+
return knownTestsForSuite
|
|
149
163
|
}
|
|
150
164
|
|
|
151
165
|
// Add the `add_test` event we don't have the test object yet, so
|
|
@@ -242,6 +256,19 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
242
256
|
})
|
|
243
257
|
// restore in case it is retried
|
|
244
258
|
event.test.fn = originalTestFns.get(event.test)
|
|
259
|
+
// We'll store the test statuses of the retries
|
|
260
|
+
if (this.isEarlyFlakeDetectionEnabled) {
|
|
261
|
+
const testName = getJestTestName(event.test)
|
|
262
|
+
const originalTestName = removeEfdStringFromTestName(testName)
|
|
263
|
+
const isNewTest = retriedTestsToNumAttempts.has(originalTestName)
|
|
264
|
+
if (isNewTest) {
|
|
265
|
+
if (newTestsTestStatuses.has(originalTestName)) {
|
|
266
|
+
newTestsTestStatuses.get(originalTestName).push(status)
|
|
267
|
+
} else {
|
|
268
|
+
newTestsTestStatuses.set(originalTestName, [status])
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
245
272
|
})
|
|
246
273
|
}
|
|
247
274
|
if (event.name === 'test_skip' || event.name === 'test_todo') {
|
|
@@ -508,6 +535,28 @@ function cliWrapper (cli, jestVersion) {
|
|
|
508
535
|
|
|
509
536
|
numSkippedSuites = 0
|
|
510
537
|
|
|
538
|
+
/**
|
|
539
|
+
* If Early Flake Detection (EFD) is enabled the logic is as follows:
|
|
540
|
+
* - If all attempts for a test are failing, the test has failed and we will let the test process fail.
|
|
541
|
+
* - If just a single attempt passes, we will prevent the test process from failing.
|
|
542
|
+
* The rationale behind is the following: you may still be able to block your CI pipeline by gating
|
|
543
|
+
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
if (isEarlyFlakeDetectionEnabled) {
|
|
547
|
+
let numFailedTestsToIgnore = 0
|
|
548
|
+
for (const testStatuses of newTestsTestStatuses.values()) {
|
|
549
|
+
const { pass, fail } = getEfdStats(testStatuses)
|
|
550
|
+
if (pass > 0) { // as long as one passes, we'll consider the test passed
|
|
551
|
+
numFailedTestsToIgnore += fail
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
// If every test that failed was an EFD retry, we'll consider the suite passed
|
|
555
|
+
if (numFailedTestsToIgnore !== 0 && result.results.numFailedTests === numFailedTestsToIgnore) {
|
|
556
|
+
result.results.success = true
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
511
560
|
return result
|
|
512
561
|
})
|
|
513
562
|
|
|
@@ -619,7 +668,6 @@ function configureTestEnvironment (readConfigsResult) {
|
|
|
619
668
|
// because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
|
|
620
669
|
configs.forEach(config => {
|
|
621
670
|
config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
|
|
622
|
-
config.testEnvironmentOptions._ddKnownTests = knownTests
|
|
623
671
|
})
|
|
624
672
|
|
|
625
673
|
isUserCodeCoverageEnabled = !!readConfigsResult.globalConfig.collectCoverage
|
|
@@ -795,6 +843,38 @@ addHook({
|
|
|
795
843
|
file: 'build/workers/ChildProcessWorker.js'
|
|
796
844
|
}, (childProcessWorker) => {
|
|
797
845
|
const ChildProcessWorker = childProcessWorker.default
|
|
846
|
+
shimmer.wrap(ChildProcessWorker.prototype, 'send', send => function (request) {
|
|
847
|
+
if (!isEarlyFlakeDetectionEnabled) {
|
|
848
|
+
return send.apply(this, arguments)
|
|
849
|
+
}
|
|
850
|
+
const [type] = request
|
|
851
|
+
// eslint-disable-next-line
|
|
852
|
+
// https://github.com/jestjs/jest/blob/1d682f21c7a35da4d3ab3a1436a357b980ebd0fa/packages/jest-worker/src/workers/ChildProcessWorker.ts#L424
|
|
853
|
+
if (type === CHILD_MESSAGE_CALL) {
|
|
854
|
+
// This is the message that the main process sends to the worker to run a test suite (=test file).
|
|
855
|
+
// In here we modify the config.testEnvironmentOptions to include the known tests for the suite.
|
|
856
|
+
// This way the suite only knows about the tests that are part of it.
|
|
857
|
+
const args = request[request.length - 1]
|
|
858
|
+
if (args.length > 1) {
|
|
859
|
+
return send.apply(this, arguments)
|
|
860
|
+
}
|
|
861
|
+
if (!args[0]?.config) {
|
|
862
|
+
return send.apply(this, arguments)
|
|
863
|
+
}
|
|
864
|
+
const [{ globalConfig, config, path: testSuiteAbsolutePath }] = args
|
|
865
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, globalConfig.rootDir || process.cwd())
|
|
866
|
+
const suiteKnownTests = knownTests.jest?.[testSuite] || []
|
|
867
|
+
args[0].config = {
|
|
868
|
+
...config,
|
|
869
|
+
testEnvironmentOptions: {
|
|
870
|
+
...config.testEnvironmentOptions,
|
|
871
|
+
_ddKnownTests: suiteKnownTests
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
return send.apply(this, arguments)
|
|
877
|
+
})
|
|
798
878
|
shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', _onMessage => function () {
|
|
799
879
|
const [code, data] = arguments[0]
|
|
800
880
|
if (code === JEST_WORKER_TRACE_PAYLOAD_CODE) { // datadog trace payload
|
|
@@ -21,7 +21,7 @@ function finish (err) {
|
|
|
21
21
|
finishChannel.publish(undefined)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
addHook({ name: 'oracledb', versions: ['5'] }, oracledb => {
|
|
24
|
+
addHook({ name: 'oracledb', versions: ['>=5'] }, oracledb => {
|
|
25
25
|
shimmer.wrap(oracledb.Connection.prototype, 'execute', execute => {
|
|
26
26
|
return function wrappedExecute (dbQuery, ...args) {
|
|
27
27
|
if (!startChannel.hasSubscribers) {
|
|
@@ -20,11 +20,15 @@ const EXCLUDED_LOCATIONS = getNodeModulesPaths(
|
|
|
20
20
|
'pusher/lib/utils.js',
|
|
21
21
|
'redlock/dist/cjs',
|
|
22
22
|
'sqreen/lib/package-reader/index.js',
|
|
23
|
-
'ws/lib/websocket-server.js'
|
|
23
|
+
'ws/lib/websocket-server.js',
|
|
24
|
+
'google-gax/build/src/grpc.js',
|
|
25
|
+
'cookie-signature/index.js'
|
|
24
26
|
)
|
|
25
27
|
|
|
26
28
|
const EXCLUDED_PATHS_FROM_STACK = [
|
|
27
|
-
path.join('node_modules', 'object-hash', path.sep)
|
|
29
|
+
path.join('node_modules', 'object-hash', path.sep),
|
|
30
|
+
path.join('node_modules', 'aws-sdk', 'lib', 'util.js'),
|
|
31
|
+
path.join('node_modules', 'keygrip', path.sep)
|
|
28
32
|
]
|
|
29
33
|
class WeakHashAnalyzer extends Analyzer {
|
|
30
34
|
constructor () {
|
|
@@ -27,6 +27,7 @@ const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private
|
|
|
27
27
|
const defaultWafObfuscatorKeyRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?)key)|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization'
|
|
28
28
|
// eslint-disable-next-line max-len
|
|
29
29
|
const defaultWafObfuscatorValueRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}'
|
|
30
|
+
const runtimeId = uuid()
|
|
30
31
|
|
|
31
32
|
function maybeFile (filepath) {
|
|
32
33
|
if (!filepath) return
|
|
@@ -291,7 +292,7 @@ class Config {
|
|
|
291
292
|
service: this.service,
|
|
292
293
|
env: this.env,
|
|
293
294
|
version: this.version,
|
|
294
|
-
'runtime-id':
|
|
295
|
+
'runtime-id': runtimeId
|
|
295
296
|
})
|
|
296
297
|
|
|
297
298
|
if (this.isCiVisibility) {
|
|
@@ -823,6 +824,7 @@ class Config {
|
|
|
823
824
|
: undefined
|
|
824
825
|
|
|
825
826
|
tagger.add(tags, options.tracing_tags)
|
|
827
|
+
if (Object.keys(tags).length) tags['runtime-id'] = runtimeId
|
|
826
828
|
|
|
827
829
|
this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
|
|
828
830
|
this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
|