dd-trace 2.5.0 → 2.6.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/index.d.ts +17 -1
- package/package.json +4 -4
- package/packages/datadog-instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +170 -0
- package/packages/datadog-plugin-cucumber/src/index.js +9 -21
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -17
- package/packages/datadog-plugin-fs/src/index.js +2 -0
- package/packages/datadog-plugin-http/src/server.js +0 -8
- package/packages/datadog-plugin-jest/src/index.js +101 -3
- package/packages/datadog-plugin-jest/src/util.js +1 -29
- package/packages/datadog-plugin-mocha/src/index.js +5 -15
- package/packages/dd-trace/lib/version.js +1 -1
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +26 -11
- package/packages/dd-trace/src/appsec/index.js +7 -3
- package/packages/dd-trace/src/appsec/reporter.js +29 -3
- package/packages/dd-trace/src/appsec/rule_manager.js +2 -2
- package/packages/dd-trace/src/config.js +25 -3
- package/packages/dd-trace/src/format.js +9 -5
- package/packages/dd-trace/src/plugins/util/test.js +20 -1
- package/packages/dd-trace/src/plugins/util/web.js +11 -10
- package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
- package/packages/dd-trace/src/span_processor.js +4 -1
- package/scripts/install_plugin_modules.js +1 -0
- package/packages/datadog-plugin-jest/src/jest-environment.js +0 -272
- package/packages/datadog-plugin-jest/src/jest-jasmine2.js +0 -185
|
@@ -35,6 +35,8 @@ const RESPONSE_HEADERS_PASSLIST = [
|
|
|
35
35
|
'content-type'
|
|
36
36
|
]
|
|
37
37
|
|
|
38
|
+
const metricsQueue = new Map()
|
|
39
|
+
|
|
38
40
|
function resolveHTTPRequest (context) {
|
|
39
41
|
if (!context) return {}
|
|
40
42
|
|
|
@@ -82,6 +84,20 @@ function formatHeaderName (name) {
|
|
|
82
84
|
.toLowerCase()
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
function reportMetrics (metrics, store) {
|
|
88
|
+
const req = store && store.get('req')
|
|
89
|
+
const topSpan = web.root(req)
|
|
90
|
+
if (!topSpan) return false
|
|
91
|
+
|
|
92
|
+
if (metrics.duration) {
|
|
93
|
+
topSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (metrics.rulesVersion) {
|
|
97
|
+
topSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
85
101
|
function reportAttack (attackData, store) {
|
|
86
102
|
const req = store && store.get('req')
|
|
87
103
|
const topSpan = web.root(req)
|
|
@@ -129,9 +145,17 @@ function reportAttack (attackData, store) {
|
|
|
129
145
|
topSpan.addTags(newTags)
|
|
130
146
|
}
|
|
131
147
|
|
|
132
|
-
function
|
|
148
|
+
function finishRequest (req, context) {
|
|
133
149
|
const topSpan = web.root(req)
|
|
134
|
-
if (!topSpan
|
|
150
|
+
if (!topSpan) return false
|
|
151
|
+
|
|
152
|
+
if (metricsQueue.size) {
|
|
153
|
+
topSpan.addTags(Object.fromEntries(metricsQueue))
|
|
154
|
+
|
|
155
|
+
metricsQueue.clear()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!context || !topSpan.context()._tags['appsec.event']) return false
|
|
135
159
|
|
|
136
160
|
const resolvedResponse = resolveHTTPResponse(context)
|
|
137
161
|
|
|
@@ -149,11 +173,13 @@ function setRateLimit (rateLimit) {
|
|
|
149
173
|
}
|
|
150
174
|
|
|
151
175
|
module.exports = {
|
|
176
|
+
metricsQueue,
|
|
152
177
|
resolveHTTPRequest,
|
|
153
178
|
resolveHTTPResponse,
|
|
154
179
|
filterHeaders,
|
|
155
180
|
formatHeaderName,
|
|
181
|
+
reportMetrics,
|
|
156
182
|
reportAttack,
|
|
157
|
-
|
|
183
|
+
finishRequest,
|
|
158
184
|
setRateLimit
|
|
159
185
|
}
|
|
@@ -4,11 +4,11 @@ const callbacks = require('./callbacks')
|
|
|
4
4
|
|
|
5
5
|
const appliedCallbacks = new Map()
|
|
6
6
|
|
|
7
|
-
function applyRules (rules) {
|
|
7
|
+
function applyRules (rules, config) {
|
|
8
8
|
if (appliedCallbacks.has(rules)) return
|
|
9
9
|
|
|
10
10
|
// for now there is only WAF
|
|
11
|
-
const callback = new callbacks.DDWAF(rules)
|
|
11
|
+
const callback = new callbacks.DDWAF(rules, config)
|
|
12
12
|
|
|
13
13
|
appliedCallbacks.set(rules, callback)
|
|
14
14
|
}
|
|
@@ -150,10 +150,29 @@ class Config {
|
|
|
150
150
|
path.join(__dirname, 'appsec', 'recommended.json')
|
|
151
151
|
)
|
|
152
152
|
const DD_APPSEC_TRACE_RATE_LIMIT = coalesce(
|
|
153
|
-
appsec.rateLimit,
|
|
154
|
-
process.env.DD_APPSEC_TRACE_RATE_LIMIT,
|
|
153
|
+
parseInt(appsec.rateLimit),
|
|
154
|
+
parseInt(process.env.DD_APPSEC_TRACE_RATE_LIMIT),
|
|
155
155
|
100
|
|
156
156
|
)
|
|
157
|
+
const DD_APPSEC_WAF_TIMEOUT = coalesce(
|
|
158
|
+
parseInt(appsec.wafTimeout),
|
|
159
|
+
parseInt(process.env.DD_APPSEC_WAF_TIMEOUT),
|
|
160
|
+
5e3 // µs
|
|
161
|
+
)
|
|
162
|
+
const DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP = coalesce(
|
|
163
|
+
appsec.obfuscatorKeyRegex,
|
|
164
|
+
process.env.DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
|
|
165
|
+
`(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?)key)|token|consumer_?(?:id|key|se\
|
|
166
|
+
cret)|sign(?:ed|ature)|bearer|authorization`
|
|
167
|
+
)
|
|
168
|
+
const DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP = coalesce(
|
|
169
|
+
appsec.obfuscatorValueRegex,
|
|
170
|
+
process.env.DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
|
|
171
|
+
`(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|to\
|
|
172
|
+
ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\
|
|
173
|
+
\\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?\
|
|
174
|
+
|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}`
|
|
175
|
+
)
|
|
157
176
|
|
|
158
177
|
const sampler = (options.experimental && options.experimental.sampler) || {}
|
|
159
178
|
const ingestion = options.ingestion || {}
|
|
@@ -223,7 +242,10 @@ class Config {
|
|
|
223
242
|
this.appsec = {
|
|
224
243
|
enabled: isTrue(DD_APPSEC_ENABLED),
|
|
225
244
|
rules: DD_APPSEC_RULES,
|
|
226
|
-
rateLimit: DD_APPSEC_TRACE_RATE_LIMIT
|
|
245
|
+
rateLimit: DD_APPSEC_TRACE_RATE_LIMIT,
|
|
246
|
+
wafTimeout: DD_APPSEC_WAF_TIMEOUT,
|
|
247
|
+
obfuscatorKeyRegex: DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP,
|
|
248
|
+
obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP
|
|
227
249
|
}
|
|
228
250
|
|
|
229
251
|
tagger.add(this.tags, {
|
|
@@ -22,7 +22,6 @@ const map = {
|
|
|
22
22
|
function format (span) {
|
|
23
23
|
const formatted = formatSpan(span)
|
|
24
24
|
|
|
25
|
-
extractError(formatted, span)
|
|
26
25
|
extractRootTags(formatted, span)
|
|
27
26
|
extractChunkTags(formatted, span)
|
|
28
27
|
extractTags(formatted, span)
|
|
@@ -74,8 +73,8 @@ function extractTags (trace, span) {
|
|
|
74
73
|
addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
|
|
75
74
|
break
|
|
76
75
|
case 'error':
|
|
77
|
-
if (
|
|
78
|
-
trace
|
|
76
|
+
if (context._name !== 'fs.operation') {
|
|
77
|
+
extractError(trace, tags[tag])
|
|
79
78
|
}
|
|
80
79
|
break
|
|
81
80
|
case 'error.type':
|
|
@@ -84,6 +83,8 @@ function extractTags (trace, span) {
|
|
|
84
83
|
// HACK: remove when implemented in the backend
|
|
85
84
|
if (context._name !== 'fs.operation') {
|
|
86
85
|
trace.error = 1
|
|
86
|
+
} else {
|
|
87
|
+
break
|
|
87
88
|
}
|
|
88
89
|
default: // eslint-disable-line no-fallthrough
|
|
89
90
|
addTag(trace.meta, trace.metrics, tag, tags[tag])
|
|
@@ -122,8 +123,11 @@ function extractChunkTags (trace, span) {
|
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
function extractError (trace,
|
|
126
|
-
|
|
126
|
+
function extractError (trace, error) {
|
|
127
|
+
if (!error) return
|
|
128
|
+
|
|
129
|
+
trace.error = 1
|
|
130
|
+
|
|
127
131
|
if (isError(error)) {
|
|
128
132
|
addTag(trace.meta, trace.metrics, 'error.msg', error.message)
|
|
129
133
|
addTag(trace.meta, trace.metrics, 'error.type', error.name)
|
|
@@ -19,6 +19,10 @@ const {
|
|
|
19
19
|
} = require('./tags')
|
|
20
20
|
const id = require('../../id')
|
|
21
21
|
|
|
22
|
+
const { SPAN_TYPE, RESOURCE_NAME, SAMPLING_PRIORITY } = require('../../../../../ext/tags')
|
|
23
|
+
const { SAMPLING_RULE_DECISION } = require('../../constants')
|
|
24
|
+
const { AUTO_KEEP } = require('../../../../../ext/priority')
|
|
25
|
+
|
|
22
26
|
const TEST_FRAMEWORK = 'test.framework'
|
|
23
27
|
const TEST_FRAMEWORK_VERSION = 'test.framework_version'
|
|
24
28
|
const TEST_TYPE = 'test.type'
|
|
@@ -60,7 +64,8 @@ module.exports = {
|
|
|
60
64
|
getTestParentSpan,
|
|
61
65
|
getTestSuitePath,
|
|
62
66
|
getCodeOwnersFileEntries,
|
|
63
|
-
getCodeOwnersForFilename
|
|
67
|
+
getCodeOwnersForFilename,
|
|
68
|
+
getTestCommonTags
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
function getTestEnvironmentMetadata (testFramework, config) {
|
|
@@ -134,6 +139,20 @@ function getTestParentSpan (tracer) {
|
|
|
134
139
|
'x-datadog-parent-id': '0000000000000000'
|
|
135
140
|
})
|
|
136
141
|
}
|
|
142
|
+
|
|
143
|
+
function getTestCommonTags (name, suite, version) {
|
|
144
|
+
return {
|
|
145
|
+
[SPAN_TYPE]: 'test',
|
|
146
|
+
[TEST_TYPE]: 'test',
|
|
147
|
+
[SAMPLING_RULE_DECISION]: 1,
|
|
148
|
+
[SAMPLING_PRIORITY]: AUTO_KEEP,
|
|
149
|
+
[TEST_NAME]: name,
|
|
150
|
+
[TEST_SUITE]: suite,
|
|
151
|
+
[RESOURCE_NAME]: `${suite}.${name}`,
|
|
152
|
+
[TEST_FRAMEWORK_VERSION]: version
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
137
156
|
/**
|
|
138
157
|
* We want to make sure that test suites are reported the same way for
|
|
139
158
|
* every OS, so we replace `path.sep` by `/`
|
|
@@ -69,6 +69,17 @@ const web = {
|
|
|
69
69
|
context.span = span
|
|
70
70
|
context.res = res
|
|
71
71
|
|
|
72
|
+
if (!config.filter(req.url)) {
|
|
73
|
+
span.setTag(MANUAL_DROP, true)
|
|
74
|
+
span.context()._trace.isRecording = false
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (config.service) {
|
|
78
|
+
span.setTag(SERVICE_NAME, config.service)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
analyticsSampler.sample(span, config.measured, true)
|
|
82
|
+
|
|
72
83
|
return span
|
|
73
84
|
},
|
|
74
85
|
wrap (req) {
|
|
@@ -83,16 +94,6 @@ const web = {
|
|
|
83
94
|
instrument (tracer, config, req, res, name, callback) {
|
|
84
95
|
const span = this.startSpan(tracer, config, req, res, name)
|
|
85
96
|
|
|
86
|
-
if (!config.filter(req.url)) {
|
|
87
|
-
span.setTag(MANUAL_DROP, true)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (config.service) {
|
|
91
|
-
span.setTag(SERVICE_NAME, config.service)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
analyticsSampler.sample(span, config.measured, true)
|
|
95
|
-
|
|
96
97
|
this.wrap(req)
|
|
97
98
|
|
|
98
99
|
return callback && tracer.scope().activate(span, () => callback(span))
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
class NativeCpuProfiler {
|
|
4
4
|
constructor (options = {}) {
|
|
5
5
|
this.type = 'wall'
|
|
6
|
-
this._samplingInterval = options.samplingInterval ||
|
|
6
|
+
this._samplingInterval = options.samplingInterval || 1e6 / 99 // 99hz
|
|
7
7
|
this._mapper = undefined
|
|
8
8
|
this._pprof = undefined
|
|
9
9
|
}
|
|
@@ -186,6 +186,7 @@ const requirePackageJson = require('${requirePackageJsonPath}')
|
|
|
186
186
|
|
|
187
187
|
module.exports = {
|
|
188
188
|
get (id) { return require(id || '${name}') },
|
|
189
|
+
getPath (id) { return require.resolve(id || '${name}' ) },
|
|
189
190
|
version () { return requirePackageJson('${name}', module).version }
|
|
190
191
|
}
|
|
191
192
|
`
|
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
const { promisify } = require('util')
|
|
2
|
-
|
|
3
|
-
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
4
|
-
const {
|
|
5
|
-
TEST_NAME,
|
|
6
|
-
TEST_SUITE,
|
|
7
|
-
TEST_STATUS,
|
|
8
|
-
TEST_FRAMEWORK_VERSION,
|
|
9
|
-
JEST_TEST_RUNNER,
|
|
10
|
-
ERROR_MESSAGE,
|
|
11
|
-
ERROR_TYPE,
|
|
12
|
-
TEST_PARAMETERS,
|
|
13
|
-
CI_APP_ORIGIN,
|
|
14
|
-
getTestEnvironmentMetadata,
|
|
15
|
-
getTestParametersString,
|
|
16
|
-
finishAllTraceSpans,
|
|
17
|
-
getTestSuitePath
|
|
18
|
-
} = require('../../dd-trace/src/plugins/util/test')
|
|
19
|
-
const {
|
|
20
|
-
getFormattedJestTestParameters,
|
|
21
|
-
getTestSpanTags,
|
|
22
|
-
setSuppressedErrors
|
|
23
|
-
} = require('./util')
|
|
24
|
-
|
|
25
|
-
const originals = new WeakMap()
|
|
26
|
-
|
|
27
|
-
function getVmContext (environment) {
|
|
28
|
-
if (typeof environment.getVmContext === 'function') {
|
|
29
|
-
return environment.getVmContext()
|
|
30
|
-
}
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function wrapEnvironment (BaseEnvironment) {
|
|
35
|
-
return class DatadogJestEnvironment extends BaseEnvironment {
|
|
36
|
-
constructor (config, context) {
|
|
37
|
-
super(config, context)
|
|
38
|
-
this.testSuite = getTestSuitePath(context.testPath, config.rootDir)
|
|
39
|
-
this.testSpansByTestName = {}
|
|
40
|
-
this.originalTestFnByTestName = {}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function createWrapTeardown (tracer, instrumenter) {
|
|
46
|
-
return function wrapTeardown (teardown) {
|
|
47
|
-
return async function teardownWithTrace () {
|
|
48
|
-
instrumenter.unwrap(this.global.test, 'each')
|
|
49
|
-
nameToParams = {}
|
|
50
|
-
// for jest-jasmine2
|
|
51
|
-
if (this.global.jasmine) {
|
|
52
|
-
instrumenter.unwrap(this.global.jasmine.Spec.prototype, 'onException')
|
|
53
|
-
instrumenter.unwrap(this.global, 'it')
|
|
54
|
-
instrumenter.unwrap(this.global, 'fit')
|
|
55
|
-
instrumenter.unwrap(this.global, 'xit')
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
instrumenter.unwrap(this.global.test, 'each')
|
|
59
|
-
|
|
60
|
-
return teardown.apply(this, arguments).finally(() => {
|
|
61
|
-
return new Promise(resolve => tracer._exporter._writer.flush(resolve))
|
|
62
|
-
})
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let nameToParams = {}
|
|
68
|
-
|
|
69
|
-
const isTimeout = (event) => {
|
|
70
|
-
return event.error &&
|
|
71
|
-
typeof event.error === 'string' &&
|
|
72
|
-
event.error.startsWith('Exceeded timeout')
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function createHandleTestEvent (tracer, testEnvironmentMetadata, instrumenter) {
|
|
76
|
-
return async function handleTestEventWithTrace (event) {
|
|
77
|
-
if (event.name === 'test_retry') {
|
|
78
|
-
let testName = event.test && event.test.name
|
|
79
|
-
const context = getVmContext(this)
|
|
80
|
-
if (context) {
|
|
81
|
-
const { currentTestName } = context.expect.getState()
|
|
82
|
-
testName = currentTestName
|
|
83
|
-
}
|
|
84
|
-
// If it's a retry, we restore the original test function so that it is not wrapped again
|
|
85
|
-
if (this.originalTestFnByTestName[testName]) {
|
|
86
|
-
event.test.fn = this.originalTestFnByTestName[testName]
|
|
87
|
-
}
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
if (event.name === 'test_fn_failure') {
|
|
91
|
-
if (!isTimeout(event)) {
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
const context = getVmContext(this)
|
|
95
|
-
if (context) {
|
|
96
|
-
const { currentTestName } = context.expect.getState()
|
|
97
|
-
const testSpan = this.testSpansByTestName[`${currentTestName}_${event.test.invocations}`]
|
|
98
|
-
if (testSpan) {
|
|
99
|
-
testSpan.setTag(ERROR_TYPE, 'Timeout')
|
|
100
|
-
testSpan.setTag(ERROR_MESSAGE, event.error)
|
|
101
|
-
testSpan.setTag(TEST_STATUS, 'fail')
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return
|
|
105
|
-
}
|
|
106
|
-
if (event.name === 'setup') {
|
|
107
|
-
instrumenter.wrap(this.global.test, 'each', function (original) {
|
|
108
|
-
return function () {
|
|
109
|
-
const testParameters = getFormattedJestTestParameters(arguments)
|
|
110
|
-
const eachBind = original.apply(this, arguments)
|
|
111
|
-
return function () {
|
|
112
|
-
const [testName] = arguments
|
|
113
|
-
nameToParams[testName] = testParameters
|
|
114
|
-
return eachBind.apply(this, arguments)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
})
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (event.name !== 'test_skip' &&
|
|
122
|
-
event.name !== 'test_todo' &&
|
|
123
|
-
event.name !== 'test_start' &&
|
|
124
|
-
event.name !== 'hook_failure') {
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
// for hook_failure events the test entry might not be defined, because the hook
|
|
128
|
-
// is not necessarily associated to a test:
|
|
129
|
-
if (!event.test) {
|
|
130
|
-
return
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const { childOf, commonSpanTags } = getTestSpanTags(tracer, testEnvironmentMetadata)
|
|
134
|
-
|
|
135
|
-
let testName = event.test.name
|
|
136
|
-
const context = getVmContext(this)
|
|
137
|
-
|
|
138
|
-
if (context) {
|
|
139
|
-
const { currentTestName } = context.expect.getState()
|
|
140
|
-
testName = currentTestName
|
|
141
|
-
}
|
|
142
|
-
const spanTags = {
|
|
143
|
-
...commonSpanTags,
|
|
144
|
-
[TEST_NAME]: testName,
|
|
145
|
-
[TEST_SUITE]: this.testSuite,
|
|
146
|
-
[TEST_FRAMEWORK_VERSION]: tracer._version,
|
|
147
|
-
[JEST_TEST_RUNNER]: 'jest-circus'
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const testParametersString = getTestParametersString(nameToParams, event.test.name)
|
|
151
|
-
if (testParametersString) {
|
|
152
|
-
spanTags[TEST_PARAMETERS] = testParametersString
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const resource = `${this.testSuite}.${testName}`
|
|
156
|
-
if (event.name === 'test_skip' || event.name === 'test_todo') {
|
|
157
|
-
const testSpan = tracer.startSpan(
|
|
158
|
-
'jest.test',
|
|
159
|
-
{
|
|
160
|
-
childOf,
|
|
161
|
-
tags: {
|
|
162
|
-
...spanTags,
|
|
163
|
-
[RESOURCE_NAME]: resource,
|
|
164
|
-
[TEST_STATUS]: 'skip'
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
)
|
|
168
|
-
testSpan.context()._trace.origin = CI_APP_ORIGIN
|
|
169
|
-
testSpan.finish()
|
|
170
|
-
return
|
|
171
|
-
}
|
|
172
|
-
if (event.name === 'hook_failure') {
|
|
173
|
-
const testSpan = tracer.startSpan(
|
|
174
|
-
'jest.test',
|
|
175
|
-
{
|
|
176
|
-
childOf,
|
|
177
|
-
tags: {
|
|
178
|
-
...spanTags,
|
|
179
|
-
[RESOURCE_NAME]: resource,
|
|
180
|
-
[TEST_STATUS]: 'fail'
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
)
|
|
184
|
-
testSpan.context()._trace.origin = CI_APP_ORIGIN
|
|
185
|
-
if (event.test.errors && event.test.errors.length) {
|
|
186
|
-
const error = new Error(event.test.errors[0][0])
|
|
187
|
-
error.stack = event.test.errors[0][1].stack
|
|
188
|
-
testSpan.setTag('error', error)
|
|
189
|
-
}
|
|
190
|
-
testSpan.finish()
|
|
191
|
-
return
|
|
192
|
-
}
|
|
193
|
-
// event.name === test_start at this point
|
|
194
|
-
const environment = this
|
|
195
|
-
environment.originalTestFnByTestName[testName] = event.test.fn
|
|
196
|
-
|
|
197
|
-
let specFunction = event.test.fn
|
|
198
|
-
if (specFunction.length) {
|
|
199
|
-
specFunction = promisify(specFunction)
|
|
200
|
-
}
|
|
201
|
-
event.test.fn = tracer.wrap(
|
|
202
|
-
'jest.test',
|
|
203
|
-
{
|
|
204
|
-
type: 'test',
|
|
205
|
-
childOf,
|
|
206
|
-
resource,
|
|
207
|
-
tags: spanTags
|
|
208
|
-
},
|
|
209
|
-
async () => {
|
|
210
|
-
let result
|
|
211
|
-
const testSpan = tracer.scope().active()
|
|
212
|
-
environment.testSpansByTestName[`${testName}_${event.test.invocations}`] = testSpan
|
|
213
|
-
testSpan.context()._trace.origin = CI_APP_ORIGIN
|
|
214
|
-
try {
|
|
215
|
-
result = await specFunction()
|
|
216
|
-
// it may have been set already if the test timed out
|
|
217
|
-
let suppressedErrors = []
|
|
218
|
-
const context = getVmContext(environment)
|
|
219
|
-
if (context) {
|
|
220
|
-
suppressedErrors = context.expect.getState().suppressedErrors
|
|
221
|
-
}
|
|
222
|
-
setSuppressedErrors(suppressedErrors, testSpan)
|
|
223
|
-
if (!testSpan._spanContext._tags[TEST_STATUS]) {
|
|
224
|
-
testSpan.setTag(TEST_STATUS, 'pass')
|
|
225
|
-
}
|
|
226
|
-
} catch (error) {
|
|
227
|
-
testSpan.setTag(TEST_STATUS, 'fail')
|
|
228
|
-
testSpan.setTag('error', error)
|
|
229
|
-
throw error
|
|
230
|
-
} finally {
|
|
231
|
-
finishAllTraceSpans(testSpan)
|
|
232
|
-
}
|
|
233
|
-
return result
|
|
234
|
-
}
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function patch (Environment, tracer, config) {
|
|
240
|
-
const testEnvironmentMetadata = getTestEnvironmentMetadata('jest', config)
|
|
241
|
-
const proto = Environment.prototype
|
|
242
|
-
|
|
243
|
-
this.wrap(proto, 'teardown', createWrapTeardown(tracer, this))
|
|
244
|
-
|
|
245
|
-
const newHandleTestEvent = createHandleTestEvent(tracer, testEnvironmentMetadata, this)
|
|
246
|
-
originals.set(newHandleTestEvent, proto.handleTestEvent)
|
|
247
|
-
proto.handleTestEvent = newHandleTestEvent
|
|
248
|
-
|
|
249
|
-
return wrapEnvironment(Environment)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function unpatch (Environment) {
|
|
253
|
-
const proto = Environment.prototype
|
|
254
|
-
|
|
255
|
-
this.unwrap(Environment.prototype, 'teardown')
|
|
256
|
-
proto.handleTestEvent = originals.get(proto.handleTestEvent)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
module.exports = [
|
|
260
|
-
{
|
|
261
|
-
name: 'jest-environment-node',
|
|
262
|
-
versions: ['>=24.8.0'],
|
|
263
|
-
patch,
|
|
264
|
-
unpatch
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
name: 'jest-environment-jsdom',
|
|
268
|
-
versions: ['>=24.8.0'],
|
|
269
|
-
patch,
|
|
270
|
-
unpatch
|
|
271
|
-
}
|
|
272
|
-
]
|