dd-trace 4.0.0-pre-5d09d34 → 4.0.0-pre-2e8aecc
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 +20 -0
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +74 -15
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +16 -22
- package/packages/datadog-instrumentations/src/mocha.js +4 -4
- package/packages/datadog-instrumentations/src/playwright.js +2 -4
- package/packages/datadog-plugin-cucumber/src/index.js +98 -11
- package/packages/datadog-plugin-cypress/src/plugin.js +119 -3
- package/packages/datadog-plugin-cypress/src/support.js +5 -0
- package/packages/datadog-plugin-jest/src/index.js +9 -8
- package/packages/datadog-plugin-mocha/src/index.js +4 -2
- package/packages/datadog-plugin-playwright/src/index.js +2 -1
- package/packages/dd-trace/src/appsec/reporter.js +14 -14
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +1 -1
- package/packages/dd-trace/src/config.js +55 -6
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/encode/0.5.js +1 -1
- package/packages/dd-trace/src/encode/tags-processors.js +3 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +186 -36
- package/packages/dd-trace/src/opentracing/propagation/tracestate.js +99 -0
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +1 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +4 -1
package/index.d.ts
CHANGED
|
@@ -221,6 +221,21 @@ export declare interface SpanSamplingRule {
|
|
|
221
221
|
name?: string
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
/**
|
|
225
|
+
* Selection and priority order of context propagation injection and extraction mechanisms.
|
|
226
|
+
*/
|
|
227
|
+
export declare interface PropagationStyle {
|
|
228
|
+
/**
|
|
229
|
+
* Selection of context propagation injection mechanisms.
|
|
230
|
+
*/
|
|
231
|
+
inject: string[],
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Selection and priority order of context propagation extraction mechanisms.
|
|
235
|
+
*/
|
|
236
|
+
extract: string[]
|
|
237
|
+
}
|
|
238
|
+
|
|
224
239
|
/**
|
|
225
240
|
* List of options available to the tracer.
|
|
226
241
|
*/
|
|
@@ -550,6 +565,11 @@ export declare interface TracerOptions {
|
|
|
550
565
|
* Custom header name to source the http.client_ip tag from.
|
|
551
566
|
*/
|
|
552
567
|
clientIpHeader?: string,
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* The selection and priority order of context propagation injection and extraction mechanisms.
|
|
571
|
+
*/
|
|
572
|
+
propagationStyle?: string[] | PropagationStyle
|
|
553
573
|
}
|
|
554
574
|
|
|
555
575
|
/**
|
package/package.json
CHANGED
|
@@ -3,15 +3,35 @@
|
|
|
3
3
|
const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
6
|
+
const testStartCh = channel('ci:cucumber:test:start')
|
|
7
|
+
const testFinishCh = channel('ci:cucumber:test:finish') // used for test steps too
|
|
8
|
+
|
|
9
|
+
const testStepStartCh = channel('ci:cucumber:test-step:start')
|
|
10
|
+
|
|
9
11
|
const errorCh = channel('ci:cucumber:error')
|
|
12
|
+
|
|
13
|
+
const testSuiteStartCh = channel('ci:cucumber:test-suite:start')
|
|
14
|
+
const testSuiteFinishCh = channel('ci:cucumber:test-suite:finish')
|
|
15
|
+
|
|
16
|
+
const sessionStartCh = channel('ci:cucumber:session:start')
|
|
10
17
|
const sessionFinishCh = channel('ci:cucumber:session:finish')
|
|
11
18
|
|
|
12
19
|
// TODO: remove in a later major version
|
|
13
20
|
const patched = new WeakSet()
|
|
14
21
|
|
|
22
|
+
let pickleByFile = {}
|
|
23
|
+
const pickleResultByFile = {}
|
|
24
|
+
|
|
25
|
+
function getSuiteStatusFromTestStatuses (testStatuses) {
|
|
26
|
+
if (testStatuses.some(status => status === 'fail')) {
|
|
27
|
+
return 'fail'
|
|
28
|
+
}
|
|
29
|
+
if (testStatuses.every(status => status === 'skip')) {
|
|
30
|
+
return 'skip'
|
|
31
|
+
}
|
|
32
|
+
return 'pass'
|
|
33
|
+
}
|
|
34
|
+
|
|
15
35
|
function getStatusFromResult (result) {
|
|
16
36
|
if (result.status === 1) {
|
|
17
37
|
return { status: 'pass' }
|
|
@@ -44,13 +64,18 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
44
64
|
patched.add(pl)
|
|
45
65
|
|
|
46
66
|
shimmer.wrap(pl.prototype, 'run', run => function () {
|
|
47
|
-
if (!
|
|
67
|
+
if (!testStartCh.hasSubscribers) {
|
|
48
68
|
return run.apply(this, arguments)
|
|
49
69
|
}
|
|
50
70
|
|
|
51
71
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
52
72
|
return asyncResource.runInAsyncScope(() => {
|
|
53
|
-
|
|
73
|
+
const testSuiteFullPath = this.pickle.uri
|
|
74
|
+
|
|
75
|
+
if (!pickleResultByFile[testSuiteFullPath]) { // first test in suite
|
|
76
|
+
testSuiteStartCh.publish(testSuiteFullPath)
|
|
77
|
+
}
|
|
78
|
+
testStartCh.publish({ testName: this.pickle.name, fullTestSuite: testSuiteFullPath })
|
|
54
79
|
try {
|
|
55
80
|
const promise = run.apply(this, arguments)
|
|
56
81
|
promise.finally(() => {
|
|
@@ -58,7 +83,17 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
58
83
|
const { status, skipReason, errorMessage } = isLatestVersion
|
|
59
84
|
? getStatusFromResultLatest(result) : getStatusFromResult(result)
|
|
60
85
|
|
|
61
|
-
|
|
86
|
+
if (!pickleResultByFile[testSuiteFullPath]) {
|
|
87
|
+
pickleResultByFile[testSuiteFullPath] = [status]
|
|
88
|
+
} else {
|
|
89
|
+
pickleResultByFile[testSuiteFullPath].push(status)
|
|
90
|
+
}
|
|
91
|
+
// last test in suite
|
|
92
|
+
if (pickleResultByFile[testSuiteFullPath].length === pickleByFile[testSuiteFullPath].length) {
|
|
93
|
+
const testSuiteStatus = getSuiteStatusFromTestStatuses(pickleResultByFile[testSuiteFullPath])
|
|
94
|
+
testSuiteFinishCh.publish(testSuiteStatus)
|
|
95
|
+
}
|
|
96
|
+
testFinishCh.publish({ status, skipReason, errorMessage })
|
|
62
97
|
})
|
|
63
98
|
return promise
|
|
64
99
|
} catch (err) {
|
|
@@ -68,7 +103,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
68
103
|
})
|
|
69
104
|
})
|
|
70
105
|
shimmer.wrap(pl.prototype, 'runStep', runStep => function () {
|
|
71
|
-
if (!
|
|
106
|
+
if (!testStepStartCh.hasSubscribers) {
|
|
72
107
|
return runStep.apply(this, arguments)
|
|
73
108
|
}
|
|
74
109
|
const testStep = arguments[0]
|
|
@@ -82,7 +117,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
82
117
|
|
|
83
118
|
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
84
119
|
return asyncResource.runInAsyncScope(() => {
|
|
85
|
-
|
|
120
|
+
testStepStartCh.publish({ resource })
|
|
86
121
|
try {
|
|
87
122
|
const promise = runStep.apply(this, arguments)
|
|
88
123
|
|
|
@@ -90,7 +125,7 @@ function wrapRun (pl, isLatestVersion) {
|
|
|
90
125
|
const { status, skipReason, errorMessage } = isLatestVersion
|
|
91
126
|
? getStatusFromResultLatest(result) : getStatusFromResult(result)
|
|
92
127
|
|
|
93
|
-
|
|
128
|
+
testFinishCh.publish({ isStep: true, status, skipReason, errorMessage })
|
|
94
129
|
})
|
|
95
130
|
return promise
|
|
96
131
|
} catch (err) {
|
|
@@ -129,16 +164,40 @@ addHook({
|
|
|
129
164
|
file: 'lib/runtime/test_case_runner.js'
|
|
130
165
|
}, testCaseHook)
|
|
131
166
|
|
|
167
|
+
function getPickleByFile (runtime) {
|
|
168
|
+
return runtime.pickleIds.reduce((acc, pickleId) => {
|
|
169
|
+
const test = runtime.eventDataCollector.getPickle(pickleId)
|
|
170
|
+
if (acc[test.uri]) {
|
|
171
|
+
acc[test.uri].push(test)
|
|
172
|
+
} else {
|
|
173
|
+
acc[test.uri] = [test]
|
|
174
|
+
}
|
|
175
|
+
return acc
|
|
176
|
+
}, {})
|
|
177
|
+
}
|
|
178
|
+
|
|
132
179
|
addHook({
|
|
133
180
|
name: '@cucumber/cucumber',
|
|
134
181
|
versions: ['>=7.0.0'],
|
|
135
182
|
file: 'lib/runtime/index.js'
|
|
136
|
-
}, (
|
|
137
|
-
shimmer.wrap(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
183
|
+
}, (runtimePackage, cucumberVersion) => {
|
|
184
|
+
shimmer.wrap(runtimePackage.default.prototype, 'start', start => async function () {
|
|
185
|
+
pickleByFile = getPickleByFile(this)
|
|
186
|
+
|
|
187
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
188
|
+
const command = process.env.npm_lifecycle_script || `cucumber-js ${processArgv}`
|
|
189
|
+
|
|
190
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
191
|
+
asyncResource.runInAsyncScope(() => {
|
|
192
|
+
sessionStartCh.publish({ command, frameworkVersion: cucumberVersion })
|
|
193
|
+
})
|
|
194
|
+
const success = await start.apply(this, arguments)
|
|
195
|
+
|
|
196
|
+
asyncResource.runInAsyncScope(() => {
|
|
197
|
+
sessionFinishCh.publish(success ? 'pass' : 'fail')
|
|
198
|
+
})
|
|
199
|
+
return success
|
|
141
200
|
})
|
|
142
201
|
|
|
143
|
-
return
|
|
202
|
+
return runtimePackage
|
|
144
203
|
})
|
|
@@ -72,7 +72,7 @@ function getTestEnvironmentOptions (config) {
|
|
|
72
72
|
return {}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function getWrappedEnvironment (BaseEnvironment) {
|
|
75
|
+
function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
76
76
|
return class DatadogEnvironment extends BaseEnvironment {
|
|
77
77
|
constructor (config, context) {
|
|
78
78
|
super(config, context)
|
|
@@ -116,7 +116,8 @@ function getWrappedEnvironment (BaseEnvironment) {
|
|
|
116
116
|
name: getJestTestName(event.test),
|
|
117
117
|
suite: this.testSuite,
|
|
118
118
|
runner: 'jest-circus',
|
|
119
|
-
testParameters
|
|
119
|
+
testParameters,
|
|
120
|
+
frameworkVersion: jestVersion
|
|
120
121
|
})
|
|
121
122
|
originalTestFns.set(event.test, event.test.fn)
|
|
122
123
|
event.test.fn = asyncResource.bind(event.test.fn)
|
|
@@ -142,7 +143,8 @@ function getWrappedEnvironment (BaseEnvironment) {
|
|
|
142
143
|
testSkippedCh.publish({
|
|
143
144
|
name: getJestTestName(event.test),
|
|
144
145
|
suite: this.testSuite,
|
|
145
|
-
runner: 'jest-circus'
|
|
146
|
+
runner: 'jest-circus',
|
|
147
|
+
frameworkVersion: jestVersion
|
|
146
148
|
})
|
|
147
149
|
})
|
|
148
150
|
}
|
|
@@ -150,14 +152,14 @@ function getWrappedEnvironment (BaseEnvironment) {
|
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
|
|
153
|
-
function getTestEnvironment (pkg) {
|
|
155
|
+
function getTestEnvironment (pkg, jestVersion) {
|
|
154
156
|
if (pkg.default) {
|
|
155
|
-
const wrappedTestEnvironment = getWrappedEnvironment(pkg.default)
|
|
157
|
+
const wrappedTestEnvironment = getWrappedEnvironment(pkg.default, jestVersion)
|
|
156
158
|
pkg.default = wrappedTestEnvironment
|
|
157
159
|
pkg.TestEnvironment = wrappedTestEnvironment
|
|
158
160
|
return pkg
|
|
159
161
|
}
|
|
160
|
-
return getWrappedEnvironment(pkg)
|
|
162
|
+
return getWrappedEnvironment(pkg, jestVersion)
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
addHook({
|
|
@@ -170,7 +172,7 @@ addHook({
|
|
|
170
172
|
versions: ['>=24.8.0']
|
|
171
173
|
}, getTestEnvironment)
|
|
172
174
|
|
|
173
|
-
function cliWrapper (cli) {
|
|
175
|
+
function cliWrapper (cli, jestVersion) {
|
|
174
176
|
const wrapped = shimmer.wrap(cli, 'runCLI', runCLI => async function () {
|
|
175
177
|
let onDone
|
|
176
178
|
const configurationPromise = new Promise((resolve) => {
|
|
@@ -215,19 +217,9 @@ function cliWrapper (cli) {
|
|
|
215
217
|
|
|
216
218
|
const isSuitesSkipped = !!skippableSuites.length
|
|
217
219
|
|
|
218
|
-
let testFrameworkVersion
|
|
219
|
-
try {
|
|
220
|
-
testFrameworkVersion = this.getVersion()
|
|
221
|
-
} catch (e) {
|
|
222
|
-
try {
|
|
223
|
-
testFrameworkVersion = this.default.getVersion()
|
|
224
|
-
} catch (e) {
|
|
225
|
-
// ignore errors
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
220
|
const processArgv = process.argv.slice(2).join(' ')
|
|
229
221
|
sessionAsyncResource.runInAsyncScope(() => {
|
|
230
|
-
testSessionStartCh.publish({ command: `jest ${processArgv}`,
|
|
222
|
+
testSessionStartCh.publish({ command: `jest ${processArgv}`, frameworkVersion: jestVersion })
|
|
231
223
|
})
|
|
232
224
|
|
|
233
225
|
const result = await runCLI.apply(this, arguments)
|
|
@@ -295,7 +287,7 @@ addHook({
|
|
|
295
287
|
versions: ['>=24.8.0']
|
|
296
288
|
}, cliWrapper)
|
|
297
289
|
|
|
298
|
-
function jestAdapterWrapper (jestAdapter) {
|
|
290
|
+
function jestAdapterWrapper (jestAdapter, jestVersion) {
|
|
299
291
|
const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
|
|
300
292
|
const newAdapter = shimmer.wrap(adapter, function () {
|
|
301
293
|
const environment = arguments[2]
|
|
@@ -306,7 +298,8 @@ function jestAdapterWrapper (jestAdapter) {
|
|
|
306
298
|
return asyncResource.runInAsyncScope(() => {
|
|
307
299
|
testSuiteStartCh.publish({
|
|
308
300
|
testSuite: environment.testSuite,
|
|
309
|
-
testEnvironmentOptions: environment.testEnvironmentOptions
|
|
301
|
+
testEnvironmentOptions: environment.testEnvironmentOptions,
|
|
302
|
+
frameworkVersion: jestVersion
|
|
310
303
|
})
|
|
311
304
|
return adapter.apply(this, arguments).then(suiteResults => {
|
|
312
305
|
const { numFailingTests, skipped, failureMessage: errorMessage } = suiteResults
|
|
@@ -447,7 +440,7 @@ addHook({
|
|
|
447
440
|
versions: ['24.8.0 - 24.9.0']
|
|
448
441
|
}, jestConfigSyncWrapper)
|
|
449
442
|
|
|
450
|
-
function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
|
|
443
|
+
function jasmineAsyncInstallWraper (jasmineAsyncInstallExport, jestVersion) {
|
|
451
444
|
return function (globalConfig, globalInput) {
|
|
452
445
|
globalInput._ddtrace = global._ddtrace
|
|
453
446
|
shimmer.wrap(globalInput.jasmine.Spec.prototype, 'execute', execute => function (onComplete) {
|
|
@@ -457,7 +450,8 @@ function jasmineAsyncInstallWraper (jasmineAsyncInstallExport) {
|
|
|
457
450
|
testStartCh.publish({
|
|
458
451
|
name: this.getFullName(),
|
|
459
452
|
suite: testSuite,
|
|
460
|
-
runner: 'jest-jasmine2'
|
|
453
|
+
runner: 'jest-jasmine2',
|
|
454
|
+
frameworkVersion: jestVersion
|
|
461
455
|
})
|
|
462
456
|
const spec = this
|
|
463
457
|
const callback = asyncResource.bind(function () {
|
|
@@ -38,7 +38,7 @@ const testFileToSuiteAr = new Map()
|
|
|
38
38
|
const originalCoverageMap = createCoverageMap()
|
|
39
39
|
|
|
40
40
|
let suitesToSkip = []
|
|
41
|
-
let
|
|
41
|
+
let frameworkVersion
|
|
42
42
|
|
|
43
43
|
function getSuitesByTestFile (root) {
|
|
44
44
|
const suitesByTestFile = {}
|
|
@@ -128,7 +128,7 @@ function mochaHook (Runner) {
|
|
|
128
128
|
this.once('start', testRunAsyncResource.bind(function () {
|
|
129
129
|
const processArgv = process.argv.slice(2).join(' ')
|
|
130
130
|
const command = `mocha ${processArgv}`
|
|
131
|
-
testSessionStartCh.publish({ command, frameworkVersion
|
|
131
|
+
testSessionStartCh.publish({ command, frameworkVersion })
|
|
132
132
|
}))
|
|
133
133
|
|
|
134
134
|
this.on('suite', function (suite) {
|
|
@@ -313,14 +313,14 @@ addHook({
|
|
|
313
313
|
name: 'mocha',
|
|
314
314
|
versions: ['>=5.2.0'],
|
|
315
315
|
file: 'lib/mocha.js'
|
|
316
|
-
}, (Mocha) => {
|
|
316
|
+
}, (Mocha, mochaVersion) => {
|
|
317
|
+
frameworkVersion = mochaVersion
|
|
317
318
|
const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
318
319
|
/**
|
|
319
320
|
* Get ITR configuration and skippable suites
|
|
320
321
|
* If ITR is disabled, `onDone` is called immediately on the subscriber
|
|
321
322
|
*/
|
|
322
323
|
shimmer.wrap(Mocha.prototype, 'run', run => function () {
|
|
323
|
-
mochaVersion = this.version
|
|
324
324
|
if (!itrConfigurationCh.hasSubscribers) {
|
|
325
325
|
return run.apply(this, arguments)
|
|
326
326
|
}
|
|
@@ -181,17 +181,15 @@ function dispatcherHookNew (dispatcherExport) {
|
|
|
181
181
|
return dispatcherExport
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
function runnerHook (runnerExport) {
|
|
184
|
+
function runnerHook (runnerExport, playwrightVersion) {
|
|
185
185
|
shimmer.wrap(runnerExport.Runner.prototype, 'runAllTests', runAllTests => async function () {
|
|
186
186
|
const testSessionAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
187
|
-
const { version: frameworkVersion } = getPlaywrightConfig(this)
|
|
188
|
-
|
|
189
187
|
const rootDir = getRootDir(this)
|
|
190
188
|
|
|
191
189
|
const processArgv = process.argv.slice(2).join(' ')
|
|
192
190
|
const command = `playwright ${processArgv}`
|
|
193
191
|
testSessionAsyncResource.runInAsyncScope(() => {
|
|
194
|
-
testSessionStartCh.publish({ command, frameworkVersion, rootDir })
|
|
192
|
+
testSessionStartCh.publish({ command, frameworkVersion: playwrightVersion, rootDir })
|
|
195
193
|
})
|
|
196
194
|
|
|
197
195
|
const res = await runAllTests.apply(this, arguments)
|
|
@@ -7,7 +7,16 @@ const {
|
|
|
7
7
|
TEST_SKIP_REASON,
|
|
8
8
|
TEST_STATUS,
|
|
9
9
|
finishAllTraceSpans,
|
|
10
|
-
getTestSuitePath
|
|
10
|
+
getTestSuitePath,
|
|
11
|
+
getTestParentSpan,
|
|
12
|
+
getTestSessionCommonTags,
|
|
13
|
+
getTestModuleCommonTags,
|
|
14
|
+
getTestSuiteCommonTags,
|
|
15
|
+
TEST_SUITE_ID,
|
|
16
|
+
TEST_MODULE_ID,
|
|
17
|
+
TEST_SESSION_ID,
|
|
18
|
+
TEST_COMMAND,
|
|
19
|
+
TEST_BUNDLE
|
|
11
20
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
21
|
const { RESOURCE_NAME } = require('../../../ext/tags')
|
|
13
22
|
const { COMPONENT, ERROR_MESSAGE } = require('../../dd-trace/src/constants')
|
|
@@ -20,21 +29,73 @@ class CucumberPlugin extends CiPlugin {
|
|
|
20
29
|
constructor (...args) {
|
|
21
30
|
super(...args)
|
|
22
31
|
|
|
23
|
-
this.
|
|
32
|
+
this.sourceRoot = process.cwd()
|
|
33
|
+
|
|
34
|
+
this.addSub('ci:cucumber:session:start', ({ command, frameworkVersion }) => {
|
|
35
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
36
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
37
|
+
|
|
38
|
+
this.command = command
|
|
39
|
+
this.frameworkVersion = frameworkVersion
|
|
40
|
+
this.testSessionSpan = this.tracer.startSpan('cucumber.test_session', {
|
|
41
|
+
childOf,
|
|
42
|
+
tags: {
|
|
43
|
+
[COMPONENT]: this.constructor.name,
|
|
44
|
+
...this.testEnvironmentMetadata,
|
|
45
|
+
...testSessionSpanMetadata
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
50
|
+
this.testModuleSpan = this.tracer.startSpan('cucumber.test_module', {
|
|
51
|
+
childOf: this.testSessionSpan,
|
|
52
|
+
tags: {
|
|
53
|
+
[COMPONENT]: this.constructor.name,
|
|
54
|
+
...this.testEnvironmentMetadata,
|
|
55
|
+
...testModuleSpanMetadata
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
this.addSub('ci:cucumber:session:finish', (status) => {
|
|
61
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
62
|
+
this.testModuleSpan.setTag(TEST_STATUS, status)
|
|
63
|
+
this.testModuleSpan.finish()
|
|
64
|
+
this.testSessionSpan.finish()
|
|
65
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
24
66
|
this.tracer._exporter.flush()
|
|
25
67
|
})
|
|
26
68
|
|
|
27
|
-
this.addSub('ci:cucumber:
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
69
|
+
this.addSub('ci:cucumber:test-suite:start', (testSuiteFullPath) => {
|
|
70
|
+
const testSuiteMetadata = getTestSuiteCommonTags(
|
|
71
|
+
this.command,
|
|
72
|
+
this.frameworkVersion,
|
|
73
|
+
getTestSuitePath(testSuiteFullPath, this.sourceRoot)
|
|
74
|
+
)
|
|
75
|
+
this.testSuiteSpan = this.tracer.startSpan('cucumber.test_suite', {
|
|
76
|
+
childOf: this.testModuleSpan,
|
|
77
|
+
tags: {
|
|
78
|
+
[COMPONENT]: this.constructor.name,
|
|
79
|
+
...this.testEnvironmentMetadata,
|
|
80
|
+
...testSuiteMetadata
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
})
|
|
31
84
|
|
|
32
|
-
|
|
85
|
+
this.addSub('ci:cucumber:test-suite:finish', status => {
|
|
86
|
+
this.testSuiteSpan.setTag(TEST_STATUS, status)
|
|
87
|
+
this.testSuiteSpan.finish()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
this.addSub('ci:cucumber:test:start', ({ testName, fullTestSuite }) => {
|
|
91
|
+
const store = storage.getStore()
|
|
92
|
+
const testSuite = getTestSuitePath(fullTestSuite, this.sourceRoot)
|
|
93
|
+
const testSpan = this.startTestSpan(testName, testSuite)
|
|
33
94
|
|
|
34
95
|
this.enter(testSpan, store)
|
|
35
96
|
})
|
|
36
97
|
|
|
37
|
-
this.addSub('ci:cucumber:
|
|
98
|
+
this.addSub('ci:cucumber:test-step:start', ({ resource }) => {
|
|
38
99
|
const store = storage.getStore()
|
|
39
100
|
const childOf = store ? store.span : store
|
|
40
101
|
const span = this.tracer.startSpan('cucumber.step', {
|
|
@@ -48,7 +109,7 @@ class CucumberPlugin extends CiPlugin {
|
|
|
48
109
|
this.enter(span, store)
|
|
49
110
|
})
|
|
50
111
|
|
|
51
|
-
this.addSub('ci:cucumber:
|
|
112
|
+
this.addSub('ci:cucumber:test:finish', ({ isStep, status, skipReason, errorMessage }) => {
|
|
52
113
|
const span = storage.getStore().span
|
|
53
114
|
const statusTag = isStep ? 'step.status' : TEST_STATUS
|
|
54
115
|
|
|
@@ -76,8 +137,34 @@ class CucumberPlugin extends CiPlugin {
|
|
|
76
137
|
})
|
|
77
138
|
}
|
|
78
139
|
|
|
79
|
-
startTestSpan (testName, testSuite
|
|
80
|
-
|
|
140
|
+
startTestSpan (testName, testSuite) {
|
|
141
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
142
|
+
// TODO: move this logic to CiPlugin once every framework supports test suite level visibility
|
|
143
|
+
// This is a hack to get good time resolution on test events, while keeping
|
|
144
|
+
// the test event as the root span of its trace.
|
|
145
|
+
childOf._trace.startTime = this.testSessionSpan.context()._trace.startTime
|
|
146
|
+
childOf._trace.ticks = this.testSessionSpan.context()._trace.ticks
|
|
147
|
+
|
|
148
|
+
const testSuiteTags = {}
|
|
149
|
+
const testSuiteId = this.testSuiteSpan.context().toSpanId()
|
|
150
|
+
testSuiteTags[TEST_SUITE_ID] = testSuiteId
|
|
151
|
+
|
|
152
|
+
const testSessionId = this.testSessionSpan.context().toTraceId()
|
|
153
|
+
testSuiteTags[TEST_SESSION_ID] = testSessionId
|
|
154
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
155
|
+
|
|
156
|
+
const testModuleId = this.testModuleSpan.context().toSpanId()
|
|
157
|
+
testSuiteTags[TEST_MODULE_ID] = testModuleId
|
|
158
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
159
|
+
testSuiteTags[TEST_BUNDLE] = this.command
|
|
160
|
+
|
|
161
|
+
return super.startTestSpan(
|
|
162
|
+
testName,
|
|
163
|
+
testSuite,
|
|
164
|
+
childOf,
|
|
165
|
+
this.frameworkVersion,
|
|
166
|
+
testSuiteTags
|
|
167
|
+
)
|
|
81
168
|
}
|
|
82
169
|
}
|
|
83
170
|
|
|
@@ -7,7 +7,15 @@ const {
|
|
|
7
7
|
getTestParentSpan,
|
|
8
8
|
getCodeOwnersFileEntries,
|
|
9
9
|
getCodeOwnersForFilename,
|
|
10
|
-
getTestCommonTags
|
|
10
|
+
getTestCommonTags,
|
|
11
|
+
getTestSessionCommonTags,
|
|
12
|
+
getTestModuleCommonTags,
|
|
13
|
+
getTestSuiteCommonTags,
|
|
14
|
+
TEST_SUITE_ID,
|
|
15
|
+
TEST_MODULE_ID,
|
|
16
|
+
TEST_SESSION_ID,
|
|
17
|
+
TEST_COMMAND,
|
|
18
|
+
TEST_BUNDLE
|
|
11
19
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
20
|
|
|
13
21
|
const { ORIGIN_KEY, COMPONENT } = require('../../dd-trace/src/constants')
|
|
@@ -30,6 +38,43 @@ function getTestSpanMetadata (tracer, testName, testSuite, cypressConfig) {
|
|
|
30
38
|
}
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
function getCypressVersion (details) {
|
|
42
|
+
if (details && details.cypressVersion) {
|
|
43
|
+
return details.cypressVersion
|
|
44
|
+
}
|
|
45
|
+
if (details && details.config && details.config.version) {
|
|
46
|
+
return details.config.version
|
|
47
|
+
}
|
|
48
|
+
return ''
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getCypressCommand (details) {
|
|
52
|
+
if (!details) {
|
|
53
|
+
return 'cypress'
|
|
54
|
+
}
|
|
55
|
+
return `cypress ${details.specPattern || ''}`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getSessionStatus (summary) {
|
|
59
|
+
if (summary.totalFailed !== undefined && summary.totalFailed > 0) {
|
|
60
|
+
return 'fail'
|
|
61
|
+
}
|
|
62
|
+
if (summary.totalSkipped !== undefined && summary.totalSkipped === summary.totalTests) {
|
|
63
|
+
return 'skip'
|
|
64
|
+
}
|
|
65
|
+
return 'pass'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getSuiteStatus (suiteStats) {
|
|
69
|
+
if (suiteStats.failures !== undefined && suiteStats.failures > 0) {
|
|
70
|
+
return 'fail'
|
|
71
|
+
}
|
|
72
|
+
if (suiteStats.tests !== undefined && suiteStats.tests === suiteStats.pending) {
|
|
73
|
+
return 'skip'
|
|
74
|
+
}
|
|
75
|
+
return 'pass'
|
|
76
|
+
}
|
|
77
|
+
|
|
33
78
|
module.exports = (on, config) => {
|
|
34
79
|
const tracer = require('../../dd-trace')
|
|
35
80
|
const testEnvironmentMetadata = getTestEnvironmentMetadata('cypress')
|
|
@@ -37,14 +82,84 @@ module.exports = (on, config) => {
|
|
|
37
82
|
const codeOwnersEntries = getCodeOwnersFileEntries()
|
|
38
83
|
|
|
39
84
|
let activeSpan = null
|
|
40
|
-
|
|
85
|
+
let testSessionSpan = null
|
|
86
|
+
let testModuleSpan = null
|
|
87
|
+
let testSuiteSpan = null
|
|
88
|
+
let command = null
|
|
89
|
+
let frameworkVersion
|
|
90
|
+
|
|
91
|
+
on('before:run', (details) => {
|
|
92
|
+
const childOf = getTestParentSpan(tracer)
|
|
93
|
+
|
|
94
|
+
command = getCypressCommand(details)
|
|
95
|
+
frameworkVersion = getCypressVersion(details)
|
|
96
|
+
|
|
97
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, frameworkVersion)
|
|
98
|
+
const testModuleSpanMetadata = getTestModuleCommonTags(command, frameworkVersion)
|
|
99
|
+
|
|
100
|
+
testSessionSpan = tracer.startSpan('cypress.test_session', {
|
|
101
|
+
childOf,
|
|
102
|
+
tags: {
|
|
103
|
+
[COMPONENT]: 'cypress',
|
|
104
|
+
...testEnvironmentMetadata,
|
|
105
|
+
...testSessionSpanMetadata
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
testModuleSpan = tracer.startSpan('cypress.test_module', {
|
|
109
|
+
childOf: testSessionSpan,
|
|
110
|
+
tags: {
|
|
111
|
+
[COMPONENT]: 'cypress',
|
|
112
|
+
...testEnvironmentMetadata,
|
|
113
|
+
...testModuleSpanMetadata
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
on('after:run', (suiteStats) => {
|
|
119
|
+
const testStatus = getSessionStatus(suiteStats)
|
|
120
|
+
testModuleSpan.setTag(TEST_STATUS, testStatus)
|
|
121
|
+
testSessionSpan.setTag(TEST_STATUS, testStatus)
|
|
122
|
+
|
|
123
|
+
testModuleSpan.finish()
|
|
124
|
+
testSessionSpan.finish()
|
|
125
|
+
|
|
41
126
|
return new Promise(resolve => {
|
|
42
127
|
tracer._tracer._exporter._writer.flush(() => resolve(null))
|
|
43
128
|
})
|
|
44
129
|
})
|
|
45
130
|
on('task', {
|
|
131
|
+
'dd:testSuiteStart': (suite) => {
|
|
132
|
+
const testSuiteSpanMetadata = getTestSuiteCommonTags(command, frameworkVersion, suite)
|
|
133
|
+
testSuiteSpan = tracer.startSpan('cypress.test_suite', {
|
|
134
|
+
childOf: testModuleSpan,
|
|
135
|
+
tags: {
|
|
136
|
+
[COMPONENT]: 'cypress',
|
|
137
|
+
...testEnvironmentMetadata,
|
|
138
|
+
...testSuiteSpanMetadata
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
return null
|
|
142
|
+
},
|
|
143
|
+
'dd:testSuiteFinish': (suiteStats) => {
|
|
144
|
+
const status = getSuiteStatus(suiteStats)
|
|
145
|
+
testSuiteSpan.setTag(TEST_STATUS, status)
|
|
146
|
+
testSuiteSpan.finish()
|
|
147
|
+
return null
|
|
148
|
+
},
|
|
46
149
|
'dd:beforeEach': (test) => {
|
|
47
150
|
const { testName, testSuite } = test
|
|
151
|
+
const testSuiteId = testSuiteSpan.context().toSpanId()
|
|
152
|
+
const testSessionId = testSessionSpan.context().toTraceId()
|
|
153
|
+
const testModuleId = testModuleSpan.context().toSpanId()
|
|
154
|
+
|
|
155
|
+
const testSuiteTags = {
|
|
156
|
+
[TEST_SUITE_ID]: testSuiteId,
|
|
157
|
+
[TEST_SESSION_ID]: testSessionId,
|
|
158
|
+
[TEST_COMMAND]: command,
|
|
159
|
+
[TEST_MODULE_ID]: testModuleId,
|
|
160
|
+
[TEST_COMMAND]: command,
|
|
161
|
+
[TEST_BUNDLE]: command
|
|
162
|
+
}
|
|
48
163
|
|
|
49
164
|
const {
|
|
50
165
|
childOf,
|
|
@@ -65,7 +180,8 @@ module.exports = (on, config) => {
|
|
|
65
180
|
[COMPONENT]: 'cypress',
|
|
66
181
|
[ORIGIN_KEY]: CI_APP_ORIGIN,
|
|
67
182
|
...testSpanMetadata,
|
|
68
|
-
...testEnvironmentMetadata
|
|
183
|
+
...testEnvironmentMetadata,
|
|
184
|
+
...testSuiteTags
|
|
69
185
|
}
|
|
70
186
|
})
|
|
71
187
|
}
|
|
@@ -8,7 +8,12 @@ beforeEach(() => {
|
|
|
8
8
|
})
|
|
9
9
|
})
|
|
10
10
|
|
|
11
|
+
before(() => {
|
|
12
|
+
cy.task('dd:testSuiteStart', Cypress.mocha.getRootSuite().file)
|
|
13
|
+
})
|
|
14
|
+
|
|
11
15
|
after(() => {
|
|
16
|
+
cy.task('dd:testSuiteFinish', Cypress.mocha.getRunner().stats)
|
|
12
17
|
cy.window().then(win => {
|
|
13
18
|
win.dispatchEvent(new Event('beforeunload'))
|
|
14
19
|
})
|