dd-trace 4.46.0 → 4.47.1
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 -0
- package/index.d.ts +20 -8
- package/package.json +9 -3
- package/packages/datadog-instrumentations/src/cucumber.js +290 -53
- package/packages/datadog-instrumentations/src/jest.js +3 -1
- package/packages/datadog-instrumentations/src/kafkajs.js +67 -31
- package/packages/datadog-instrumentations/src/microgateway-core.js +3 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +139 -54
- package/packages/datadog-instrumentations/src/mocha/utils.js +35 -15
- package/packages/datadog-instrumentations/src/mocha/worker.js +29 -1
- package/packages/datadog-instrumentations/src/openai.js +4 -2
- package/packages/datadog-instrumentations/src/pg.js +59 -4
- package/packages/datadog-instrumentations/src/vitest.js +184 -9
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +33 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +24 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +36 -6
- package/packages/datadog-plugin-cypress/src/support.js +4 -1
- package/packages/datadog-plugin-http/src/client.js +1 -42
- package/packages/datadog-plugin-http2/src/client.js +1 -26
- package/packages/datadog-plugin-jest/src/index.js +17 -1
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +20 -0
- package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -2
- package/packages/datadog-plugin-kafkajs/src/index.js +3 -1
- package/packages/datadog-plugin-mocha/src/index.js +18 -0
- package/packages/datadog-plugin-openai/src/index.js +27 -18
- package/packages/datadog-plugin-playwright/src/index.js +9 -0
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
- package/packages/datadog-plugin-vitest/src/index.js +68 -3
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/channels.js +4 -2
- package/packages/dd-trace/src/appsec/rasp/index.js +103 -0
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +86 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +37 -0
- package/packages/dd-trace/src/appsec/rasp/utils.js +63 -0
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +16 -7
- package/packages/dd-trace/src/appsec/remote_config/manager.js +89 -51
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +33 -14
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +2 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +13 -0
- package/packages/dd-trace/src/config.js +61 -10
- package/packages/dd-trace/src/constants.js +11 -1
- package/packages/dd-trace/src/data_streams_context.js +3 -0
- package/packages/dd-trace/src/datastreams/fnv.js +23 -0
- package/packages/dd-trace/src/datastreams/pathway.js +12 -5
- package/packages/dd-trace/src/datastreams/processor.js +35 -0
- package/packages/dd-trace/src/datastreams/schemas/schema.js +8 -0
- package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +125 -0
- package/packages/dd-trace/src/datastreams/schemas/schema_sampler.js +29 -0
- package/packages/dd-trace/src/debugger/devtools_client/config.js +24 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +57 -0
- package/packages/dd-trace/src/debugger/devtools_client/inspector_promises_polyfill.js +23 -0
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +164 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +28 -0
- package/packages/dd-trace/src/debugger/devtools_client/session.js +7 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +47 -0
- package/packages/dd-trace/src/debugger/devtools_client/status.js +109 -0
- package/packages/dd-trace/src/debugger/index.js +92 -0
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +29 -2
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/payload-tagging/config/aws.json +30 -0
- package/packages/dd-trace/src/payload-tagging/config/index.js +30 -0
- package/packages/dd-trace/src/payload-tagging/index.js +93 -0
- package/packages/dd-trace/src/payload-tagging/tagging.js +83 -0
- package/packages/dd-trace/src/plugin_manager.js +11 -10
- package/packages/dd-trace/src/plugins/ci_plugin.js +33 -8
- package/packages/dd-trace/src/plugins/util/env.js +5 -2
- package/packages/dd-trace/src/plugins/util/test.js +26 -2
- package/packages/dd-trace/src/profiling/config.js +5 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns.js +13 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookup.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookupservice.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_resolve.js +24 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_reverse.js +16 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +48 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/net.js +24 -0
- package/packages/dd-trace/src/profiling/profilers/events.js +108 -32
- package/packages/dd-trace/src/profiling/profilers/shared.js +5 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +9 -3
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +10 -2
- package/packages/dd-trace/src/proxy.js +10 -3
- package/packages/dd-trace/src/span_stats.js +4 -2
- package/packages/dd-trace/src/appsec/rasp.js +0 -176
|
@@ -404,7 +404,7 @@ addHook({
|
|
|
404
404
|
|
|
405
405
|
addHook({
|
|
406
406
|
name: '@jest/test-sequencer',
|
|
407
|
-
versions: ['>=
|
|
407
|
+
versions: ['>=28']
|
|
408
408
|
}, (sequencerPackage, frameworkVersion) => {
|
|
409
409
|
shimmer.wrap(sequencerPackage.default.prototype, 'shard', shard => function () {
|
|
410
410
|
const shardedTests = shard.apply(this, arguments)
|
|
@@ -648,6 +648,7 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
648
648
|
testSuiteStartCh.publish({
|
|
649
649
|
testSuite: environment.testSuite,
|
|
650
650
|
testEnvironmentOptions: environment.testEnvironmentOptions,
|
|
651
|
+
testSourceFile: environment.testSourceFile,
|
|
651
652
|
displayName: environment.displayName,
|
|
652
653
|
frameworkVersion: jestVersion
|
|
653
654
|
})
|
|
@@ -765,6 +766,7 @@ addHook({
|
|
|
765
766
|
_ddTestModuleId,
|
|
766
767
|
_ddTestSessionId,
|
|
767
768
|
_ddTestCommand,
|
|
769
|
+
_ddTestSessionName,
|
|
768
770
|
_ddForcedToRun,
|
|
769
771
|
_ddUnskippable,
|
|
770
772
|
_ddItrCorrelationId,
|
|
@@ -17,6 +17,10 @@ const consumerCommitCh = channel('apm:kafkajs:consume:commit')
|
|
|
17
17
|
const consumerFinishCh = channel('apm:kafkajs:consume:finish')
|
|
18
18
|
const consumerErrorCh = channel('apm:kafkajs:consume:error')
|
|
19
19
|
|
|
20
|
+
const batchConsumerStartCh = channel('apm:kafkajs:consume-batch:start')
|
|
21
|
+
const batchConsumerFinishCh = channel('apm:kafkajs:consume-batch:finish')
|
|
22
|
+
const batchConsumerErrorCh = channel('apm:kafkajs:consume-batch:error')
|
|
23
|
+
|
|
20
24
|
function commitsFromEvent (event) {
|
|
21
25
|
const { payload: { groupId, topics } } = event
|
|
22
26
|
const commitList = []
|
|
@@ -96,6 +100,17 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
96
100
|
return createConsumer.apply(this, arguments)
|
|
97
101
|
}
|
|
98
102
|
|
|
103
|
+
const eachMessageExtractor = (args) => {
|
|
104
|
+
const { topic, partition, message } = args[0]
|
|
105
|
+
return { topic, partition, message, groupId }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const eachBatchExtractor = (args) => {
|
|
109
|
+
const { batch } = args[0]
|
|
110
|
+
const { topic, partition, messages } = batch
|
|
111
|
+
return { topic, partition, messages, groupId }
|
|
112
|
+
}
|
|
113
|
+
|
|
99
114
|
const consumer = createConsumer.apply(this, arguments)
|
|
100
115
|
|
|
101
116
|
consumer.on(consumer.events.COMMIT_OFFSETS, commitsFromEvent)
|
|
@@ -103,43 +118,64 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
103
118
|
const run = consumer.run
|
|
104
119
|
|
|
105
120
|
const groupId = arguments[0].groupId
|
|
106
|
-
consumer.run = function ({ eachMessage, ...runArgs }) {
|
|
107
|
-
|
|
121
|
+
consumer.run = function ({ eachMessage, eachBatch, ...runArgs }) {
|
|
122
|
+
eachMessage = wrapFunction(
|
|
123
|
+
eachMessage,
|
|
124
|
+
consumerStartCh,
|
|
125
|
+
consumerFinishCh,
|
|
126
|
+
consumerErrorCh,
|
|
127
|
+
eachMessageExtractor
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
eachBatch = wrapFunction(
|
|
131
|
+
eachBatch,
|
|
132
|
+
batchConsumerStartCh,
|
|
133
|
+
batchConsumerFinishCh,
|
|
134
|
+
batchConsumerErrorCh,
|
|
135
|
+
eachBatchExtractor
|
|
136
|
+
)
|
|
108
137
|
|
|
109
138
|
return run({
|
|
110
|
-
eachMessage
|
|
111
|
-
|
|
112
|
-
return innerAsyncResource.runInAsyncScope(() => {
|
|
113
|
-
const { topic, partition, message } = eachMessageArgs[0]
|
|
114
|
-
consumerStartCh.publish({ topic, partition, message, groupId })
|
|
115
|
-
try {
|
|
116
|
-
const result = eachMessage.apply(this, eachMessageArgs)
|
|
117
|
-
if (result && typeof result.then === 'function') {
|
|
118
|
-
result.then(
|
|
119
|
-
innerAsyncResource.bind(() => consumerFinishCh.publish(undefined)),
|
|
120
|
-
innerAsyncResource.bind(err => {
|
|
121
|
-
if (err) {
|
|
122
|
-
consumerErrorCh.publish(err)
|
|
123
|
-
}
|
|
124
|
-
consumerFinishCh.publish(undefined)
|
|
125
|
-
})
|
|
126
|
-
)
|
|
127
|
-
} else {
|
|
128
|
-
consumerFinishCh.publish(undefined)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return result
|
|
132
|
-
} catch (e) {
|
|
133
|
-
consumerErrorCh.publish(e)
|
|
134
|
-
consumerFinishCh.publish(undefined)
|
|
135
|
-
throw e
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
},
|
|
139
|
+
eachMessage,
|
|
140
|
+
eachBatch,
|
|
139
141
|
...runArgs
|
|
140
142
|
})
|
|
141
143
|
}
|
|
144
|
+
|
|
142
145
|
return consumer
|
|
143
146
|
})
|
|
144
147
|
return Kafka
|
|
145
148
|
})
|
|
149
|
+
|
|
150
|
+
const wrapFunction = (fn, startCh, finishCh, errorCh, extractArgs) => {
|
|
151
|
+
return typeof fn === 'function'
|
|
152
|
+
? function (...args) {
|
|
153
|
+
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
154
|
+
return innerAsyncResource.runInAsyncScope(() => {
|
|
155
|
+
const extractedArgs = extractArgs(args)
|
|
156
|
+
startCh.publish(extractedArgs)
|
|
157
|
+
try {
|
|
158
|
+
const result = fn.apply(this, args)
|
|
159
|
+
if (result && typeof result.then === 'function') {
|
|
160
|
+
result.then(
|
|
161
|
+
innerAsyncResource.bind(() => finishCh.publish(undefined)),
|
|
162
|
+
innerAsyncResource.bind(err => {
|
|
163
|
+
if (err) {
|
|
164
|
+
errorCh.publish(err)
|
|
165
|
+
}
|
|
166
|
+
finishCh.publish(undefined)
|
|
167
|
+
})
|
|
168
|
+
)
|
|
169
|
+
} else {
|
|
170
|
+
finishCh.publish(undefined)
|
|
171
|
+
}
|
|
172
|
+
return result
|
|
173
|
+
} catch (e) {
|
|
174
|
+
errorCh.publish(e)
|
|
175
|
+
finishCh.publish(undefined)
|
|
176
|
+
throw e
|
|
177
|
+
}
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
: fn
|
|
181
|
+
}
|
|
@@ -8,7 +8,9 @@ const routeChannel = channel('apm:microgateway-core:request:route')
|
|
|
8
8
|
const errorChannel = channel('apm:microgateway-core:request:error')
|
|
9
9
|
|
|
10
10
|
const name = 'microgateway-core'
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// TODO Remove " <=3.0.0" when "volos-util-apigee" module is fixed
|
|
13
|
+
const versions = ['>=2.1 <=3.0.0']
|
|
12
14
|
const requestResources = new WeakMap()
|
|
13
15
|
|
|
14
16
|
function wrapConfigProxyFactory (configProxyFactory) {
|
|
@@ -11,12 +11,12 @@ const {
|
|
|
11
11
|
fromCoverageMapToCoverage,
|
|
12
12
|
getCoveredFilenamesFromCoverage,
|
|
13
13
|
mergeCoverage,
|
|
14
|
-
resetCoverage
|
|
14
|
+
resetCoverage,
|
|
15
|
+
getIsFaultyEarlyFlakeDetection
|
|
15
16
|
} = require('../../../dd-trace/src/plugins/util/test')
|
|
16
17
|
|
|
17
18
|
const {
|
|
18
19
|
isNewTest,
|
|
19
|
-
retryTest,
|
|
20
20
|
getSuitesByTestFile,
|
|
21
21
|
runnableWrapper,
|
|
22
22
|
getOnTestHandler,
|
|
@@ -25,22 +25,21 @@ const {
|
|
|
25
25
|
getOnHookEndHandler,
|
|
26
26
|
getOnFailHandler,
|
|
27
27
|
getOnPendingHandler,
|
|
28
|
-
testFileToSuiteAr
|
|
28
|
+
testFileToSuiteAr,
|
|
29
|
+
newTests,
|
|
30
|
+
getTestFullName,
|
|
31
|
+
getRunTestsWrapper
|
|
29
32
|
} = require('./utils')
|
|
33
|
+
|
|
30
34
|
require('./common')
|
|
31
35
|
|
|
32
36
|
const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
33
37
|
const patched = new WeakSet()
|
|
34
|
-
|
|
35
|
-
let suitesToSkip = []
|
|
38
|
+
|
|
36
39
|
const unskippableSuites = []
|
|
40
|
+
let suitesToSkip = []
|
|
37
41
|
let isSuitesSkipped = false
|
|
38
42
|
let skippedSuites = []
|
|
39
|
-
let isEarlyFlakeDetectionEnabled = false
|
|
40
|
-
let isSuitesSkippingEnabled = false
|
|
41
|
-
let isFlakyTestRetriesEnabled = false
|
|
42
|
-
let earlyFlakeDetectionNumRetries = 0
|
|
43
|
-
let knownTests = []
|
|
44
43
|
let itrCorrelationId = ''
|
|
45
44
|
let isForcedToRun = false
|
|
46
45
|
const config = {}
|
|
@@ -69,6 +68,17 @@ const itrSkippedSuitesCh = channel('ci:mocha:itr:skipped-suites')
|
|
|
69
68
|
|
|
70
69
|
const getCodeCoverageCh = channel('ci:nyc:get-coverage')
|
|
71
70
|
|
|
71
|
+
// Tests from workers do not come with `isFailed` method
|
|
72
|
+
function isTestFailed (test) {
|
|
73
|
+
if (test.isFailed) {
|
|
74
|
+
return test.isFailed()
|
|
75
|
+
}
|
|
76
|
+
if (test.isPending) {
|
|
77
|
+
return !test.isPending() && test.state !== 'failed'
|
|
78
|
+
}
|
|
79
|
+
return false
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
function getFilteredSuites (originalSuites) {
|
|
73
83
|
return originalSuites.reduce((acc, suite) => {
|
|
74
84
|
const testPath = getTestSuitePath(suite.file, process.cwd())
|
|
@@ -107,7 +117,7 @@ function getOnEndHandler (isParallel) {
|
|
|
107
117
|
status = 'fail'
|
|
108
118
|
}
|
|
109
119
|
|
|
110
|
-
if (
|
|
120
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
111
121
|
/**
|
|
112
122
|
* If Early Flake Detection (EFD) is enabled the logic is as follows:
|
|
113
123
|
* - If all attempts for a test are failing, the test has failed and we will let the test process fail.
|
|
@@ -116,7 +126,7 @@ function getOnEndHandler (isParallel) {
|
|
|
116
126
|
* on flakiness (the test will be considered flaky), but you may choose to unblock the pipeline too.
|
|
117
127
|
*/
|
|
118
128
|
for (const tests of Object.values(newTests)) {
|
|
119
|
-
const failingNewTests = tests.filter(test => test
|
|
129
|
+
const failingNewTests = tests.filter(test => isTestFailed(test))
|
|
120
130
|
const areAllNewTestsFailing = failingNewTests.length === tests.length
|
|
121
131
|
if (failingNewTests.length && !areAllNewTestsFailing) {
|
|
122
132
|
this.stats.failures -= failingNewTests.length
|
|
@@ -153,13 +163,14 @@ function getOnEndHandler (isParallel) {
|
|
|
153
163
|
hasForcedToRunSuites: isForcedToRun,
|
|
154
164
|
hasUnskippableSuites: !!unskippableSuites.length,
|
|
155
165
|
error,
|
|
156
|
-
isEarlyFlakeDetectionEnabled,
|
|
166
|
+
isEarlyFlakeDetectionEnabled: config.isEarlyFlakeDetectionEnabled,
|
|
167
|
+
isEarlyFlakeDetectionFaulty: config.isEarlyFlakeDetectionFaulty,
|
|
157
168
|
isParallel
|
|
158
169
|
})
|
|
159
170
|
})
|
|
160
171
|
}
|
|
161
172
|
|
|
162
|
-
function getExecutionConfiguration (runner, onFinishRequest) {
|
|
173
|
+
function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
|
|
163
174
|
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
164
175
|
|
|
165
176
|
const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
|
|
@@ -186,15 +197,15 @@ function getExecutionConfiguration (runner, onFinishRequest) {
|
|
|
186
197
|
onFinishRequest()
|
|
187
198
|
}
|
|
188
199
|
|
|
189
|
-
const onReceivedKnownTests = ({ err, knownTests
|
|
200
|
+
const onReceivedKnownTests = ({ err, knownTests }) => {
|
|
190
201
|
if (err) {
|
|
191
|
-
knownTests = []
|
|
192
|
-
isEarlyFlakeDetectionEnabled = false
|
|
202
|
+
config.knownTests = []
|
|
203
|
+
config.isEarlyFlakeDetectionEnabled = false
|
|
193
204
|
} else {
|
|
194
|
-
knownTests =
|
|
205
|
+
config.knownTests = knownTests
|
|
195
206
|
}
|
|
196
207
|
|
|
197
|
-
if (isSuitesSkippingEnabled) {
|
|
208
|
+
if (config.isSuitesSkippingEnabled) {
|
|
198
209
|
skippableSuitesCh.publish({
|
|
199
210
|
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
200
211
|
})
|
|
@@ -208,22 +219,19 @@ function getExecutionConfiguration (runner, onFinishRequest) {
|
|
|
208
219
|
return onFinishRequest()
|
|
209
220
|
}
|
|
210
221
|
|
|
211
|
-
isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
config.
|
|
217
|
-
config.
|
|
218
|
-
config.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
|
|
219
|
-
config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
|
|
220
|
-
config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
|
|
222
|
+
config.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
223
|
+
config.earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
224
|
+
config.earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
|
|
225
|
+
// ITR and auto test retries are not supported in parallel mode yet
|
|
226
|
+
config.isSuitesSkippingEnabled = !isParallel && libraryConfig.isSuitesSkippingEnabled
|
|
227
|
+
config.isFlakyTestRetriesEnabled = !isParallel && libraryConfig.isFlakyTestRetriesEnabled
|
|
228
|
+
config.flakyTestRetriesCount = !isParallel && libraryConfig.flakyTestRetriesCount
|
|
221
229
|
|
|
222
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
230
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
223
231
|
knownTestsCh.publish({
|
|
224
232
|
onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
|
|
225
233
|
})
|
|
226
|
-
} else if (isSuitesSkippingEnabled) {
|
|
234
|
+
} else if (config.isSuitesSkippingEnabled) {
|
|
227
235
|
skippableSuitesCh.publish({
|
|
228
236
|
onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
|
|
229
237
|
})
|
|
@@ -251,8 +259,8 @@ addHook({
|
|
|
251
259
|
return run.apply(this, arguments)
|
|
252
260
|
}
|
|
253
261
|
|
|
254
|
-
// `options.delay` does not work in parallel mode, so
|
|
255
|
-
//
|
|
262
|
+
// `options.delay` does not work in parallel mode, so we can't delay the execution this way
|
|
263
|
+
// This needs to be both here and in `runMocha` hook. Read the comment in `runMocha` hook for more info.
|
|
256
264
|
this.options.delay = true
|
|
257
265
|
|
|
258
266
|
const runner = run.apply(this, arguments)
|
|
@@ -264,7 +272,19 @@ addHook({
|
|
|
264
272
|
}
|
|
265
273
|
})
|
|
266
274
|
|
|
267
|
-
getExecutionConfiguration(runner, () => {
|
|
275
|
+
getExecutionConfiguration(runner, false, () => {
|
|
276
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
277
|
+
const testSuites = this.files.map(file => getTestSuitePath(file, process.cwd()))
|
|
278
|
+
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
279
|
+
testSuites,
|
|
280
|
+
config.knownTests?.mocha || {},
|
|
281
|
+
config.earlyFlakeDetectionFaultyThreshold
|
|
282
|
+
)
|
|
283
|
+
if (isFaulty) {
|
|
284
|
+
config.isEarlyFlakeDetectionEnabled = false
|
|
285
|
+
config.isEarlyFlakeDetectionFaulty = true
|
|
286
|
+
}
|
|
287
|
+
}
|
|
268
288
|
if (getCodeCoverageCh.hasSubscribers) {
|
|
269
289
|
getCodeCoverageCh.publish({
|
|
270
290
|
onDone: (receivedCodeCoverage) => {
|
|
@@ -282,9 +302,6 @@ addHook({
|
|
|
282
302
|
return Mocha
|
|
283
303
|
})
|
|
284
304
|
|
|
285
|
-
// Only used to set `mocha.options.delay` to true in serial mode. When the mocha CLI is used,
|
|
286
|
-
// setting options.delay in Mocha#run is not enough to delay the execution.
|
|
287
|
-
// TODO: modify this hook to grab the data in parallel mode, so that ITR and EFD can work.
|
|
288
305
|
addHook({
|
|
289
306
|
name: 'mocha',
|
|
290
307
|
versions: ['>=5.2.0'],
|
|
@@ -294,15 +311,20 @@ addHook({
|
|
|
294
311
|
if (!testStartCh.hasSubscribers) {
|
|
295
312
|
return runMocha.apply(this, arguments)
|
|
296
313
|
}
|
|
297
|
-
|
|
298
314
|
const mocha = arguments[0]
|
|
315
|
+
|
|
299
316
|
/**
|
|
300
317
|
* This attaches `run` to the global context, which we'll call after
|
|
301
|
-
* our configuration and skippable suites requests
|
|
318
|
+
* our configuration and skippable suites requests.
|
|
319
|
+
* You need this both here and in Mocha#run hook: the programmatic API
|
|
320
|
+
* does not call `runMocha`, so it needs to be in Mocha#run. When using
|
|
321
|
+
* the CLI, modifying `options.delay` in Mocha#run is not enough (it's too late),
|
|
322
|
+
* so it also needs to be here.
|
|
302
323
|
*/
|
|
303
324
|
if (!mocha.options.parallel) {
|
|
304
325
|
mocha.options.delay = true
|
|
305
326
|
}
|
|
327
|
+
|
|
306
328
|
return runMocha.apply(this, arguments)
|
|
307
329
|
})
|
|
308
330
|
return run
|
|
@@ -319,18 +341,7 @@ addHook({
|
|
|
319
341
|
|
|
320
342
|
patched.add(Runner)
|
|
321
343
|
|
|
322
|
-
shimmer.wrap(Runner.prototype, 'runTests', runTests =>
|
|
323
|
-
if (isEarlyFlakeDetectionEnabled) {
|
|
324
|
-
// by the time we reach `this.on('test')`, it is too late. We need to add retries here
|
|
325
|
-
suite.tests.forEach(test => {
|
|
326
|
-
if (!test.isPending() && isNewTest(test, knownTests)) {
|
|
327
|
-
test._ddIsNew = true
|
|
328
|
-
retryTest(test, earlyFlakeDetectionNumRetries)
|
|
329
|
-
}
|
|
330
|
-
})
|
|
331
|
-
}
|
|
332
|
-
return runTests.apply(this, arguments)
|
|
333
|
-
})
|
|
344
|
+
shimmer.wrap(Runner.prototype, 'runTests', runTests => getRunTestsWrapper(runTests, config))
|
|
334
345
|
|
|
335
346
|
shimmer.wrap(Runner.prototype, 'run', run => function () {
|
|
336
347
|
if (!testStartCh.hasSubscribers) {
|
|
@@ -514,10 +525,10 @@ addHook({
|
|
|
514
525
|
// Used to start and finish test session and test module
|
|
515
526
|
addHook({
|
|
516
527
|
name: 'mocha',
|
|
517
|
-
versions: ['>=
|
|
528
|
+
versions: ['>=8.0.0'],
|
|
518
529
|
file: 'lib/nodejs/parallel-buffered-runner.js'
|
|
519
530
|
}, (ParallelBufferedRunner, frameworkVersion) => {
|
|
520
|
-
shimmer.wrap(ParallelBufferedRunner.prototype, 'run', run => function () {
|
|
531
|
+
shimmer.wrap(ParallelBufferedRunner.prototype, 'run', run => function (cb, { files }) {
|
|
521
532
|
if (!testStartCh.hasSubscribers) {
|
|
522
533
|
return run.apply(this, arguments)
|
|
523
534
|
}
|
|
@@ -525,8 +536,82 @@ addHook({
|
|
|
525
536
|
this.once('start', getOnStartHandler(true, frameworkVersion))
|
|
526
537
|
this.once('end', getOnEndHandler(true))
|
|
527
538
|
|
|
528
|
-
|
|
539
|
+
getExecutionConfiguration(this, true, () => {
|
|
540
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
541
|
+
const testSuites = files.map(file => getTestSuitePath(file, process.cwd()))
|
|
542
|
+
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
543
|
+
testSuites,
|
|
544
|
+
config.knownTests?.mocha || {},
|
|
545
|
+
config.earlyFlakeDetectionFaultyThreshold
|
|
546
|
+
)
|
|
547
|
+
if (isFaulty) {
|
|
548
|
+
config.isEarlyFlakeDetectionEnabled = false
|
|
549
|
+
config.isEarlyFlakeDetectionFaulty = true
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
run.apply(this, arguments)
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
return this
|
|
529
556
|
})
|
|
530
557
|
|
|
531
558
|
return ParallelBufferedRunner
|
|
532
559
|
})
|
|
560
|
+
|
|
561
|
+
// Only in parallel mode: BufferedWorkerPool#run is used to run a test file in a worker
|
|
562
|
+
// If Early Flake Detection is enabled,
|
|
563
|
+
// In this hook we pass the known tests to the worker and collect the new tests that run
|
|
564
|
+
addHook({
|
|
565
|
+
name: 'mocha',
|
|
566
|
+
versions: ['>=8.0.0'],
|
|
567
|
+
file: 'lib/nodejs/buffered-worker-pool.js'
|
|
568
|
+
}, (BufferedWorkerPoolPackage) => {
|
|
569
|
+
const { BufferedWorkerPool } = BufferedWorkerPoolPackage
|
|
570
|
+
|
|
571
|
+
shimmer.wrap(BufferedWorkerPool.prototype, 'run', run => async function (testSuiteAbsolutePath, workerArgs) {
|
|
572
|
+
if (!testStartCh.hasSubscribers || !config.isEarlyFlakeDetectionEnabled) {
|
|
573
|
+
return run.apply(this, arguments)
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const testPath = getTestSuitePath(testSuiteAbsolutePath, process.cwd())
|
|
577
|
+
const testSuiteKnownTests = config.knownTests.mocha?.[testPath] || []
|
|
578
|
+
|
|
579
|
+
// We pass the known tests for the test file to the worker
|
|
580
|
+
const testFileResult = await run.apply(
|
|
581
|
+
this,
|
|
582
|
+
[
|
|
583
|
+
testSuiteAbsolutePath,
|
|
584
|
+
{
|
|
585
|
+
...workerArgs,
|
|
586
|
+
_ddEfdNumRetries: config.earlyFlakeDetectionNumRetries,
|
|
587
|
+
_ddKnownTests: {
|
|
588
|
+
mocha: {
|
|
589
|
+
[testPath]: testSuiteKnownTests
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
]
|
|
594
|
+
)
|
|
595
|
+
const tests = testFileResult
|
|
596
|
+
.events
|
|
597
|
+
.filter(event => event.eventName === 'test end')
|
|
598
|
+
.map(event => event.data)
|
|
599
|
+
|
|
600
|
+
// `newTests` is filled in the worker process, so we need to use the test results to fill it here too.
|
|
601
|
+
for (const test of tests) {
|
|
602
|
+
if (isNewTest(test, config.knownTests)) {
|
|
603
|
+
const testFullName = getTestFullName(test)
|
|
604
|
+
const tests = newTests[testFullName]
|
|
605
|
+
|
|
606
|
+
if (!tests) {
|
|
607
|
+
newTests[testFullName] = [test]
|
|
608
|
+
} else {
|
|
609
|
+
tests.push(test)
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return testFileResult
|
|
614
|
+
})
|
|
615
|
+
|
|
616
|
+
return BufferedWorkerPoolPackage
|
|
617
|
+
})
|
|
@@ -24,6 +24,7 @@ const originalFns = new WeakMap()
|
|
|
24
24
|
const testToStartLine = new WeakMap()
|
|
25
25
|
const testFileToSuiteAr = new Map()
|
|
26
26
|
const wrappedFunctions = new WeakSet()
|
|
27
|
+
const newTests = {}
|
|
27
28
|
|
|
28
29
|
function isNewTest (test, knownTests) {
|
|
29
30
|
const testSuite = getTestSuitePath(test.file, process.cwd())
|
|
@@ -151,7 +152,7 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
|
|
|
151
152
|
return RunnablePackage
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
function getOnTestHandler (isMain
|
|
155
|
+
function getOnTestHandler (isMain) {
|
|
155
156
|
return function (test) {
|
|
156
157
|
const testStartLine = testToStartLine.get(test)
|
|
157
158
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
@@ -179,22 +180,22 @@ function getOnTestHandler (isMain, newTests) {
|
|
|
179
180
|
testStartLine
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
if (isMain) {
|
|
183
|
-
testInfo.isNew = isNew
|
|
184
|
-
testInfo.isEfdRetry = isEfdRetry
|
|
185
|
-
// We want to store the result of the new tests
|
|
186
|
-
if (isNew) {
|
|
187
|
-
const testFullName = getTestFullName(test)
|
|
188
|
-
if (newTests[testFullName]) {
|
|
189
|
-
newTests[testFullName].push(test)
|
|
190
|
-
} else {
|
|
191
|
-
newTests[testFullName] = [test]
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
} else {
|
|
183
|
+
if (!isMain) {
|
|
195
184
|
testInfo.isParallel = true
|
|
196
185
|
}
|
|
197
186
|
|
|
187
|
+
testInfo.isNew = isNew
|
|
188
|
+
testInfo.isEfdRetry = isEfdRetry
|
|
189
|
+
// We want to store the result of the new tests
|
|
190
|
+
if (isNew) {
|
|
191
|
+
const testFullName = getTestFullName(test)
|
|
192
|
+
if (newTests[testFullName]) {
|
|
193
|
+
newTests[testFullName].push(test)
|
|
194
|
+
} else {
|
|
195
|
+
newTests[testFullName] = [test]
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
198
199
|
asyncResource.runInAsyncScope(() => {
|
|
199
200
|
testStartCh.publish(testInfo)
|
|
200
201
|
})
|
|
@@ -327,6 +328,23 @@ function getOnPendingHandler () {
|
|
|
327
328
|
}
|
|
328
329
|
}
|
|
329
330
|
}
|
|
331
|
+
|
|
332
|
+
// Hook to add retries to tests if EFD is enabled
|
|
333
|
+
function getRunTestsWrapper (runTests, config) {
|
|
334
|
+
return function (suite, fn) {
|
|
335
|
+
if (config.isEarlyFlakeDetectionEnabled) {
|
|
336
|
+
// by the time we reach `this.on('test')`, it is too late. We need to add retries here
|
|
337
|
+
suite.tests.forEach(test => {
|
|
338
|
+
if (!test.isPending() && isNewTest(test, config.knownTests)) {
|
|
339
|
+
test._ddIsNew = true
|
|
340
|
+
retryTest(test, config.earlyFlakeDetectionNumRetries)
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
return runTests.apply(this, arguments)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
330
348
|
module.exports = {
|
|
331
349
|
isNewTest,
|
|
332
350
|
retryTest,
|
|
@@ -345,5 +363,7 @@ module.exports = {
|
|
|
345
363
|
getOnHookEndHandler,
|
|
346
364
|
getOnFailHandler,
|
|
347
365
|
getOnPendingHandler,
|
|
348
|
-
testFileToSuiteAr
|
|
366
|
+
testFileToSuiteAr,
|
|
367
|
+
getRunTestsWrapper,
|
|
368
|
+
newTests
|
|
349
369
|
}
|
|
@@ -9,19 +9,47 @@ const {
|
|
|
9
9
|
getOnTestEndHandler,
|
|
10
10
|
getOnHookEndHandler,
|
|
11
11
|
getOnFailHandler,
|
|
12
|
-
getOnPendingHandler
|
|
12
|
+
getOnPendingHandler,
|
|
13
|
+
getRunTestsWrapper
|
|
13
14
|
} = require('./utils')
|
|
14
15
|
require('./common')
|
|
15
16
|
|
|
16
17
|
const workerFinishCh = channel('ci:mocha:worker:finish')
|
|
17
18
|
|
|
19
|
+
const config = {}
|
|
20
|
+
|
|
21
|
+
addHook({
|
|
22
|
+
name: 'mocha',
|
|
23
|
+
versions: ['>=8.0.0'],
|
|
24
|
+
file: 'lib/mocha.js'
|
|
25
|
+
}, (Mocha) => {
|
|
26
|
+
shimmer.wrap(Mocha.prototype, 'run', run => function () {
|
|
27
|
+
if (this.options._ddKnownTests) {
|
|
28
|
+
// EFD is enabled if there's a list of known tests
|
|
29
|
+
config.isEarlyFlakeDetectionEnabled = true
|
|
30
|
+
config.knownTests = this.options._ddKnownTests
|
|
31
|
+
config.earlyFlakeDetectionNumRetries = this.options._ddEfdNumRetries
|
|
32
|
+
delete this.options._ddKnownTests
|
|
33
|
+
delete this.options._ddEfdNumRetries
|
|
34
|
+
}
|
|
35
|
+
return run.apply(this, arguments)
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
return Mocha
|
|
39
|
+
})
|
|
40
|
+
|
|
18
41
|
// Runner is also hooked in mocha/main.js, but in here we only generate test events.
|
|
19
42
|
addHook({
|
|
20
43
|
name: 'mocha',
|
|
21
44
|
versions: ['>=5.2.0'],
|
|
22
45
|
file: 'lib/runner.js'
|
|
23
46
|
}, function (Runner) {
|
|
47
|
+
shimmer.wrap(Runner.prototype, 'runTests', runTests => getRunTestsWrapper(runTests, config))
|
|
48
|
+
|
|
24
49
|
shimmer.wrap(Runner.prototype, 'run', run => function () {
|
|
50
|
+
if (!workerFinishCh.hasSubscribers) {
|
|
51
|
+
return run.apply(this, arguments)
|
|
52
|
+
}
|
|
25
53
|
// We flush when the worker ends with its test file (a mocha instance in a worker runs a single test file)
|
|
26
54
|
this.on('end', () => {
|
|
27
55
|
workerFinishCh.publish()
|
|
@@ -165,10 +165,12 @@ function addStreamedChunk (content, chunk) {
|
|
|
165
165
|
|
|
166
166
|
if (tools) {
|
|
167
167
|
oldChoice.delta.tool_calls = tools.map((newTool, toolIdx) => {
|
|
168
|
-
const oldTool = oldChoice.delta.tool_calls[toolIdx]
|
|
168
|
+
const oldTool = oldChoice.delta.tool_calls?.[toolIdx]
|
|
169
169
|
|
|
170
170
|
if (oldTool) {
|
|
171
171
|
oldTool.function.arguments += newTool.function.arguments
|
|
172
|
+
} else {
|
|
173
|
+
return newTool
|
|
172
174
|
}
|
|
173
175
|
|
|
174
176
|
return oldTool
|
|
@@ -247,7 +249,7 @@ function wrapStreamIterator (response, options, n, ctx) {
|
|
|
247
249
|
return res
|
|
248
250
|
})
|
|
249
251
|
.catch(err => {
|
|
250
|
-
finish(undefined, err)
|
|
252
|
+
finish(ctx, undefined, err)
|
|
251
253
|
|
|
252
254
|
throw err
|
|
253
255
|
})
|