dd-trace 5.104.0 → 5.105.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 +90 -102
- package/index.d.ts +82 -3
- package/package.json +15 -15
- package/packages/datadog-core/src/storage.js +1 -1
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/ai.js +8 -7
- package/packages/datadog-instrumentations/src/aws-sdk.js +13 -0
- package/packages/datadog-instrumentations/src/azure-cosmos.js +7 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +3 -0
- package/packages/datadog-instrumentations/src/cucumber.js +78 -5
- package/packages/datadog-instrumentations/src/dns.js +54 -18
- package/packages/datadog-instrumentations/src/fastify.js +142 -82
- package/packages/datadog-instrumentations/src/graphql.js +188 -62
- package/packages/datadog-instrumentations/src/helpers/ai-messages.js +322 -14
- package/packages/datadog-instrumentations/src/helpers/hooks.js +4 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +269 -0
- package/packages/datadog-instrumentations/src/helpers/promise-instrumentor.js +42 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -3
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/azure-cosmos.js +50 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/langgraph.js +4 -2
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/playwright.js +85 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +37 -236
- package/packages/datadog-instrumentations/src/hono.js +54 -3
- package/packages/datadog-instrumentations/src/http/server.js +9 -4
- package/packages/datadog-instrumentations/src/jest/coverage-backfill.js +163 -0
- package/packages/datadog-instrumentations/src/jest.js +360 -150
- package/packages/datadog-instrumentations/src/kafkajs.js +120 -16
- package/packages/datadog-instrumentations/src/mocha/main.js +128 -17
- package/packages/datadog-instrumentations/src/nats.js +182 -0
- package/packages/datadog-instrumentations/src/nyc.js +38 -1
- package/packages/datadog-instrumentations/src/openai.js +33 -18
- package/packages/datadog-instrumentations/src/oracledb.js +6 -1
- package/packages/datadog-instrumentations/src/pino.js +17 -5
- package/packages/datadog-instrumentations/src/playwright.js +515 -292
- package/packages/datadog-instrumentations/src/router.js +76 -32
- package/packages/datadog-instrumentations/src/stripe.js +1 -1
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-azure-cosmos/src/index.js +144 -0
- package/packages/datadog-plugin-azure-event-hubs/src/producer.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -2
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +1 -1
- package/packages/datadog-plugin-bunyan/src/index.js +28 -0
- package/packages/datadog-plugin-cucumber/src/index.js +17 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +199 -28
- package/packages/datadog-plugin-cypress/src/support.js +69 -1
- package/packages/datadog-plugin-dns/src/lookup.js +8 -6
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +1 -1
- package/packages/datadog-plugin-graphql/src/execute.js +2 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +64 -67
- package/packages/datadog-plugin-http/src/server.js +40 -15
- package/packages/datadog-plugin-jest/src/index.js +11 -3
- package/packages/datadog-plugin-jest/src/util.js +15 -8
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -0
- package/packages/datadog-plugin-langgraph/src/stream.js +1 -1
- package/packages/datadog-plugin-mocha/src/index.js +19 -4
- package/packages/datadog-plugin-mongodb-core/src/index.js +281 -40
- package/packages/datadog-plugin-nats/src/consumer.js +43 -0
- package/packages/datadog-plugin-nats/src/index.js +20 -0
- package/packages/datadog-plugin-nats/src/producer.js +62 -0
- package/packages/datadog-plugin-nats/src/util.js +33 -0
- package/packages/datadog-plugin-next/src/index.js +5 -3
- package/packages/datadog-plugin-openai/src/tracing.js +15 -2
- package/packages/datadog-plugin-oracledb/src/index.js +13 -2
- package/packages/datadog-plugin-pino/src/index.js +42 -0
- package/packages/datadog-plugin-playwright/src/index.js +4 -4
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +33 -44
- package/packages/datadog-plugin-selenium/src/index.js +1 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -13
- package/packages/datadog-plugin-winston/src/index.js +30 -0
- package/packages/datadog-shimmer/src/shimmer.js +33 -40
- package/packages/dd-trace/src/aiguard/index.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +1 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +5 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/utils.js +1 -1
- package/packages/dd-trace/src/appsec/user_tracking.js +5 -4
- package/packages/dd-trace/src/baggage.js +7 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +0 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +25 -13
- package/packages/dd-trace/src/ci-visibility/test-optimization-cache.js +70 -6
- package/packages/dd-trace/src/config/generated-config-types.d.ts +6 -2
- package/packages/dd-trace/src/config/supported-configurations.json +27 -8
- package/packages/dd-trace/src/datastreams/writer.js +2 -4
- package/packages/dd-trace/src/debugger/devtools_client/condition.js +5 -8
- package/packages/dd-trace/src/encode/0.4.js +124 -108
- package/packages/dd-trace/src/encode/0.5.js +114 -26
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +31 -23
- package/packages/dd-trace/src/encode/agentless-json.js +4 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -13
- package/packages/dd-trace/src/encode/span-stats.js +16 -16
- package/packages/dd-trace/src/encode/tags-processors.js +16 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/genai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +9 -7
- package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -1
- package/packages/dd-trace/src/llmobs/plugins/openai/index.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +0 -16
- package/packages/dd-trace/src/llmobs/span_processor.js +3 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -1
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -1
- package/packages/dd-trace/src/llmobs/util.js +66 -3
- package/packages/dd-trace/src/log/index.js +1 -1
- package/packages/dd-trace/src/msgpack/chunk.js +394 -10
- package/packages/dd-trace/src/msgpack/index.js +96 -2
- package/packages/dd-trace/src/openfeature/encoding.js +70 -0
- package/packages/dd-trace/src/openfeature/flagging_provider.js +20 -0
- package/packages/dd-trace/src/openfeature/span-enrichment-hook.js +143 -0
- package/packages/dd-trace/src/openfeature/span-enrichment.js +149 -0
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +4 -3
- package/packages/dd-trace/src/opentelemetry/span.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/log.js +18 -7
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +62 -67
- package/packages/dd-trace/src/opentracing/span.js +59 -19
- package/packages/dd-trace/src/opentracing/span_context.js +49 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +20 -20
- package/packages/dd-trace/src/plugins/database.js +7 -6
- package/packages/dd-trace/src/plugins/index.js +4 -0
- package/packages/dd-trace/src/plugins/log_injection.js +56 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -48
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +15 -17
- package/packages/dd-trace/src/plugins/tracing.js +43 -5
- package/packages/dd-trace/src/plugins/util/test.js +236 -13
- package/packages/dd-trace/src/plugins/util/web.js +79 -65
- package/packages/dd-trace/src/priority_sampler.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +2 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +10 -4
- package/packages/dd-trace/src/sampling_rule.js +7 -7
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +10 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +8 -0
- package/packages/dd-trace/src/service-naming/source-resolver.js +46 -0
- package/packages/dd-trace/src/span_format.js +190 -58
- package/packages/dd-trace/src/spanleak.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -3
- package/packages/dd-trace/src/tagger.js +0 -2
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +70 -39
- package/vendor/dist/@datadog/sketches-js/LICENSE +10 -36
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/dd-trace/src/msgpack/encoder.js +0 -308
- package/packages/dd-trace/src/plugins/structured_log_plugin.js +0 -9
|
@@ -62,6 +62,7 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
62
62
|
shimmer.wrap(Kafka.prototype, 'producer', createProducer => function () {
|
|
63
63
|
const producer = createProducer.apply(this, arguments)
|
|
64
64
|
const originalSend = producer.send
|
|
65
|
+
const originalSendBatch = producer.sendBatch
|
|
65
66
|
const bootstrapServers = this._brokers
|
|
66
67
|
const cluster = clientToCluster.get(producer)
|
|
67
68
|
|
|
@@ -75,35 +76,46 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Resolve the negotiated clusterId once and hand it to `call`. Fast path reads
|
|
81
|
+
* `cluster.brokerPool.metadata` synchronously when kafkajs already fetched it.
|
|
82
|
+
* Slow path primes `refreshMetadataIfNecessary`, which `sharedPromiseTo`
|
|
83
|
+
* deduplicates with kafkajs's own internal fetch so total latency is unchanged.
|
|
84
|
+
*
|
|
85
|
+
* @param {(clusterId: string | undefined) => Promise<unknown>} call
|
|
86
|
+
*/
|
|
87
|
+
const withClusterId = (call) => {
|
|
85
88
|
const metadata = cluster?.brokerPool?.metadata
|
|
86
89
|
if (metadata) {
|
|
87
90
|
refreshHeaderSupport()
|
|
88
|
-
return
|
|
91
|
+
return call(metadata.clusterId)
|
|
89
92
|
}
|
|
90
|
-
|
|
91
|
-
// Slow path, taken at most once per producer connect cycle. Prime the
|
|
92
|
-
// metadata fetch kafkajs's send would do internally a few stack frames
|
|
93
|
-
// later. `sharedPromiseTo` collapses our call and kafkajs's call into a
|
|
94
|
-
// single round trip, so total latency is unchanged.
|
|
95
93
|
if (typeof cluster?.refreshMetadataIfNecessary !== 'function') {
|
|
96
|
-
return
|
|
94
|
+
return call()
|
|
97
95
|
}
|
|
98
96
|
return cluster.refreshMetadataIfNecessary().then(
|
|
99
97
|
() => {
|
|
100
98
|
refreshHeaderSupport()
|
|
101
|
-
return
|
|
99
|
+
return call(cluster.brokerPool?.metadata?.clusterId)
|
|
102
100
|
},
|
|
103
|
-
() =>
|
|
101
|
+
() => call()
|
|
104
102
|
)
|
|
105
103
|
}
|
|
106
104
|
|
|
105
|
+
producer.send = function (...args) {
|
|
106
|
+
if (!producerStartCh.hasSubscribers) {
|
|
107
|
+
return originalSend.apply(this, args)
|
|
108
|
+
}
|
|
109
|
+
return withClusterId((clusterId) => runSend.call(this, args, clusterId))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
producer.sendBatch = function (...args) {
|
|
113
|
+
if (!producerStartCh.hasSubscribers) {
|
|
114
|
+
return originalSendBatch.apply(this, args)
|
|
115
|
+
}
|
|
116
|
+
return withClusterId((clusterId) => runSendBatch.call(this, args, clusterId))
|
|
117
|
+
}
|
|
118
|
+
|
|
107
119
|
function runSend (args, clusterId) {
|
|
108
120
|
const arg0 = args[0]
|
|
109
121
|
const topic = arg0?.topic
|
|
@@ -166,6 +178,98 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
166
178
|
})
|
|
167
179
|
}
|
|
168
180
|
|
|
181
|
+
function runSendBatch (args, clusterId) {
|
|
182
|
+
const arg0 = args[0]
|
|
183
|
+
const inputTopicMessages = Array.isArray(arg0?.topicMessages) ? arg0.topicMessages : []
|
|
184
|
+
if (inputTopicMessages.length === 0) {
|
|
185
|
+
return originalSendBatch.apply(this, args)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// One ctx per topicMessages entry — kafkajs implements `send` as a single-entry
|
|
189
|
+
// `sendBatch` (`producer/messageProducer.js`), so one span per entry is the same
|
|
190
|
+
// unit `send` already produces. Cloning only happens for valid arrays so kafkajs
|
|
191
|
+
// still sees and rejects a caller's malformed `messages` field.
|
|
192
|
+
const outputEntries = new Array(inputTopicMessages.length)
|
|
193
|
+
const ctxList = []
|
|
194
|
+
let cloned = false
|
|
195
|
+
for (let i = 0; i < inputTopicMessages.length; i++) {
|
|
196
|
+
const entry = inputTopicMessages[i]
|
|
197
|
+
const topic = entry?.topic
|
|
198
|
+
const rawMessages = entry?.messages
|
|
199
|
+
let entryMessages = rawMessages
|
|
200
|
+
if (Array.isArray(rawMessages) && rawMessages.length > 0) {
|
|
201
|
+
entryMessages = cloneMessages(rawMessages, !disableHeaderInjection)
|
|
202
|
+
outputEntries[i] = { ...entry, messages: entryMessages }
|
|
203
|
+
cloned = true
|
|
204
|
+
} else {
|
|
205
|
+
outputEntries[i] = entry
|
|
206
|
+
}
|
|
207
|
+
ctxList.push({
|
|
208
|
+
bootstrapServers,
|
|
209
|
+
clusterId,
|
|
210
|
+
disableHeaderInjection,
|
|
211
|
+
messages: Array.isArray(entryMessages) ? entryMessages : [],
|
|
212
|
+
topic,
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
if (cloned) {
|
|
216
|
+
args[0] = { ...arg0, topicMessages: outputEntries }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
for (const ctx of ctxList) {
|
|
220
|
+
producerStartCh.runStores(ctx, noop)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let result
|
|
224
|
+
try {
|
|
225
|
+
result = originalSendBatch.apply(this, args)
|
|
226
|
+
} catch (error) {
|
|
227
|
+
failProduceBatch(ctxList, error)
|
|
228
|
+
throw error
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
result.then(
|
|
232
|
+
(res) => {
|
|
233
|
+
for (const ctx of ctxList) {
|
|
234
|
+
ctx.result = res
|
|
235
|
+
producerFinishCh.publish(ctx)
|
|
236
|
+
}
|
|
237
|
+
// kafkajs returns a single aggregated response covering every topic;
|
|
238
|
+
// commit fires once so the plugin's `setOffset` loop runs once per
|
|
239
|
+
// entry of the response, not once per span.
|
|
240
|
+
producerCommitCh.publish(ctxList[0])
|
|
241
|
+
},
|
|
242
|
+
(error) => failProduceBatch(ctxList, error)
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
return result
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Tag every open ctx with the shared error, then publish error + finish so the
|
|
250
|
+
* plugin closes each span. The mixed-version safety net (broker advertised
|
|
251
|
+
* Produce v3+ but the leader rejected the headers) fires at most once per
|
|
252
|
+
* failed batch and short-circuits subsequent sends to the disabled path.
|
|
253
|
+
*
|
|
254
|
+
* @param {Array<object>} ctxList
|
|
255
|
+
* @param {Error} error
|
|
256
|
+
*/
|
|
257
|
+
function failProduceBatch (ctxList, error) {
|
|
258
|
+
if (error?.name === 'KafkaJSProtocolError' && error.type === 'UNKNOWN') {
|
|
259
|
+
disableHeaderInjection = true
|
|
260
|
+
refreshHeaderSupport = noop
|
|
261
|
+
log.error(
|
|
262
|
+
// eslint-disable-next-line @stylistic/max-len
|
|
263
|
+
'Kafka Broker responded with UNKNOWN_SERVER_ERROR (-1). Please look at broker logs for more information. Tracer message header injection for Kafka is disabled.'
|
|
264
|
+
)
|
|
265
|
+
}
|
|
266
|
+
for (const ctx of ctxList) {
|
|
267
|
+
ctx.error = error
|
|
268
|
+
producerErrorCh.publish(ctx)
|
|
269
|
+
producerFinishCh.publish(ctx)
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
169
273
|
return producer
|
|
170
274
|
})
|
|
171
275
|
|
|
@@ -6,16 +6,21 @@ const { DD_MAJOR } = require('../../../../version')
|
|
|
6
6
|
const { addHook, channel } = require('../helpers/instrument')
|
|
7
7
|
const shimmer = require('../../../datadog-shimmer')
|
|
8
8
|
const { isMarkedAsUnskippable } = require('../../../datadog-plugin-jest/src/util')
|
|
9
|
+
const { writeCoverageBackfillToCache } = require('../../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
9
10
|
const log = require('../../../dd-trace/src/log')
|
|
10
11
|
const { getEnvironmentVariable } = require('../../../dd-trace/src/config/helper')
|
|
11
12
|
const {
|
|
12
13
|
getTestSuitePath,
|
|
13
14
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
14
15
|
fromCoverageMapToCoverage,
|
|
15
|
-
|
|
16
|
+
getCoveredFilesFromCoverage,
|
|
17
|
+
getExecutableFilesFromCoverage,
|
|
18
|
+
applySkippedCoverageToCoverage,
|
|
16
19
|
mergeCoverage,
|
|
17
20
|
resetCoverage,
|
|
18
21
|
getIsFaultyEarlyFlakeDetection,
|
|
22
|
+
getRelativeCoverageFiles,
|
|
23
|
+
getTestCoverageLinesPercentage,
|
|
19
24
|
collectTestOptimizationSummariesFromTraces,
|
|
20
25
|
logTestOptimizationSummary,
|
|
21
26
|
getTestOptimizationRequestResults,
|
|
@@ -53,6 +58,8 @@ const unskippableSuites = []
|
|
|
53
58
|
let suitesToSkip = []
|
|
54
59
|
let isSuitesSkipped = false
|
|
55
60
|
let skippedSuites = []
|
|
61
|
+
let skippableSuitesCoverage = {}
|
|
62
|
+
let skippedSuitesCoverage = {}
|
|
56
63
|
let itrCorrelationId = ''
|
|
57
64
|
let isForcedToRun = false
|
|
58
65
|
const config = {}
|
|
@@ -133,10 +140,33 @@ function haveRootTestsFinished (rootTests) {
|
|
|
133
140
|
return true
|
|
134
141
|
}
|
|
135
142
|
|
|
143
|
+
function getSuitePath (suite) {
|
|
144
|
+
return getTestSuitePath(suite.file, process.cwd())
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function getSuitesToSkip (originalSuites) {
|
|
148
|
+
return getSuitesToSkipFromPaths(originalSuites.map(getSuitePath))
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function getSuitesToSkipFromPaths (localSuites) {
|
|
152
|
+
const localSuitesSet = new Set(localSuites)
|
|
153
|
+
const suitesToSkipForRun = []
|
|
154
|
+
|
|
155
|
+
for (const suite of suitesToSkip) {
|
|
156
|
+
if (localSuitesSet.has(suite)) {
|
|
157
|
+
suitesToSkipForRun.push(suite)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return suitesToSkipForRun
|
|
162
|
+
}
|
|
163
|
+
|
|
136
164
|
function getFilteredSuites (originalSuites) {
|
|
165
|
+
const suitesToSkipForRun = getSuitesToSkip(originalSuites)
|
|
166
|
+
|
|
137
167
|
return originalSuites.reduce((acc, suite) => {
|
|
138
|
-
const testPath =
|
|
139
|
-
const shouldSkip =
|
|
168
|
+
const testPath = getSuitePath(suite)
|
|
169
|
+
const shouldSkip = suitesToSkipForRun.includes(testPath)
|
|
140
170
|
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
141
171
|
if (shouldSkip && !isUnskippable) {
|
|
142
172
|
acc.skippedSuites.add(testPath)
|
|
@@ -144,7 +174,50 @@ function getFilteredSuites (originalSuites) {
|
|
|
144
174
|
acc.suitesToRun.push(suite)
|
|
145
175
|
}
|
|
146
176
|
return acc
|
|
147
|
-
}, { suitesToRun: [], skippedSuites: new Set() })
|
|
177
|
+
}, { suitesToRun: [], skippedSuites: new Set(), suitesToSkipForRun })
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function hasSkippableSuitesCoverage () {
|
|
181
|
+
return skippableSuitesCoverage &&
|
|
182
|
+
typeof skippableSuitesCoverage === 'object' &&
|
|
183
|
+
Object.keys(skippableSuitesCoverage).length > 0
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isTiaCoverageBackfillEnabled () {
|
|
187
|
+
return config.isItrEnabled && config.isCoverageReportUploadEnabled
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getCoverageRootDir () {
|
|
191
|
+
return config.repositoryRoot || process.cwd()
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function shouldReportCodeCoverageLinesPct (hasBackfilledCoverage) {
|
|
195
|
+
return !isSuitesSkipped || hasBackfilledCoverage
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function getSkippedSuitesCoverageForRun () {
|
|
199
|
+
return isSuitesSkipped && isTiaCoverageBackfillEnabled() && hasSkippableSuitesCoverage()
|
|
200
|
+
? skippableSuitesCoverage
|
|
201
|
+
: {}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function applySkippedCoverageToMochaCoverageMap () {
|
|
205
|
+
if (!isTiaCoverageBackfillEnabled()) return false
|
|
206
|
+
return applySkippedCoverageToCoverage(originalCoverageMap, skippedSuitesCoverage, getCoverageRootDir())
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function getMochaTestSessionCoverageFiles () {
|
|
210
|
+
return getRelativeCoverageFiles(getExecutableFilesFromCoverage(originalCoverageMap), getCoverageRootDir())
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function resetSuiteSkippingRunState () {
|
|
214
|
+
isSuitesSkipped = false
|
|
215
|
+
skippedSuites = []
|
|
216
|
+
skippableSuitesCoverage = {}
|
|
217
|
+
skippedSuitesCoverage = {}
|
|
218
|
+
untestedCoverage = undefined
|
|
219
|
+
config.repositoryRoot = undefined
|
|
220
|
+
writeCoverageBackfillToCache({})
|
|
148
221
|
}
|
|
149
222
|
|
|
150
223
|
function getOnStartHandler (frameworkVersion) {
|
|
@@ -218,12 +291,24 @@ function getOnEndHandler (isParallel) {
|
|
|
218
291
|
testFileToSuiteCtx.clear()
|
|
219
292
|
|
|
220
293
|
let testCodeCoverageLinesTotal
|
|
221
|
-
|
|
294
|
+
let testSessionCoverageFiles
|
|
295
|
+
if (global.__coverage__ || untestedCoverage) {
|
|
222
296
|
try {
|
|
297
|
+
let hasBackfilledCoverage = false
|
|
223
298
|
if (untestedCoverage) {
|
|
224
299
|
originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
|
|
225
300
|
}
|
|
226
|
-
|
|
301
|
+
hasBackfilledCoverage = applySkippedCoverageToMochaCoverageMap()
|
|
302
|
+
if (shouldReportCodeCoverageLinesPct(hasBackfilledCoverage)) {
|
|
303
|
+
testCodeCoverageLinesTotal = getTestCoverageLinesPercentage(
|
|
304
|
+
originalCoverageMap,
|
|
305
|
+
undefined,
|
|
306
|
+
getCoverageRootDir()
|
|
307
|
+
)
|
|
308
|
+
}
|
|
309
|
+
if (isTiaCoverageBackfillEnabled()) {
|
|
310
|
+
testSessionCoverageFiles = getMochaTestSessionCoverageFiles()
|
|
311
|
+
}
|
|
227
312
|
} catch {
|
|
228
313
|
// ignore errors
|
|
229
314
|
}
|
|
@@ -235,6 +320,7 @@ function getOnEndHandler (isParallel) {
|
|
|
235
320
|
status,
|
|
236
321
|
isSuitesSkipped,
|
|
237
322
|
testCodeCoverageLinesTotal,
|
|
323
|
+
testSessionCoverageFiles,
|
|
238
324
|
numSkippedSuites: skippedSuites.length,
|
|
239
325
|
hasForcedToRunSuites: isForcedToRun,
|
|
240
326
|
hasUnskippableSuites: !!unskippableSuites.length,
|
|
@@ -276,23 +362,39 @@ function applyTestManagementTestsResponse ({ err, testManagementTests: receivedT
|
|
|
276
362
|
}
|
|
277
363
|
}
|
|
278
364
|
|
|
279
|
-
function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest) {
|
|
365
|
+
function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFinishRequest, localSuites) {
|
|
280
366
|
const ctx = {
|
|
281
367
|
isParallel,
|
|
282
368
|
frameworkVersion,
|
|
283
369
|
}
|
|
284
370
|
let skippableSuitesResponse
|
|
285
|
-
|
|
286
|
-
|
|
371
|
+
resetSuiteSkippingRunState()
|
|
372
|
+
|
|
373
|
+
const onReceivedSkippableSuites = ({
|
|
374
|
+
err,
|
|
375
|
+
skippableSuites,
|
|
376
|
+
itrCorrelationId: responseItrCorrelationId,
|
|
377
|
+
skippableSuitesCoverage: responseSkippableSuitesCoverage,
|
|
378
|
+
}) => {
|
|
287
379
|
if (err) {
|
|
288
380
|
suitesToSkip = []
|
|
381
|
+
skippableSuitesCoverage = {}
|
|
289
382
|
} else {
|
|
290
383
|
suitesToSkip = skippableSuites
|
|
291
384
|
itrCorrelationId = responseItrCorrelationId
|
|
385
|
+
skippableSuitesCoverage = responseSkippableSuitesCoverage || {}
|
|
292
386
|
}
|
|
387
|
+
if (localSuites) {
|
|
388
|
+
suitesToSkip = getSuitesToSkipFromPaths(localSuites)
|
|
389
|
+
mochaGlobalRunCh.runStores(ctx, () => {
|
|
390
|
+
onFinishRequest()
|
|
391
|
+
})
|
|
392
|
+
return
|
|
393
|
+
}
|
|
394
|
+
|
|
293
395
|
// We remove the suites that we skip through ITR
|
|
294
396
|
const filteredSuites = getFilteredSuites(runner.suite.suites)
|
|
295
|
-
const { suitesToRun } = filteredSuites
|
|
397
|
+
const { suitesToRun, suitesToSkipForRun } = filteredSuites
|
|
296
398
|
|
|
297
399
|
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
298
400
|
|
|
@@ -301,6 +403,9 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
301
403
|
runner.suite.suites = suitesToRun
|
|
302
404
|
|
|
303
405
|
skippedSuites = [...filteredSuites.skippedSuites]
|
|
406
|
+
suitesToSkip = suitesToSkipForRun
|
|
407
|
+
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
408
|
+
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
304
409
|
|
|
305
410
|
mochaGlobalRunCh.runStores(ctx, () => {
|
|
306
411
|
onFinishRequest()
|
|
@@ -346,12 +451,13 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
346
451
|
}
|
|
347
452
|
}
|
|
348
453
|
|
|
349
|
-
const onReceivedConfiguration = ({ err, libraryConfig }) => {
|
|
454
|
+
const onReceivedConfiguration = ({ err, libraryConfig, repositoryRoot }) => {
|
|
350
455
|
if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
|
|
351
456
|
return mochaGlobalRunCh.runStores(ctx, () => {
|
|
352
457
|
onFinishRequest()
|
|
353
458
|
})
|
|
354
459
|
}
|
|
460
|
+
config.repositoryRoot = repositoryRoot
|
|
355
461
|
config.isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
|
|
356
462
|
config.earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
|
|
357
463
|
config.earlyFlakeDetectionSlowTestRetries = libraryConfig.earlyFlakeDetectionSlowTestRetries ?? {}
|
|
@@ -360,7 +466,10 @@ function getExecutionConfiguration (runner, isParallel, frameworkVersion, onFini
|
|
|
360
466
|
config.isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
|
|
361
467
|
config.testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
|
|
362
468
|
config.isImpactedTestsEnabled = libraryConfig.isImpactedTestsEnabled
|
|
363
|
-
config.
|
|
469
|
+
config.isItrEnabled = libraryConfig.isItrEnabled
|
|
470
|
+
config.isCodeCoverageEnabled = libraryConfig.isCodeCoverageEnabled
|
|
471
|
+
config.isCoverageReportUploadEnabled = libraryConfig.isCoverageReportUploadEnabled
|
|
472
|
+
config.isSuitesSkippingEnabled = config.isItrEnabled && libraryConfig.isSuitesSkippingEnabled
|
|
364
473
|
config.isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
|
|
365
474
|
config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
|
|
366
475
|
|
|
@@ -588,7 +697,7 @@ addHook({
|
|
|
588
697
|
const status = getRootSuiteStatus(rootTests)
|
|
589
698
|
|
|
590
699
|
if (global.__coverage__) {
|
|
591
|
-
const coverageFiles =
|
|
700
|
+
const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
|
|
592
701
|
testSuiteCodeCoverageCh.publish({ coverageFiles, suiteFile: file })
|
|
593
702
|
mergeCoverage(global.__coverage__, originalCoverageMap)
|
|
594
703
|
resetCoverage(global.__coverage__)
|
|
@@ -786,7 +895,7 @@ addHook({
|
|
|
786
895
|
}
|
|
787
896
|
|
|
788
897
|
if (global.__coverage__) {
|
|
789
|
-
const coverageFiles =
|
|
898
|
+
const coverageFiles = getCoveredFilesFromCoverage(global.__coverage__)
|
|
790
899
|
|
|
791
900
|
testSuiteCodeCoverageCh.publish({
|
|
792
901
|
coverageFiles,
|
|
@@ -908,11 +1017,11 @@ addHook({
|
|
|
908
1017
|
}
|
|
909
1018
|
}
|
|
910
1019
|
|
|
1020
|
+
const localSuites = files.map(file => getTestSuitePath(file, process.cwd()))
|
|
911
1021
|
getExecutionConfiguration(this, true, frameworkVersion, () => {
|
|
912
1022
|
if (config.isKnownTestsEnabled) {
|
|
913
|
-
const testSuites = files.map(file => getTestSuitePath(file, process.cwd()))
|
|
914
1023
|
const isFaulty = getIsFaultyEarlyFlakeDetection(
|
|
915
|
-
|
|
1024
|
+
localSuites,
|
|
916
1025
|
config.knownTests?.mocha || {},
|
|
917
1026
|
config.earlyFlakeDetectionFaultyThreshold
|
|
918
1027
|
)
|
|
@@ -937,11 +1046,13 @@ addHook({
|
|
|
937
1046
|
}
|
|
938
1047
|
isSuitesSkipped = skippedFiles.length > 0
|
|
939
1048
|
skippedSuites = skippedFiles
|
|
1049
|
+
skippedSuitesCoverage = getSkippedSuitesCoverageForRun()
|
|
1050
|
+
writeCoverageBackfillToCache(skippedSuitesCoverage, getCoverageRootDir())
|
|
940
1051
|
run.apply(this, [cb, { files: filteredFiles }])
|
|
941
1052
|
} else {
|
|
942
1053
|
run.apply(this, arguments)
|
|
943
1054
|
}
|
|
944
|
-
})
|
|
1055
|
+
}, localSuites)
|
|
945
1056
|
|
|
946
1057
|
return this
|
|
947
1058
|
})
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Shimmer required: NATS consumer paths need argument modification — the user's
|
|
4
|
+
// `opts.callback` is wrapped before being handed to SubscriptionImpl, and the
|
|
5
|
+
// returned subscription's async iterator is wrapped so iterator-style consumers
|
|
6
|
+
// get receive events. Orchestrion can only wrap method calls, not arguments
|
|
7
|
+
// or returned iterables.
|
|
8
|
+
|
|
9
|
+
const shimmer = require('../../datadog-shimmer')
|
|
10
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
11
|
+
|
|
12
|
+
const publishStartCh = channel('apm:nats:publish:start')
|
|
13
|
+
const publishFinishCh = channel('apm:nats:publish:finish')
|
|
14
|
+
const publishErrorCh = channel('apm:nats:publish:error')
|
|
15
|
+
|
|
16
|
+
const consumeStartCh = channel('apm:nats:consume:start')
|
|
17
|
+
const consumeFinishCh = channel('apm:nats:consume:finish')
|
|
18
|
+
const consumeErrorCh = channel('apm:nats:consume:error')
|
|
19
|
+
|
|
20
|
+
// Tracks connections that are currently inside a `request`/`requestMany` call
|
|
21
|
+
// so the nested `this.publish(...)` they issue short-circuits without creating
|
|
22
|
+
// a second producer span (the outer request wrap already created one and
|
|
23
|
+
// injected headers — the inner publish would double-count it). A WeakSet avoids
|
|
24
|
+
// changing the shape of the user's connection object.
|
|
25
|
+
const requestsInFlight = new WeakSet()
|
|
26
|
+
|
|
27
|
+
// Captured from the `lib/headers.js` hook below. The nats-core package always
|
|
28
|
+
// imports `./headers` from `lib/nats.js`, so by the time we wrap `publish` the
|
|
29
|
+
// reference is set. No defensive checks needed at call sites.
|
|
30
|
+
let createHeaders
|
|
31
|
+
|
|
32
|
+
addHook({ name: '@nats-io/nats-core', versions: ['>=3.0.0'], file: 'lib/headers.js' }, exports => {
|
|
33
|
+
createHeaders = exports.headers
|
|
34
|
+
return exports
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
// transport-node re-exports nats-core internals — the passthrough hook ensures
|
|
38
|
+
// the package name is registered so `withVersions('nats', '@nats-io/transport-node', ...)`
|
|
39
|
+
// can resolve it in plugin tests.
|
|
40
|
+
addHook({ name: '@nats-io/transport-node', versions: ['>=3.0.0'] }, exports => exports)
|
|
41
|
+
|
|
42
|
+
function wrapSyncProducer (original, type) {
|
|
43
|
+
return function (subject, data, options) {
|
|
44
|
+
if (!publishStartCh.hasSubscribers) {
|
|
45
|
+
return original.apply(this, arguments)
|
|
46
|
+
}
|
|
47
|
+
const opts = { ...options }
|
|
48
|
+
const ctx = { type, subject, data, options: opts, connection: this, createHeaders }
|
|
49
|
+
return publishStartCh.runStores(ctx, () => {
|
|
50
|
+
try {
|
|
51
|
+
return original.call(this, subject, data, opts)
|
|
52
|
+
} catch (err) {
|
|
53
|
+
ctx.error = err
|
|
54
|
+
publishErrorCh.publish(ctx)
|
|
55
|
+
throw err
|
|
56
|
+
} finally {
|
|
57
|
+
publishFinishCh.publish(ctx)
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// publish is also wrapped by `wrapSyncProducer`, but request/requestMany call
|
|
64
|
+
// `this.publish(...)` internally. Set a marker on the connection so the inner
|
|
65
|
+
// publish wrap short-circuits — see `wrapPublish`.
|
|
66
|
+
function wrapAsyncProducer (original, type) {
|
|
67
|
+
return function (subject, data, options) {
|
|
68
|
+
if (!publishStartCh.hasSubscribers) {
|
|
69
|
+
return original.apply(this, arguments)
|
|
70
|
+
}
|
|
71
|
+
const opts = { ...options }
|
|
72
|
+
const ctx = { type, subject, data, options: opts, connection: this, createHeaders }
|
|
73
|
+
return publishStartCh.runStores(ctx, () => {
|
|
74
|
+
requestsInFlight.add(this)
|
|
75
|
+
let promise
|
|
76
|
+
try {
|
|
77
|
+
// `request`/`requestMany` never throw synchronously — they wrap their own
|
|
78
|
+
// input validation in a try/catch that returns `Promise.reject`.
|
|
79
|
+
promise = original.call(this, subject, data, opts)
|
|
80
|
+
} finally {
|
|
81
|
+
// The nested `this.publish(...)` runs during the synchronous body of
|
|
82
|
+
// request/requestMany, so clearing the marker as soon as the call
|
|
83
|
+
// returns is sufficient — the promise resolution happens later.
|
|
84
|
+
requestsInFlight.delete(this)
|
|
85
|
+
}
|
|
86
|
+
return Promise.resolve(promise).then(
|
|
87
|
+
result => {
|
|
88
|
+
ctx.result = result
|
|
89
|
+
publishFinishCh.publish(ctx)
|
|
90
|
+
return result
|
|
91
|
+
},
|
|
92
|
+
err => {
|
|
93
|
+
ctx.error = err
|
|
94
|
+
publishErrorCh.publish(ctx)
|
|
95
|
+
publishFinishCh.publish(ctx)
|
|
96
|
+
throw err
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function wrapPublish (original) {
|
|
104
|
+
const wrapped = wrapSyncProducer(original, 'publish')
|
|
105
|
+
return function (subject, data, options) {
|
|
106
|
+
// Called from inside request/requestMany — the outer wrap already produced
|
|
107
|
+
// a span and injected headers; running the inner wrap would double-count.
|
|
108
|
+
if (requestsInFlight.has(this)) {
|
|
109
|
+
return original.apply(this, arguments)
|
|
110
|
+
}
|
|
111
|
+
return wrapped.apply(this, arguments)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function wrapSubscribeCallback (userCallback, subject, connection) {
|
|
116
|
+
return function (err, message) {
|
|
117
|
+
if (!message || err) {
|
|
118
|
+
return userCallback.call(this, err, message)
|
|
119
|
+
}
|
|
120
|
+
const ctx = { subject, message, connection }
|
|
121
|
+
return consumeStartCh.runStores(ctx, () => {
|
|
122
|
+
try {
|
|
123
|
+
return userCallback.call(this, err, message)
|
|
124
|
+
} catch (e) {
|
|
125
|
+
ctx.error = e
|
|
126
|
+
consumeErrorCh.publish(ctx)
|
|
127
|
+
throw e
|
|
128
|
+
} finally {
|
|
129
|
+
consumeFinishCh.publish(ctx)
|
|
130
|
+
}
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Iterator-style consumers don't expose a delivery callback we can wrap, so
|
|
136
|
+
// the consume span represents the moment of receipt only — it starts and
|
|
137
|
+
// finishes before the value is yielded to user code, and the user's loop
|
|
138
|
+
// body is not parented under the span.
|
|
139
|
+
function wrapAsyncIteratorFactory (asyncIterator, subject, connection) {
|
|
140
|
+
return function () {
|
|
141
|
+
const iterator = asyncIterator.apply(this, arguments)
|
|
142
|
+
iterator.next = shimmer.wrapCallback(iterator.next, next => function () {
|
|
143
|
+
return next.apply(this, arguments).then(result => {
|
|
144
|
+
if (result && !result.done && result.value) {
|
|
145
|
+
const ctx = { subject, message: result.value, connection }
|
|
146
|
+
consumeStartCh.runStores(ctx, () => {
|
|
147
|
+
consumeFinishCh.publish(ctx)
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
return result
|
|
151
|
+
})
|
|
152
|
+
})
|
|
153
|
+
return iterator
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
addHook({ name: '@nats-io/nats-core', versions: ['>=3.0.0'], file: 'lib/nats.js' }, exports => {
|
|
158
|
+
const proto = exports.NatsConnectionImpl.prototype
|
|
159
|
+
|
|
160
|
+
shimmer.wrap(proto, 'publish', wrapPublish)
|
|
161
|
+
shimmer.wrap(proto, 'request', request => wrapAsyncProducer(request, 'request'))
|
|
162
|
+
shimmer.wrap(proto, 'requestMany', requestMany => wrapAsyncProducer(requestMany, 'requestMany'))
|
|
163
|
+
|
|
164
|
+
shimmer.wrap(proto, 'subscribe', subscribe => function (subject, opts) {
|
|
165
|
+
if (!consumeStartCh.hasSubscribers) {
|
|
166
|
+
return subscribe.apply(this, arguments)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const userOpts = opts ?? {}
|
|
170
|
+
if (typeof userOpts.callback === 'function') {
|
|
171
|
+
arguments[1] = { ...userOpts, callback: wrapSubscribeCallback(userOpts.callback, subject, this) }
|
|
172
|
+
return subscribe.apply(this, arguments)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const sub = subscribe.apply(this, arguments)
|
|
176
|
+
shimmer.wrap(sub, Symbol.asyncIterator, asyncIterator =>
|
|
177
|
+
wrapAsyncIteratorFactory(asyncIterator, subject, this))
|
|
178
|
+
return sub
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
return exports
|
|
182
|
+
})
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
4
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config/helper')
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
readCoverageBackfillFromCache,
|
|
7
|
+
readCoverageBackfillRootDirFromCache,
|
|
8
|
+
setupSettingsCachePath,
|
|
9
|
+
} = require('../../dd-trace/src/ci-visibility/test-optimization-cache')
|
|
10
|
+
const { applySkippedCoverageToCoverage } = require('../../dd-trace/src/plugins/util/test')
|
|
6
11
|
const { addHook, channel } = require('./helpers/instrument')
|
|
7
12
|
|
|
8
13
|
const codeCoverageWrapCh = channel('ci:nyc:wrap')
|
|
@@ -16,6 +21,38 @@ addHook({
|
|
|
16
21
|
// when dd-trace fetches library configuration
|
|
17
22
|
setupSettingsCachePath()
|
|
18
23
|
|
|
24
|
+
if (nycPackage.prototype.getCoverageMapFromAllCoverageFiles) {
|
|
25
|
+
// Some test frameworks receive skipped-suite coverage in the test process, but nyc merges reports later in the nyc
|
|
26
|
+
// process. Reuse the settings cache path as the process handoff so nyc can backfill skipped files before reporting.
|
|
27
|
+
shimmer.wrap(
|
|
28
|
+
nycPackage.prototype,
|
|
29
|
+
'getCoverageMapFromAllCoverageFiles',
|
|
30
|
+
getCoverageMapFromAllCoverageFiles => function (...args) {
|
|
31
|
+
const coverageMap = getCoverageMapFromAllCoverageFiles.apply(this, args)
|
|
32
|
+
const applyCoverageBackfill = (resolvedCoverageMap) => {
|
|
33
|
+
try {
|
|
34
|
+
if (!resolvedCoverageMap) {
|
|
35
|
+
return resolvedCoverageMap
|
|
36
|
+
}
|
|
37
|
+
applySkippedCoverageToCoverage(
|
|
38
|
+
resolvedCoverageMap,
|
|
39
|
+
readCoverageBackfillFromCache(),
|
|
40
|
+
readCoverageBackfillRootDirFromCache() || this.cwd
|
|
41
|
+
)
|
|
42
|
+
} catch {
|
|
43
|
+
// Do not break nyc's report generation if the cached backfill is stale or malformed.
|
|
44
|
+
}
|
|
45
|
+
return resolvedCoverageMap
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (coverageMap && typeof coverageMap.then === 'function') {
|
|
49
|
+
return coverageMap.then(applyCoverageBackfill)
|
|
50
|
+
}
|
|
51
|
+
return applyCoverageBackfill(coverageMap)
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
19
56
|
// `wrap` is an async function
|
|
20
57
|
shimmer.wrap(nycPackage.prototype, 'wrap', wrap => function (...args) {
|
|
21
58
|
// Only relevant if the config `all` is set to true (for untested code coverage)
|