dd-trace 4.16.0 → 4.18.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 +1 -0
- package/index.d.ts +9 -1
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/body-parser.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +29 -4
- package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +45 -0
- package/packages/datadog-instrumentations/src/express.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/jest.js +58 -20
- package/packages/datadog-instrumentations/src/knex.js +69 -1
- package/packages/datadog-instrumentations/src/mocha.js +34 -4
- package/packages/datadog-instrumentations/src/mongodb.js +63 -0
- package/packages/datadog-instrumentations/src/mongoose.js +140 -1
- package/packages/datadog-instrumentations/src/next.js +98 -23
- package/packages/datadog-instrumentations/src/playwright.js +22 -8
- package/packages/datadog-plugin-cucumber/src/index.js +17 -5
- package/packages/datadog-plugin-cypress/src/plugin.js +38 -8
- package/packages/datadog-plugin-http/src/client.js +2 -0
- package/packages/datadog-plugin-jest/src/index.js +29 -6
- package/packages/datadog-plugin-jest/src/util.js +45 -2
- package/packages/datadog-plugin-memcached/src/index.js +10 -5
- package/packages/datadog-plugin-mocha/src/index.js +25 -6
- package/packages/datadog-plugin-next/src/index.js +4 -3
- package/packages/datadog-plugin-playwright/src/index.js +4 -1
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +60 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +269 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +5 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +22 -4
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +173 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +21 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +3 -3
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +2 -2
- package/packages/dd-trace/src/appsec/iast/iast-log.js +9 -4
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +4 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +6 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +25 -12
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +4 -4
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +13 -2
- package/packages/dd-trace/src/appsec/iast/taint-tracking/secure-marks-generator.js +13 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +2 -1
- package/packages/dd-trace/src/appsec/iast/telemetry/index.js +1 -14
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +16 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +22 -4
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +9 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +15 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +169 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +5 -1
- package/packages/dd-trace/src/appsec/index.js +31 -13
- package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -3
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +14 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +4 -2
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -0
- package/packages/dd-trace/src/config.js +37 -13
- package/packages/dd-trace/src/format.js +3 -0
- package/packages/dd-trace/src/git_properties.js +16 -15
- package/packages/dd-trace/src/plugin_manager.js +3 -1
- package/packages/dd-trace/src/plugins/util/ci.js +17 -0
- package/packages/dd-trace/src/plugins/util/git.js +26 -4
- package/packages/dd-trace/src/plugins/util/test.js +45 -2
- package/packages/dd-trace/src/profiling/config.js +20 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +51 -40
- package/packages/dd-trace/src/service-naming/extra-services.js +24 -0
- package/packages/dd-trace/src/telemetry/index.js +4 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +65 -0
- package/packages/dd-trace/src/{appsec/iast/telemetry/log → telemetry/logs}/log-collector.js +9 -22
- package/packages/dd-trace/src/telemetry/metrics.js +0 -5
- package/packages/dd-trace/src/appsec/iast/telemetry/log/index.js +0 -87
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -14,6 +14,7 @@ require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
|
|
|
14
14
|
require,int64-buffer,MIT,Copyright 2015-2016 Yusuke Kawasaki
|
|
15
15
|
require,ipaddr.js,MIT,Copyright 2011-2017 whitequark
|
|
16
16
|
require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
|
|
17
|
+
require,jest-docblock,MIT,Copyright Meta Platforms, Inc. and affiliates.
|
|
17
18
|
require,koalas,MIT,Copyright 2013-2017 Brian Woodward
|
|
18
19
|
require,limiter,MIT,Copyright 2011 John Hurliman
|
|
19
20
|
require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
|
package/index.d.ts
CHANGED
|
@@ -453,7 +453,15 @@ export declare interface TracerOptions {
|
|
|
453
453
|
* Whether to enable vulnerability redaction
|
|
454
454
|
* @default true
|
|
455
455
|
*/
|
|
456
|
-
redactionEnabled?: boolean
|
|
456
|
+
redactionEnabled?: boolean,
|
|
457
|
+
/**
|
|
458
|
+
* Specifies a regex that will redact sensitive source names in vulnerability reports.
|
|
459
|
+
*/
|
|
460
|
+
redactionNamePattern?: string,
|
|
461
|
+
/**
|
|
462
|
+
* Specifies a regex that will redact sensitive source values in vulnerability reports.
|
|
463
|
+
*/
|
|
464
|
+
redactionValuePattern?: string
|
|
457
465
|
}
|
|
458
466
|
};
|
|
459
467
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.18.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -69,10 +69,10 @@
|
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
71
|
"@datadog/native-appsec": "^4.0.0",
|
|
72
|
-
"@datadog/native-iast-rewriter": "2.1
|
|
73
|
-
"@datadog/native-iast-taint-tracking": "1.
|
|
72
|
+
"@datadog/native-iast-rewriter": "2.2.1",
|
|
73
|
+
"@datadog/native-iast-taint-tracking": "1.6.3",
|
|
74
74
|
"@datadog/native-metrics": "^2.0.0",
|
|
75
|
-
"@datadog/pprof": "
|
|
75
|
+
"@datadog/pprof": "4.0.1",
|
|
76
76
|
"@datadog/sketches-js": "^2.1.0",
|
|
77
77
|
"@opentelemetry/api": "^1.0.0",
|
|
78
78
|
"@opentelemetry/core": "^1.14.0",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"int64-buffer": "^0.1.9",
|
|
84
84
|
"ipaddr.js": "^2.1.0",
|
|
85
85
|
"istanbul-lib-coverage": "3.2.0",
|
|
86
|
+
"jest-docblock": "^29.7.0",
|
|
86
87
|
"koalas": "^1.0.2",
|
|
87
88
|
"limiter": "^1.1.4",
|
|
88
89
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -10,8 +10,9 @@ function publishRequestBodyAndNext (req, res, next) {
|
|
|
10
10
|
return function () {
|
|
11
11
|
if (bodyParserReadCh.hasSubscribers && req) {
|
|
12
12
|
const abortController = new AbortController()
|
|
13
|
+
const body = req.body
|
|
13
14
|
|
|
14
|
-
bodyParserReadCh.publish({ req, res, abortController })
|
|
15
|
+
bodyParserReadCh.publish({ req, res, body, abortController })
|
|
15
16
|
|
|
16
17
|
if (abortController.signal.aborted) return
|
|
17
18
|
}
|
|
@@ -31,6 +31,10 @@ const {
|
|
|
31
31
|
getTestSuitePath
|
|
32
32
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
33
33
|
|
|
34
|
+
const isMarkedAsUnskippable = (pickle) => {
|
|
35
|
+
return !!pickle.tags.find(tag => tag.name === '@datadog:unskippable')
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
// We'll preserve the original coverage here
|
|
35
39
|
const originalCoverageMap = createCoverageMap()
|
|
36
40
|
|
|
@@ -39,6 +43,9 @@ const patched = new WeakSet()
|
|
|
39
43
|
|
|
40
44
|
let pickleByFile = {}
|
|
41
45
|
const pickleResultByFile = {}
|
|
46
|
+
let skippableSuites = []
|
|
47
|
+
let isForcedToRun = false
|
|
48
|
+
let isUnskippable = false
|
|
42
49
|
|
|
43
50
|
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
44
51
|
if (testStatuses.some(status => status === 'fail')) {
|
|
@@ -91,7 +98,11 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
91
98
|
const testSuiteFullPath = this.pickle.uri
|
|
92
99
|
|
|
93
100
|
if (!pickleResultByFile[testSuiteFullPath]) { // first test in suite
|
|
94
|
-
|
|
101
|
+
isUnskippable = isMarkedAsUnskippable(this.pickle)
|
|
102
|
+
const testSuitePath = getTestSuitePath(testSuiteFullPath, process.cwd())
|
|
103
|
+
isForcedToRun = isUnskippable && skippableSuites.includes(testSuitePath)
|
|
104
|
+
|
|
105
|
+
testSuiteStartCh.publish({ testSuitePath, isUnskippable, isForcedToRun })
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
const testSourceLine = this.gherkinDocument &&
|
|
@@ -221,8 +232,11 @@ function getFilteredPickles (runtime, suitesToSkip) {
|
|
|
221
232
|
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
222
233
|
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
223
234
|
const testSuitePath = getTestSuitePath(test.uri, process.cwd())
|
|
235
|
+
|
|
236
|
+
const isUnskippable = isMarkedAsUnskippable(test)
|
|
224
237
|
const isSkipped = suitesToSkip.includes(testSuitePath)
|
|
225
|
-
|
|
238
|
+
|
|
239
|
+
if (isSkipped && !isUnskippable) {
|
|
226
240
|
acc.skippedSuites.add(testSuitePath)
|
|
227
241
|
} else {
|
|
228
242
|
acc.picklesToRun.push(pickleId)
|
|
@@ -270,7 +284,11 @@ addHook({
|
|
|
270
284
|
skippableSuitesCh.publish({ onDone })
|
|
271
285
|
})
|
|
272
286
|
|
|
273
|
-
const
|
|
287
|
+
const skippableResponse = await skippableSuitesPromise
|
|
288
|
+
|
|
289
|
+
const err = skippableResponse.err
|
|
290
|
+
skippableSuites = skippableResponse.skippableSuites
|
|
291
|
+
|
|
274
292
|
let skippedSuites = []
|
|
275
293
|
let isSuitesSkipped = false
|
|
276
294
|
|
|
@@ -278,6 +296,11 @@ addHook({
|
|
|
278
296
|
const filteredPickles = getFilteredPickles(this, skippableSuites)
|
|
279
297
|
const { picklesToRun } = filteredPickles
|
|
280
298
|
isSuitesSkipped = picklesToRun.length !== this.pickleIds.length
|
|
299
|
+
|
|
300
|
+
log.debug(
|
|
301
|
+
() => `${picklesToRun.length} out of ${this.pickleIds.length} suites are going to run.`
|
|
302
|
+
)
|
|
303
|
+
|
|
281
304
|
this.pickleIds = picklesToRun
|
|
282
305
|
|
|
283
306
|
skippedSuites = Array.from(filteredPickles.skippedSuites)
|
|
@@ -315,7 +338,9 @@ addHook({
|
|
|
315
338
|
status: success ? 'pass' : 'fail',
|
|
316
339
|
isSuitesSkipped,
|
|
317
340
|
testCodeCoverageLinesTotal,
|
|
318
|
-
numSkippedSuites: skippedSuites.length
|
|
341
|
+
numSkippedSuites: skippedSuites.length,
|
|
342
|
+
hasUnskippableSuites: isUnskippable,
|
|
343
|
+
hasForcedToRunSuites: isForcedToRun
|
|
319
344
|
})
|
|
320
345
|
})
|
|
321
346
|
return success
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook
|
|
6
|
+
} = require('./helpers/instrument')
|
|
7
|
+
const shimmer = require('../../datadog-shimmer')
|
|
8
|
+
|
|
9
|
+
const sanitizeMethodFinished = channel('datadog:express-mongo-sanitize:sanitize:finish')
|
|
10
|
+
const sanitizeMiddlewareFinished = channel('datadog:express-mongo-sanitize:filter:finish')
|
|
11
|
+
|
|
12
|
+
const propertiesToSanitize = ['body', 'params', 'headers', 'query']
|
|
13
|
+
|
|
14
|
+
addHook({ name: 'express-mongo-sanitize', versions: ['>=1.0.0'] }, expressMongoSanitize => {
|
|
15
|
+
shimmer.wrap(expressMongoSanitize, 'sanitize', sanitize => function () {
|
|
16
|
+
const sanitizedObject = sanitize.apply(this, arguments)
|
|
17
|
+
|
|
18
|
+
if (sanitizeMethodFinished.hasSubscribers) {
|
|
19
|
+
sanitizeMethodFinished.publish({ sanitizedObject })
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return sanitizedObject
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return shimmer.wrap(expressMongoSanitize, function () {
|
|
26
|
+
const middleware = expressMongoSanitize.apply(this, arguments)
|
|
27
|
+
|
|
28
|
+
return shimmer.wrap(middleware, function (req, res, next) {
|
|
29
|
+
if (!sanitizeMiddlewareFinished.hasSubscribers) {
|
|
30
|
+
return middleware.apply(this, arguments)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const wrappedNext = shimmer.wrap(next, function () {
|
|
34
|
+
sanitizeMiddlewareFinished.publish({
|
|
35
|
+
sanitizedProperties: propertiesToSanitize,
|
|
36
|
+
req
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return next.apply(this, arguments)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
return middleware.call(this, req, res, wrappedNext)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -33,8 +33,9 @@ function publishQueryParsedAndNext (req, res, next) {
|
|
|
33
33
|
return function () {
|
|
34
34
|
if (queryParserReadCh.hasSubscribers && req) {
|
|
35
35
|
const abortController = new AbortController()
|
|
36
|
+
const query = req.query
|
|
36
37
|
|
|
37
|
-
queryParserReadCh.publish({ req, res, abortController })
|
|
38
|
+
queryParserReadCh.publish({ req, res, query, abortController })
|
|
38
39
|
|
|
39
40
|
if (abortController.signal.aborted) return
|
|
40
41
|
}
|
|
@@ -38,6 +38,7 @@ module.exports = {
|
|
|
38
38
|
'dns': () => require('../dns'),
|
|
39
39
|
'elasticsearch': () => require('../elasticsearch'),
|
|
40
40
|
'express': () => require('../express'),
|
|
41
|
+
'express-mongo-sanitize': () => require('../express-mongo-sanitize'),
|
|
41
42
|
'fastify': () => require('../fastify'),
|
|
42
43
|
'find-my-way': () => require('../find-my-way'),
|
|
43
44
|
'fs': () => require('../fs'),
|
|
@@ -68,7 +69,7 @@ module.exports = {
|
|
|
68
69
|
'mocha': () => require('../mocha'),
|
|
69
70
|
'mocha-each': () => require('../mocha'),
|
|
70
71
|
'moleculer': () => require('../moleculer'),
|
|
71
|
-
'mongodb': () => require('../mongodb
|
|
72
|
+
'mongodb': () => require('../mongodb'),
|
|
72
73
|
'mongodb-core': () => require('../mongodb-core'),
|
|
73
74
|
'mongoose': () => require('../mongoose'),
|
|
74
75
|
'mysql': () => require('../mysql'),
|
|
@@ -46,6 +46,8 @@ let isCodeCoverageEnabled = false
|
|
|
46
46
|
let isSuitesSkippingEnabled = false
|
|
47
47
|
let isSuitesSkipped = false
|
|
48
48
|
let numSkippedSuites = 0
|
|
49
|
+
let hasUnskippableSuites = false
|
|
50
|
+
let hasForcedToRunSuites = false
|
|
49
51
|
|
|
50
52
|
const sessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
51
53
|
|
|
@@ -205,15 +207,22 @@ addHook({
|
|
|
205
207
|
const [test] = shardedTests
|
|
206
208
|
const rootDir = test && test.context && test.context.config && test.context.config.rootDir
|
|
207
209
|
|
|
208
|
-
const
|
|
210
|
+
const jestSuitesToRun = getJestSuitesToRun(skippableSuites, shardedTests, rootDir || process.cwd())
|
|
209
211
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
+
log.debug(
|
|
213
|
+
() => `${jestSuitesToRun.suitesToRun.length} out of ${shardedTests.length} suites are going to run.`
|
|
214
|
+
)
|
|
212
215
|
|
|
213
|
-
|
|
216
|
+
hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
|
|
217
|
+
hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
|
|
218
|
+
|
|
219
|
+
isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== shardedTests.length
|
|
220
|
+
numSkippedSuites = jestSuitesToRun.skippedSuites.length
|
|
221
|
+
|
|
222
|
+
itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
|
|
214
223
|
|
|
215
224
|
skippableSuites = []
|
|
216
|
-
return suitesToRun
|
|
225
|
+
return jestSuitesToRun.suitesToRun
|
|
217
226
|
})
|
|
218
227
|
return sequencerPackage
|
|
219
228
|
})
|
|
@@ -268,7 +277,16 @@ function cliWrapper (cli, jestVersion) {
|
|
|
268
277
|
|
|
269
278
|
const result = await runCLI.apply(this, arguments)
|
|
270
279
|
|
|
271
|
-
const {
|
|
280
|
+
const {
|
|
281
|
+
results: {
|
|
282
|
+
success,
|
|
283
|
+
coverageMap,
|
|
284
|
+
numFailedTestSuites,
|
|
285
|
+
numFailedTests,
|
|
286
|
+
numTotalTests,
|
|
287
|
+
numTotalTestSuites
|
|
288
|
+
}
|
|
289
|
+
} = result
|
|
272
290
|
|
|
273
291
|
let testCodeCoverageLinesTotal
|
|
274
292
|
try {
|
|
@@ -277,15 +295,30 @@ function cliWrapper (cli, jestVersion) {
|
|
|
277
295
|
} catch (e) {
|
|
278
296
|
// ignore errors
|
|
279
297
|
}
|
|
298
|
+
let status, error
|
|
299
|
+
|
|
300
|
+
if (success) {
|
|
301
|
+
if (numTotalTests === 0 && numTotalTestSuites === 0) {
|
|
302
|
+
status = 'skip'
|
|
303
|
+
} else {
|
|
304
|
+
status = 'pass'
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
status = 'fail'
|
|
308
|
+
error = new Error(`Failed test suites: ${numFailedTestSuites}. Failed tests: ${numFailedTests}`)
|
|
309
|
+
}
|
|
280
310
|
|
|
281
311
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
282
312
|
testSessionFinishCh.publish({
|
|
283
|
-
status
|
|
313
|
+
status,
|
|
284
314
|
isSuitesSkipped,
|
|
285
315
|
isSuitesSkippingEnabled,
|
|
286
316
|
isCodeCoverageEnabled,
|
|
287
317
|
testCodeCoverageLinesTotal,
|
|
288
|
-
numSkippedSuites
|
|
318
|
+
numSkippedSuites,
|
|
319
|
+
hasUnskippableSuites,
|
|
320
|
+
hasForcedToRunSuites,
|
|
321
|
+
error
|
|
289
322
|
})
|
|
290
323
|
})
|
|
291
324
|
|
|
@@ -357,23 +390,23 @@ function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
|
357
390
|
status = 'fail'
|
|
358
391
|
}
|
|
359
392
|
|
|
360
|
-
const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
|
|
361
|
-
.map(filename => getTestSuitePath(filename, environment.rootDir))
|
|
362
|
-
|
|
363
393
|
/**
|
|
364
394
|
* Child processes do not each request ITR configuration, so the jest's parent process
|
|
365
395
|
* needs to pass them the configuration. This is done via _ddTestCodeCoverageEnabled, which
|
|
366
396
|
* controls whether coverage is reported.
|
|
367
|
-
|
|
368
|
-
if (
|
|
369
|
-
environment.
|
|
370
|
-
|
|
397
|
+
*/
|
|
398
|
+
if (environment.testEnvironmentOptions?._ddTestCodeCoverageEnabled) {
|
|
399
|
+
const coverageFiles = getCoveredFilenamesFromCoverage(environment.global.__coverage__)
|
|
400
|
+
.map(filename => getTestSuitePath(filename, environment.rootDir))
|
|
371
401
|
asyncResource.runInAsyncScope(() => {
|
|
372
402
|
testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
|
|
373
403
|
})
|
|
374
404
|
}
|
|
375
405
|
testSuiteFinishCh.publish({ status, errorMessage })
|
|
376
406
|
return suiteResults
|
|
407
|
+
}).catch(error => {
|
|
408
|
+
testSuiteFinishCh.publish({ status: 'fail', error })
|
|
409
|
+
throw error
|
|
377
410
|
})
|
|
378
411
|
})
|
|
379
412
|
})
|
|
@@ -500,16 +533,21 @@ addHook({
|
|
|
500
533
|
const testPaths = await getTestPaths.apply(this, arguments)
|
|
501
534
|
const { tests } = testPaths
|
|
502
535
|
|
|
503
|
-
const
|
|
536
|
+
const jestSuitesToRun = getJestSuitesToRun(skippableSuites, tests, rootDir)
|
|
537
|
+
|
|
538
|
+
log.debug(() => `${jestSuitesToRun.suitesToRun.length} out of ${tests.length} suites are going to run.`)
|
|
539
|
+
|
|
540
|
+
hasUnskippableSuites = jestSuitesToRun.hasUnskippableSuites
|
|
541
|
+
hasForcedToRunSuites = jestSuitesToRun.hasForcedToRunSuites
|
|
504
542
|
|
|
505
|
-
isSuitesSkipped = suitesToRun.length !== tests.length
|
|
506
|
-
numSkippedSuites = skippedSuites.length
|
|
543
|
+
isSuitesSkipped = jestSuitesToRun.suitesToRun.length !== tests.length
|
|
544
|
+
numSkippedSuites = jestSuitesToRun.skippedSuites.length
|
|
507
545
|
|
|
508
|
-
itrSkippedSuitesCh.publish({ skippedSuites, frameworkVersion })
|
|
546
|
+
itrSkippedSuitesCh.publish({ skippedSuites: jestSuitesToRun.skippedSuites, frameworkVersion })
|
|
509
547
|
|
|
510
548
|
skippableSuites = []
|
|
511
549
|
|
|
512
|
-
return { ...testPaths, tests: suitesToRun }
|
|
550
|
+
return { ...testPaths, tests: jestSuitesToRun.suitesToRun }
|
|
513
551
|
})
|
|
514
552
|
|
|
515
553
|
return searchSourcePackage
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { addHook } = require('./helpers/instrument')
|
|
3
|
+
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
4
|
const { wrapThen } = require('./helpers/promise')
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
6
|
|
|
7
|
+
const startRawQueryCh = channel('datadog:knex:raw:start')
|
|
8
|
+
const finishRawQueryCh = channel('datadog:knex:raw:finish')
|
|
9
|
+
|
|
7
10
|
patch('lib/query/builder.js')
|
|
8
11
|
patch('lib/raw.js')
|
|
9
12
|
patch('lib/schema/builder.js')
|
|
@@ -18,3 +21,68 @@ function patch (file) {
|
|
|
18
21
|
return Builder
|
|
19
22
|
})
|
|
20
23
|
}
|
|
24
|
+
|
|
25
|
+
addHook({
|
|
26
|
+
name: 'knex',
|
|
27
|
+
versions: ['>=2'],
|
|
28
|
+
file: 'lib/knex-builder/Knex.js'
|
|
29
|
+
}, Knex => {
|
|
30
|
+
shimmer.wrap(Knex.Client.prototype, 'raw', raw => function () {
|
|
31
|
+
if (!startRawQueryCh.hasSubscribers) {
|
|
32
|
+
return raw.apply(this, arguments)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sql = arguments[0]
|
|
36
|
+
|
|
37
|
+
// Skip query done by Knex to get the value used for undefined
|
|
38
|
+
if (sql === 'DEFAULT') {
|
|
39
|
+
return raw.apply(this, arguments)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
43
|
+
|
|
44
|
+
function finish () {
|
|
45
|
+
finishRawQueryCh.publish()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return asyncResource.runInAsyncScope(() => {
|
|
49
|
+
startRawQueryCh.publish({ sql, dialect: this.dialect })
|
|
50
|
+
|
|
51
|
+
const rawResult = raw.apply(this, arguments)
|
|
52
|
+
shimmer.wrap(rawResult, 'then', originalThen => function () {
|
|
53
|
+
return asyncResource.runInAsyncScope(() => {
|
|
54
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
55
|
+
if (arguments[1]) arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
|
|
56
|
+
|
|
57
|
+
const originalThenResult = originalThen.apply(this, arguments)
|
|
58
|
+
|
|
59
|
+
shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
|
|
60
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
61
|
+
return originalCatch.apply(this, arguments)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return originalThenResult
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
|
|
69
|
+
return asyncResource.runInAsyncScope(() => {
|
|
70
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
71
|
+
return originalAsCallback.apply(this, arguments)
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return rawResult
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
return Knex
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
function wrapCallbackWithFinish (callback, finish) {
|
|
82
|
+
if (typeof callback !== 'function') return callback
|
|
83
|
+
|
|
84
|
+
return function () {
|
|
85
|
+
finish()
|
|
86
|
+
callback.apply(this, arguments)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
const { createCoverageMap } = require('istanbul-lib-coverage')
|
|
2
2
|
|
|
3
|
+
const { isMarkedAsUnskippable } = require('../../datadog-plugin-jest/src/util')
|
|
4
|
+
|
|
3
5
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
6
|
const shimmer = require('../../datadog-shimmer')
|
|
5
7
|
const log = require('../../dd-trace/src/log')
|
|
6
|
-
|
|
7
8
|
const {
|
|
8
9
|
getCoveredFilenamesFromCoverage,
|
|
9
10
|
resetCoverage,
|
|
@@ -50,6 +51,8 @@ let suitesToSkip = []
|
|
|
50
51
|
let frameworkVersion
|
|
51
52
|
let isSuitesSkipped = false
|
|
52
53
|
let skippedSuites = []
|
|
54
|
+
const unskippableSuites = []
|
|
55
|
+
let isForcedToRun = false
|
|
53
56
|
|
|
54
57
|
function getSuitesByTestFile (root) {
|
|
55
58
|
const suitesByTestFile = {}
|
|
@@ -104,7 +107,8 @@ function getFilteredSuites (originalSuites) {
|
|
|
104
107
|
return originalSuites.reduce((acc, suite) => {
|
|
105
108
|
const testPath = getTestSuitePath(suite.file, process.cwd())
|
|
106
109
|
const shouldSkip = suitesToSkip.includes(testPath)
|
|
107
|
-
|
|
110
|
+
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
111
|
+
if (shouldSkip && !isUnskippable) {
|
|
108
112
|
acc.skippedSuites.add(testPath)
|
|
109
113
|
} else {
|
|
110
114
|
acc.suitesToRun.push(suite)
|
|
@@ -129,11 +133,20 @@ function mochaHook (Runner) {
|
|
|
129
133
|
|
|
130
134
|
this.once('end', testRunAsyncResource.bind(function () {
|
|
131
135
|
let status = 'pass'
|
|
136
|
+
let error
|
|
132
137
|
if (this.stats) {
|
|
133
138
|
status = this.stats.failures === 0 ? 'pass' : 'fail'
|
|
139
|
+
if (this.stats.tests === 0) {
|
|
140
|
+
status = 'skip'
|
|
141
|
+
}
|
|
134
142
|
} else if (this.failures !== 0) {
|
|
135
143
|
status = 'fail'
|
|
136
144
|
}
|
|
145
|
+
|
|
146
|
+
if (status === 'fail') {
|
|
147
|
+
error = new Error(`Failed tests: ${this.failures}.`)
|
|
148
|
+
}
|
|
149
|
+
|
|
137
150
|
testFileToSuiteAr.clear()
|
|
138
151
|
|
|
139
152
|
let testCodeCoverageLinesTotal
|
|
@@ -151,7 +164,10 @@ function mochaHook (Runner) {
|
|
|
151
164
|
status,
|
|
152
165
|
isSuitesSkipped,
|
|
153
166
|
testCodeCoverageLinesTotal,
|
|
154
|
-
numSkippedSuites: skippedSuites.length
|
|
167
|
+
numSkippedSuites: skippedSuites.length,
|
|
168
|
+
hasForcedToRunSuites: isForcedToRun,
|
|
169
|
+
hasUnskippableSuites: !!unskippableSuites.length,
|
|
170
|
+
error
|
|
155
171
|
})
|
|
156
172
|
}))
|
|
157
173
|
|
|
@@ -172,8 +188,10 @@ function mochaHook (Runner) {
|
|
|
172
188
|
if (!asyncResource) {
|
|
173
189
|
asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
174
190
|
testFileToSuiteAr.set(suite.file, asyncResource)
|
|
191
|
+
const isUnskippable = unskippableSuites.includes(suite.file)
|
|
192
|
+
isForcedToRun = isUnskippable && suitesToSkip.includes(getTestSuitePath(suite.file, process.cwd()))
|
|
175
193
|
asyncResource.runInAsyncScope(() => {
|
|
176
|
-
testSuiteStartCh.publish(suite)
|
|
194
|
+
testSuiteStartCh.publish({ testSuite: suite.file, isUnskippable, isForcedToRun })
|
|
177
195
|
})
|
|
178
196
|
}
|
|
179
197
|
})
|
|
@@ -370,6 +388,13 @@ addHook({
|
|
|
370
388
|
|
|
371
389
|
const runner = run.apply(this, arguments)
|
|
372
390
|
|
|
391
|
+
this.files.forEach(path => {
|
|
392
|
+
const isUnskippable = isMarkedAsUnskippable({ path })
|
|
393
|
+
if (isUnskippable) {
|
|
394
|
+
unskippableSuites.push(path)
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
|
|
373
398
|
const onReceivedSkippableSuites = ({ err, skippableSuites }) => {
|
|
374
399
|
if (err) {
|
|
375
400
|
suitesToSkip = []
|
|
@@ -381,6 +406,11 @@ addHook({
|
|
|
381
406
|
const { suitesToRun } = filteredSuites
|
|
382
407
|
|
|
383
408
|
isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
|
|
409
|
+
|
|
410
|
+
log.debug(
|
|
411
|
+
() => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
|
|
412
|
+
)
|
|
413
|
+
|
|
384
414
|
runner.suite.suites = suitesToRun
|
|
385
415
|
|
|
386
416
|
skippedSuites = Array.from(filteredSuites.skippedSuites)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
require('./mongodb-core')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
channel,
|
|
7
|
+
addHook,
|
|
8
|
+
AsyncResource
|
|
9
|
+
} = require('./helpers/instrument')
|
|
10
|
+
const shimmer = require('../../datadog-shimmer')
|
|
11
|
+
|
|
12
|
+
// collection methods with filter
|
|
13
|
+
const collectionMethodsWithFilter = [
|
|
14
|
+
'count',
|
|
15
|
+
'countDocuments',
|
|
16
|
+
'deleteMany',
|
|
17
|
+
'deleteOne',
|
|
18
|
+
'find',
|
|
19
|
+
'findOneAndDelete',
|
|
20
|
+
'findOneAndReplace',
|
|
21
|
+
'replaceOne'
|
|
22
|
+
] // findOne is ignored because it calls to find
|
|
23
|
+
|
|
24
|
+
const collectionMethodsWithTwoFilters = [
|
|
25
|
+
'findOneAndUpdate',
|
|
26
|
+
'updateMany',
|
|
27
|
+
'updateOne'
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const startCh = channel('datadog:mongodb:collection:filter:start')
|
|
31
|
+
|
|
32
|
+
addHook({ name: 'mongodb', versions: ['>=3.3 <5', '5', '>=6'] }, mongodb => {
|
|
33
|
+
[...collectionMethodsWithFilter, ...collectionMethodsWithTwoFilters].forEach(methodName => {
|
|
34
|
+
if (!(methodName in mongodb.Collection.prototype)) return
|
|
35
|
+
|
|
36
|
+
const useTwoArguments = collectionMethodsWithTwoFilters.includes(methodName)
|
|
37
|
+
|
|
38
|
+
shimmer.wrap(mongodb.Collection.prototype, methodName, method => {
|
|
39
|
+
return function () {
|
|
40
|
+
if (!startCh.hasSubscribers) {
|
|
41
|
+
return method.apply(this, arguments)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
45
|
+
|
|
46
|
+
return asyncResource.runInAsyncScope(() => {
|
|
47
|
+
const filters = [arguments[0]]
|
|
48
|
+
if (useTwoArguments) {
|
|
49
|
+
filters.push(arguments[1])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
startCh.publish({
|
|
53
|
+
filters,
|
|
54
|
+
methodName
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return method.apply(this, arguments)
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
return mongodb
|
|
63
|
+
})
|