dd-trace 5.75.0 → 5.77.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 -1
- package/ci/init.js +1 -0
- package/package.json +15 -15
- package/packages/datadog-instrumentations/src/express.js +18 -7
- package/packages/datadog-instrumentations/src/jest.js +16 -16
- package/packages/datadog-instrumentations/src/openai.js +8 -0
- package/packages/datadog-instrumentations/src/playwright.js +47 -0
- package/packages/datadog-instrumentations/src/router.js +9 -8
- package/packages/datadog-instrumentations/src/vitest.js +94 -8
- package/packages/datadog-plugin-cucumber/src/index.js +2 -1
- package/packages/datadog-plugin-grpc/src/util.js +5 -1
- package/packages/datadog-plugin-http/src/client.js +5 -1
- package/packages/datadog-plugin-http2/src/client.js +5 -1
- package/packages/datadog-plugin-openai/src/stream-helpers.js +26 -1
- package/packages/datadog-plugin-openai/src/tracing.js +46 -1
- package/packages/datadog-plugin-vitest/src/index.js +5 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +1 -1
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -3
- package/packages/dd-trace/src/appsec/rasp/lfi.js +23 -9
- package/packages/dd-trace/src/appsec/stack_trace.js +6 -6
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +30 -7
- package/packages/dd-trace/src/config.js +10 -1
- package/packages/dd-trace/src/debugger/devtools_client/index.js +8 -1
- package/packages/dd-trace/src/debugger/devtools_client/log.js +15 -4
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +5 -1
- package/packages/dd-trace/src/exporters/common/docker.js +1 -1
- package/packages/dd-trace/src/exporters/span-stats/writer.js +4 -5
- package/packages/dd-trace/src/format.js +4 -5
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +9 -6
- package/packages/dd-trace/src/llmobs/plugins/anthropic.js +3 -6
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +3 -2
- package/packages/dd-trace/src/llmobs/plugins/openai.js +216 -12
- package/packages/dd-trace/src/llmobs/span_processor.js +4 -3
- package/packages/dd-trace/src/llmobs/tagger.js +9 -3
- package/packages/dd-trace/src/llmobs/util.js +1 -1
- package/packages/dd-trace/src/openfeature/writers/exposures.js +2 -2
- package/packages/dd-trace/src/opentelemetry/span.js +3 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +3 -1
- package/packages/dd-trace/src/plugins/util/serverless.js +1 -2
- package/packages/dd-trace/src/plugins/util/test.js +16 -1
- package/packages/dd-trace/src/plugins/util/web.js +5 -1
- package/packages/dd-trace/src/profiling/config.js +32 -10
- package/packages/dd-trace/src/proxy.js +2 -2
- package/packages/dd-trace/src/remote_config/capabilities.js +2 -0
- package/packages/dd-trace/src/remote_config/index.js +4 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
- package/packages/dd-trace/src/span_processor.js +4 -1
- package/packages/dd-trace/src/startup-log.js +24 -38
- package/packages/dd-trace/src/supported-configurations.json +1 -0
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -11,7 +11,7 @@ require,@opentelemetry/api,Apache license 2.0,Copyright OpenTelemetry Authors
|
|
|
11
11
|
require,@opentelemetry/api-logs,Apache license 2.0,Copyright OpenTelemetry Authors
|
|
12
12
|
require,@opentelemetry/core,Apache license 2.0,Copyright OpenTelemetry Authors
|
|
13
13
|
require,@opentelemetry/resources,Apache license 2.0,Copyright OpenTelemetry Authors
|
|
14
|
-
require,@isaacs/ttlcache,
|
|
14
|
+
require,@isaacs/ttlcache,Blue Oak,Copyright Isaac Z. Schlueter and Contributors
|
|
15
15
|
require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
|
|
16
16
|
require,dc-polyfill,MIT,Copyright 2023 Datadog Inc.
|
|
17
17
|
require,escape-string-regexp,MIT,Copyright Sindre Sorhus
|
package/ci/init.js
CHANGED
|
@@ -29,6 +29,7 @@ function detectTestWorkerType () {
|
|
|
29
29
|
if (getEnvironmentVariable('MOCHA_WORKER_ID')) return 'mocha'
|
|
30
30
|
if (getEnvironmentVariable('DD_PLAYWRIGHT_WORKER')) return 'playwright'
|
|
31
31
|
if (getEnvironmentVariable('TINYPOOL_WORKER_ID')) return 'vitest'
|
|
32
|
+
if (getEnvironmentVariable('DD_VITEST_WORKER')) return 'vitest'
|
|
32
33
|
return null
|
|
33
34
|
}
|
|
34
35
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.77.0",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -125,15 +125,15 @@
|
|
|
125
125
|
"@datadog/native-appsec": "10.3.0",
|
|
126
126
|
"@datadog/native-iast-taint-tracking": "4.0.0",
|
|
127
127
|
"@datadog/native-metrics": "3.1.1",
|
|
128
|
-
"@datadog/openfeature-node-server": "0.1.0-preview.
|
|
129
|
-
"@datadog/pprof": "5.
|
|
128
|
+
"@datadog/openfeature-node-server": "0.1.0-preview.15",
|
|
129
|
+
"@datadog/pprof": "5.12.0",
|
|
130
130
|
"@datadog/sketches-js": "2.1.1",
|
|
131
|
-
"@datadog/wasm-js-rewriter": "
|
|
132
|
-
"@isaacs/ttlcache": "^
|
|
131
|
+
"@datadog/wasm-js-rewriter": "5.0.1",
|
|
132
|
+
"@isaacs/ttlcache": "^2.0.1",
|
|
133
133
|
"@opentelemetry/api": ">=1.0.0 <1.10.0",
|
|
134
134
|
"@opentelemetry/api-logs": "<1.0.0",
|
|
135
135
|
"@opentelemetry/core": ">=1.14.0 <1.31.0",
|
|
136
|
-
"@opentelemetry/resources": ">=1.0.0 <1.
|
|
136
|
+
"@opentelemetry/resources": ">=1.0.0 <1.31.0",
|
|
137
137
|
"crypto-randomuuid": "^1.0.0",
|
|
138
138
|
"dc-polyfill": "^0.1.10",
|
|
139
139
|
"escape-string-regexp": "^5.0.0",
|
|
@@ -160,13 +160,13 @@
|
|
|
160
160
|
"ttl-set": "^1.0.0"
|
|
161
161
|
},
|
|
162
162
|
"devDependencies": {
|
|
163
|
-
"@babel/helpers": "^7.
|
|
163
|
+
"@babel/helpers": "^7.28.4",
|
|
164
164
|
"@eslint/eslintrc": "^3.3.1",
|
|
165
|
-
"@eslint/js": "^9.
|
|
165
|
+
"@eslint/js": "^9.39.0",
|
|
166
166
|
"@msgpack/msgpack": "^3.1.2",
|
|
167
167
|
"@openfeature/core": "^1.9.0",
|
|
168
168
|
"@openfeature/server-sdk": "^1.20.0",
|
|
169
|
-
"@stylistic/eslint-plugin": "^5.
|
|
169
|
+
"@stylistic/eslint-plugin": "^5.5.0",
|
|
170
170
|
"@types/chai": "^4.3.16",
|
|
171
171
|
"@types/mocha": "^10.0.10",
|
|
172
172
|
"@types/node": "^18.19.106",
|
|
@@ -175,15 +175,15 @@
|
|
|
175
175
|
"axios": "^1.12.2",
|
|
176
176
|
"benchmark": "^2.1.4",
|
|
177
177
|
"body-parser": "^2.2.0",
|
|
178
|
-
"bun": "1.3.
|
|
178
|
+
"bun": "1.3.2",
|
|
179
179
|
"chai": "^4.5.0",
|
|
180
|
-
"eslint": "^9.
|
|
181
|
-
"eslint-plugin-cypress": "^5.
|
|
180
|
+
"eslint": "^9.39.0",
|
|
181
|
+
"eslint-plugin-cypress": "^5.2.0",
|
|
182
182
|
"eslint-plugin-import": "^2.32.0",
|
|
183
|
-
"eslint-plugin-mocha": "^11.
|
|
184
|
-
"eslint-plugin-n": "^17.
|
|
183
|
+
"eslint-plugin-mocha": "^11.2.0",
|
|
184
|
+
"eslint-plugin-n": "^17.23.1",
|
|
185
185
|
"eslint-plugin-promise": "^7.2.1",
|
|
186
|
-
"eslint-plugin-unicorn": "^
|
|
186
|
+
"eslint-plugin-unicorn": "^62.0.0",
|
|
187
187
|
"express": "^5.1.0",
|
|
188
188
|
"glob": "^10.4.5",
|
|
189
189
|
"globals": "^16.3.0",
|
|
@@ -53,12 +53,21 @@ function wrapResponseRender (render) {
|
|
|
53
53
|
return render.apply(this, arguments)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
const abortController = new AbortController()
|
|
56
57
|
return responseRenderChannel.traceSync(
|
|
57
|
-
|
|
58
|
+
function () {
|
|
59
|
+
if (abortController.signal.aborted) {
|
|
60
|
+
const error = abortController.signal.reason || new Error('Aborted')
|
|
61
|
+
throw error
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return render.apply(this, arguments)
|
|
65
|
+
},
|
|
58
66
|
{
|
|
59
67
|
req: this.req,
|
|
60
68
|
view,
|
|
61
|
-
options
|
|
69
|
+
options,
|
|
70
|
+
abortController
|
|
62
71
|
},
|
|
63
72
|
this,
|
|
64
73
|
...arguments
|
|
@@ -67,26 +76,28 @@ function wrapResponseRender (render) {
|
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
function wrapAppAll (all) {
|
|
70
|
-
return function wrappedAll (
|
|
71
|
-
if (!routeAddedChannel.hasSubscribers) return all.
|
|
79
|
+
return function wrappedAll (...args) {
|
|
80
|
+
if (!routeAddedChannel.hasSubscribers) return all.apply(this, args)
|
|
72
81
|
|
|
82
|
+
const path = args[0]
|
|
73
83
|
const paths = normalizeRoutePaths(path)
|
|
74
84
|
|
|
75
85
|
for (const p of paths) {
|
|
76
86
|
routeAddedChannel.publish({ method: '*', path: p })
|
|
77
87
|
}
|
|
78
88
|
|
|
79
|
-
return all.
|
|
89
|
+
return all.apply(this, args)
|
|
80
90
|
}
|
|
81
91
|
}
|
|
82
92
|
|
|
83
93
|
// Wrap app.route() to instrument Route object
|
|
84
94
|
function wrapAppRoute (route) {
|
|
85
|
-
return function wrappedRoute (
|
|
86
|
-
const routeObj = route.
|
|
95
|
+
return function wrappedRoute (...args) {
|
|
96
|
+
const routeObj = route.apply(this, args)
|
|
87
97
|
|
|
88
98
|
if (!routeAddedChannel.hasSubscribers) return routeObj
|
|
89
99
|
|
|
100
|
+
const path = args[0]
|
|
90
101
|
const paths = normalizeRoutePaths(path)
|
|
91
102
|
|
|
92
103
|
if (!paths.length) return routeObj
|
|
@@ -140,7 +140,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
140
140
|
this.hasSnapshotTests = undefined
|
|
141
141
|
this.testSuiteAbsolutePath = context.testPath
|
|
142
142
|
|
|
143
|
-
this.displayName = config.projectConfig?.displayName?.name
|
|
143
|
+
this.displayName = config.projectConfig?.displayName?.name || config.displayName
|
|
144
144
|
this.testEnvironmentOptions = getTestEnvironmentOptions(config)
|
|
145
145
|
|
|
146
146
|
const repositoryRoot = this.testEnvironmentOptions._ddRepositoryRoot
|
|
@@ -411,23 +411,19 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
|
|
|
411
411
|
} else {
|
|
412
412
|
originalHookFns.set(hook, hookFn)
|
|
413
413
|
}
|
|
414
|
-
|
|
415
|
-
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
416
|
-
const wrapperHook = function () {
|
|
414
|
+
const newHookFn = shimmer.wrapFunction(hookFn, hookFn => function () {
|
|
417
415
|
return testFnCh.runStores(ctx, () => hookFn.apply(this, arguments))
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
Object.defineProperty(wrapperHook, 'length', { value: hookFn.length })
|
|
421
|
-
hook.fn = wrapperHook
|
|
416
|
+
})
|
|
417
|
+
hook.fn = newHookFn
|
|
422
418
|
}
|
|
423
419
|
const originalFn = event.test.fn
|
|
424
420
|
originalTestFns.set(event.test, originalFn)
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
event.test.fn =
|
|
421
|
+
|
|
422
|
+
const newFn = shimmer.wrapFunction(event.test.fn, testFn => function () {
|
|
423
|
+
return testFnCh.runStores(ctx, () => testFn.apply(this, arguments))
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
event.test.fn = newFn
|
|
431
427
|
})
|
|
432
428
|
}
|
|
433
429
|
|
|
@@ -1293,7 +1289,7 @@ addHook({
|
|
|
1293
1289
|
|
|
1294
1290
|
shimmer.wrap(Runtime.prototype, '_createJestObjectFor', _createJestObjectFor => function (from) {
|
|
1295
1291
|
const result = _createJestObjectFor.apply(this, arguments)
|
|
1296
|
-
const suiteFilePath = this._testPath
|
|
1292
|
+
const suiteFilePath = this._testPath || from
|
|
1297
1293
|
|
|
1298
1294
|
shimmer.wrap(result, 'mock', mock => function (moduleName) {
|
|
1299
1295
|
// If the library is mocked with `jest.mock`, we don't want to bypass jest's own require engine
|
|
@@ -1450,7 +1446,11 @@ addHook({
|
|
|
1450
1446
|
}, (childProcessWorker) => {
|
|
1451
1447
|
const ChildProcessWorker = childProcessWorker.default
|
|
1452
1448
|
shimmer.wrap(ChildProcessWorker.prototype, 'send', sendWrapper)
|
|
1453
|
-
|
|
1449
|
+
if (ChildProcessWorker.prototype._onMessage) {
|
|
1450
|
+
shimmer.wrap(ChildProcessWorker.prototype, '_onMessage', onMessageWrapper)
|
|
1451
|
+
} else if (ChildProcessWorker.prototype.onMessage) {
|
|
1452
|
+
shimmer.wrap(ChildProcessWorker.prototype, 'onMessage', onMessageWrapper)
|
|
1453
|
+
}
|
|
1454
1454
|
return childProcessWorker
|
|
1455
1455
|
})
|
|
1456
1456
|
|
|
@@ -22,6 +22,14 @@ const V4_PACKAGE_SHIMS = [
|
|
|
22
22
|
methods: ['create'],
|
|
23
23
|
streamedResponse: true
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
file: 'resources/responses/responses',
|
|
27
|
+
targetClass: 'Responses',
|
|
28
|
+
baseResource: 'responses',
|
|
29
|
+
methods: ['create'],
|
|
30
|
+
streamedResponse: true,
|
|
31
|
+
versions: ['>=4.87.0']
|
|
32
|
+
},
|
|
25
33
|
{
|
|
26
34
|
file: 'resources/embeddings',
|
|
27
35
|
targetClass: 'Embeddings',
|
|
@@ -68,6 +68,8 @@ let modifiedFiles = {}
|
|
|
68
68
|
const quarantinedOrDisabledTestsAttemptToFix = []
|
|
69
69
|
let quarantinedButNotAttemptToFixFqns = new Set()
|
|
70
70
|
let rootDir = ''
|
|
71
|
+
let sessionProjects = []
|
|
72
|
+
|
|
71
73
|
const MINIMUM_SUPPORTED_VERSION_RANGE_EFD = '>=1.38.0' // TODO: remove this once we drop support for v5
|
|
72
74
|
|
|
73
75
|
function isValidKnownTests (receivedKnownTests) {
|
|
@@ -495,6 +497,7 @@ function dispatcherHook (dispatcherExport) {
|
|
|
495
497
|
const dispatcher = this
|
|
496
498
|
const worker = createWorker.apply(this, arguments)
|
|
497
499
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
500
|
+
sessionProjects = projects
|
|
498
501
|
|
|
499
502
|
// for older versions of playwright, `shouldCreateTestSpan` should always be true,
|
|
500
503
|
// since the `_runTest` function wrapper is not available for older versions
|
|
@@ -535,6 +538,7 @@ function dispatcherHookNew (dispatcherExport, runWrapper) {
|
|
|
535
538
|
const dispatcher = this
|
|
536
539
|
const worker = createWorker.apply(this, arguments)
|
|
537
540
|
const projects = getProjectsFromDispatcher(dispatcher)
|
|
541
|
+
sessionProjects = projects
|
|
538
542
|
|
|
539
543
|
worker.on('testBegin', ({ testId }) => {
|
|
540
544
|
const test = getTestByTestId(dispatcher, testId)
|
|
@@ -1255,3 +1259,46 @@ addHook({
|
|
|
1255
1259
|
|
|
1256
1260
|
return workerPackage
|
|
1257
1261
|
})
|
|
1262
|
+
|
|
1263
|
+
function generateSummaryWrapper (generateSummary) {
|
|
1264
|
+
return function () {
|
|
1265
|
+
for (const test of this.suite.allTests()) {
|
|
1266
|
+
// https://github.com/microsoft/playwright/blob/bf92ffecff6f30a292b53430dbaee0207e0c61ad/packages/playwright/src/reporters/base.ts#L279
|
|
1267
|
+
const didNotRun = test.outcome() === 'skipped' &&
|
|
1268
|
+
(!test.results.length || test.expectedStatus !== 'skipped')
|
|
1269
|
+
if (didNotRun) {
|
|
1270
|
+
const {
|
|
1271
|
+
_requireFile: testSuiteAbsolutePath,
|
|
1272
|
+
location: { line: testSourceLine },
|
|
1273
|
+
} = test
|
|
1274
|
+
const browserName = getBrowserNameFromProjects(sessionProjects, test)
|
|
1275
|
+
|
|
1276
|
+
testSkipCh.publish({
|
|
1277
|
+
testName: getTestFullname(test),
|
|
1278
|
+
testSuiteAbsolutePath,
|
|
1279
|
+
testSourceLine,
|
|
1280
|
+
browserName,
|
|
1281
|
+
})
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return generateSummary.apply(this, arguments)
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// If a playwright project B has a dependency on project A,
|
|
1289
|
+
// and project A fails, the tests in project B will not run.
|
|
1290
|
+
// This hook is used to report tests that did not run as skipped.
|
|
1291
|
+
// Note: this is different from tests skipped via test.skip() or test.fixme()
|
|
1292
|
+
addHook({
|
|
1293
|
+
name: 'playwright',
|
|
1294
|
+
file: 'lib/reporters/base.js',
|
|
1295
|
+
versions: ['>=1.38.0']
|
|
1296
|
+
}, (reportersPackage) => {
|
|
1297
|
+
// v1.50.0 changed the name of the base reporter from BaseReporter to TerminalReporter
|
|
1298
|
+
if (reportersPackage.TerminalReporter) {
|
|
1299
|
+
shimmer.wrap(reportersPackage.TerminalReporter.prototype, 'generateSummary', generateSummaryWrapper)
|
|
1300
|
+
} else if (reportersPackage.BaseReporter) {
|
|
1301
|
+
shimmer.wrap(reportersPackage.BaseReporter.prototype, 'generateSummary', generateSummaryWrapper)
|
|
1302
|
+
}
|
|
1303
|
+
return reportersPackage
|
|
1304
|
+
})
|
|
@@ -146,33 +146,34 @@ function createWrapRouterMethod (name) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
function wrapMethod (original) {
|
|
149
|
-
return shimmer.wrapFunction(original, original => function methodWithTrace (
|
|
149
|
+
return shimmer.wrapFunction(original, original => function methodWithTrace (...args) {
|
|
150
150
|
let offset = 0
|
|
151
151
|
if (this.stack) {
|
|
152
152
|
offset = Array.isArray(this.stack) ? this.stack.length : 1
|
|
153
153
|
}
|
|
154
|
-
const router = original.
|
|
154
|
+
const router = original.apply(this, args)
|
|
155
155
|
|
|
156
156
|
if (typeof this.stack === 'function') {
|
|
157
157
|
this.stack = [{ handle: this.stack }]
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
if (routeAddedChannel.hasSubscribers) {
|
|
161
|
-
routeAddedChannel.publish({ topOfStackFunc: methodWithTrace, layer: this.stack
|
|
161
|
+
routeAddedChannel.publish({ topOfStackFunc: methodWithTrace, layer: this.stack?.at(-1) })
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
const fn = args[0]
|
|
165
|
+
|
|
164
166
|
// Publish only if this router was mounted by app.use() (prevents early '/sub/...')
|
|
165
167
|
if (routeAddedChannel.hasSubscribers && isAppMounted(this) && this.stack?.length > offset) {
|
|
166
168
|
// Handle nested router mounting for 'use' method
|
|
167
|
-
if (original.name === 'use' &&
|
|
169
|
+
if (original.name === 'use' && args.length >= 2) {
|
|
168
170
|
const { mountPaths, startIdx } = extractMountPaths(fn)
|
|
169
171
|
|
|
170
172
|
if (mountPaths.length) {
|
|
171
173
|
const parentPaths = getRouterMountPaths(this)
|
|
172
|
-
const callArgs = [fn, ...otherArgs]
|
|
173
174
|
|
|
174
|
-
for (let i = startIdx; i <
|
|
175
|
-
const nestedRouter =
|
|
175
|
+
for (let i = startIdx; i < args.length; i++) {
|
|
176
|
+
const nestedRouter = args[i]
|
|
176
177
|
|
|
177
178
|
if (!nestedRouter || typeof nestedRouter !== 'function') continue
|
|
178
179
|
|
|
@@ -206,7 +207,7 @@ function createWrapRouterMethod (name) {
|
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
|
|
209
|
-
if (this.stack
|
|
210
|
+
if (this.stack?.length > offset) {
|
|
210
211
|
wrapStack(this.stack.slice(offset), extractMatchers(fn))
|
|
211
212
|
}
|
|
212
213
|
|
|
@@ -60,6 +60,7 @@ let testManagementAttemptToFixRetries = 0
|
|
|
60
60
|
let isDiEnabled = false
|
|
61
61
|
let testCodeCoverageLinesTotal
|
|
62
62
|
let isSessionStarted = false
|
|
63
|
+
let vitestPool = null
|
|
63
64
|
|
|
64
65
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 400
|
|
65
66
|
|
|
@@ -157,6 +158,14 @@ function isTestPackage (testPackage) {
|
|
|
157
158
|
return testPackage.V?.name === 'VitestTestRunner'
|
|
158
159
|
}
|
|
159
160
|
|
|
161
|
+
function hasForksPoolWorker (vitestPackage) {
|
|
162
|
+
return vitestPackage.f?.name === 'ForksPoolWorker'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function hasThreadsPoolWorker (vitestPackage) {
|
|
166
|
+
return vitestPackage.T?.name === 'ThreadsPoolWorker'
|
|
167
|
+
}
|
|
168
|
+
|
|
160
169
|
function getSessionStatus (state) {
|
|
161
170
|
if (state.getCountOfFailedTests() > 0) {
|
|
162
171
|
return 'fail'
|
|
@@ -389,6 +398,7 @@ function getFinishWrapper (exitOrClose) {
|
|
|
389
398
|
isEarlyFlakeDetectionEnabled,
|
|
390
399
|
isEarlyFlakeDetectionFaulty,
|
|
391
400
|
isTestManagementTestsEnabled,
|
|
401
|
+
vitestPool,
|
|
392
402
|
onFinish
|
|
393
403
|
})
|
|
394
404
|
|
|
@@ -418,11 +428,27 @@ function getCreateCliWrapper (vitestPackage, frameworkVersion) {
|
|
|
418
428
|
}
|
|
419
429
|
|
|
420
430
|
function threadHandler (thread) {
|
|
421
|
-
|
|
431
|
+
const { runtime } = thread
|
|
432
|
+
let workerProcess
|
|
433
|
+
if (runtime === 'child_process') {
|
|
434
|
+
vitestPool = 'child_process'
|
|
435
|
+
workerProcess = thread.process
|
|
436
|
+
} else if (runtime === 'worker_threads') {
|
|
437
|
+
vitestPool = 'worker_threads'
|
|
438
|
+
workerProcess = thread.thread
|
|
439
|
+
} else {
|
|
440
|
+
vitestPool = 'unknown'
|
|
441
|
+
}
|
|
442
|
+
if (!workerProcess) {
|
|
443
|
+
log.error('Vitest error: could not get process or thread from TinyPool#run')
|
|
422
444
|
return
|
|
423
445
|
}
|
|
424
|
-
|
|
425
|
-
|
|
446
|
+
|
|
447
|
+
if (workerProcesses.has(workerProcess)) {
|
|
448
|
+
return
|
|
449
|
+
}
|
|
450
|
+
workerProcesses.add(workerProcess)
|
|
451
|
+
workerProcess.on('message', (message) => {
|
|
426
452
|
if (message.__tinypool_worker_message__ && message.data) {
|
|
427
453
|
if (message.interprocessCode === VITEST_WORKER_TRACE_PAYLOAD_CODE) {
|
|
428
454
|
workerReportTraceCh.publish(message.data)
|
|
@@ -433,11 +459,7 @@ function threadHandler (thread) {
|
|
|
433
459
|
})
|
|
434
460
|
}
|
|
435
461
|
|
|
436
|
-
|
|
437
|
-
name: 'tinypool',
|
|
438
|
-
versions: ['>=1.0.0'],
|
|
439
|
-
file: 'dist/index.js'
|
|
440
|
-
}, (TinyPool) => {
|
|
462
|
+
function wrapTinyPoolRun (TinyPool) {
|
|
441
463
|
shimmer.wrap(TinyPool.prototype, 'run', run => async function () {
|
|
442
464
|
// We have to do this before and after because the threads list gets recycled, that is, the processes are re-created
|
|
443
465
|
this.threads.forEach(threadHandler)
|
|
@@ -445,15 +467,79 @@ addHook({
|
|
|
445
467
|
this.threads.forEach(threadHandler)
|
|
446
468
|
return runResult
|
|
447
469
|
})
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
addHook({
|
|
473
|
+
name: 'tinypool',
|
|
474
|
+
// version from tinypool@0.8 was used in vitest@1.6.0
|
|
475
|
+
versions: ['>=0.8.0 <1.0.0'],
|
|
476
|
+
file: 'dist/esm/index.js'
|
|
477
|
+
}, (TinyPool) => {
|
|
478
|
+
wrapTinyPoolRun(TinyPool)
|
|
479
|
+
return TinyPool
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
addHook({
|
|
483
|
+
name: 'tinypool',
|
|
484
|
+
versions: ['>=1.0.0'],
|
|
485
|
+
file: 'dist/index.js'
|
|
486
|
+
}, (TinyPool) => {
|
|
487
|
+
wrapTinyPoolRun(TinyPool)
|
|
448
488
|
|
|
449
489
|
return TinyPool
|
|
450
490
|
})
|
|
451
491
|
|
|
492
|
+
function getWrappedOn (on) {
|
|
493
|
+
return function (event, callback) {
|
|
494
|
+
if (event !== 'message') {
|
|
495
|
+
return on.apply(this, arguments)
|
|
496
|
+
}
|
|
497
|
+
// `arguments[1]` is the callback function, which
|
|
498
|
+
// we modify to intercept our messages to not interfere
|
|
499
|
+
// with vitest's own messages
|
|
500
|
+
arguments[1] = shimmer.wrapFunction(callback, callback => function (message) {
|
|
501
|
+
if (message.type !== 'Buffer' && Array.isArray(message)) {
|
|
502
|
+
const [interprocessCode, data] = message
|
|
503
|
+
if (interprocessCode === VITEST_WORKER_TRACE_PAYLOAD_CODE) {
|
|
504
|
+
workerReportTraceCh.publish(data)
|
|
505
|
+
} else if (interprocessCode === VITEST_WORKER_LOGS_PAYLOAD_CODE) {
|
|
506
|
+
workerReportLogsCh.publish(data)
|
|
507
|
+
}
|
|
508
|
+
// If we execute the callback vitest crashes, as the message is not supported
|
|
509
|
+
return
|
|
510
|
+
}
|
|
511
|
+
return callback.apply(this, arguments)
|
|
512
|
+
})
|
|
513
|
+
return on.apply(this, arguments)
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
452
517
|
function getStartVitestWrapper (cliApiPackage, frameworkVersion) {
|
|
453
518
|
if (!isCliApiPackage(cliApiPackage)) {
|
|
454
519
|
return cliApiPackage
|
|
455
520
|
}
|
|
456
521
|
shimmer.wrap(cliApiPackage, 's', getCliOrStartVitestWrapper(frameworkVersion))
|
|
522
|
+
|
|
523
|
+
if (hasForksPoolWorker(cliApiPackage)) {
|
|
524
|
+
// function is async
|
|
525
|
+
shimmer.wrap(cliApiPackage.f.prototype, 'start', start => function () {
|
|
526
|
+
vitestPool = 'child_process'
|
|
527
|
+
this.env.DD_VITEST_WORKER = '1'
|
|
528
|
+
|
|
529
|
+
return start.apply(this, arguments)
|
|
530
|
+
})
|
|
531
|
+
shimmer.wrap(cliApiPackage.f.prototype, 'on', getWrappedOn)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (hasThreadsPoolWorker(cliApiPackage)) {
|
|
535
|
+
// function is async
|
|
536
|
+
shimmer.wrap(cliApiPackage.T.prototype, 'start', start => function () {
|
|
537
|
+
vitestPool = 'worker_threads'
|
|
538
|
+
this.env.DD_VITEST_WORKER = '1'
|
|
539
|
+
return start.apply(this, arguments)
|
|
540
|
+
})
|
|
541
|
+
shimmer.wrap(cliApiPackage.T.prototype, 'on', getWrappedOn)
|
|
542
|
+
}
|
|
457
543
|
return cliApiPackage
|
|
458
544
|
}
|
|
459
545
|
|
|
@@ -51,7 +51,8 @@ const {
|
|
|
51
51
|
} = require('../../dd-trace/src/ci-visibility/telemetry')
|
|
52
52
|
|
|
53
53
|
const BREAKPOINT_HIT_GRACE_PERIOD_MS = 200
|
|
54
|
-
const BREAKPOINT_SET_GRACE_PERIOD_MS =
|
|
54
|
+
const BREAKPOINT_SET_GRACE_PERIOD_MS = 400
|
|
55
|
+
|
|
55
56
|
const isCucumberWorker = !!getEnvironmentVariable('CUCUMBER_WORKER_ID')
|
|
56
57
|
|
|
57
58
|
class CucumberPlugin extends CiPlugin {
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
const pick = require('../../datadog-core/src/utils/src/pick')
|
|
4
4
|
const log = require('../../dd-trace/src/log')
|
|
5
5
|
|
|
6
|
+
function getEmptyObject () {
|
|
7
|
+
return {}
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
module.exports = {
|
|
7
11
|
getMethodMetadata (path, kind) {
|
|
8
12
|
const tags = {
|
|
@@ -57,6 +61,6 @@ module.exports = {
|
|
|
57
61
|
log.error('Expected \'%s\' to be an array or function.', filter)
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
return
|
|
64
|
+
return getEmptyObject
|
|
61
65
|
}
|
|
62
66
|
}
|
|
@@ -183,13 +183,17 @@ function normalizeClientConfig (config) {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
function is400ErrorCode (code) {
|
|
187
|
+
return code < 400 || code >= 500
|
|
188
|
+
}
|
|
189
|
+
|
|
186
190
|
function getStatusValidator (config) {
|
|
187
191
|
if (typeof config.validateStatus === 'function') {
|
|
188
192
|
return config.validateStatus
|
|
189
193
|
} else if (config.hasOwnProperty('validateStatus')) {
|
|
190
194
|
log.error('Expected `validateStatus` to be a function.')
|
|
191
195
|
}
|
|
192
|
-
return
|
|
196
|
+
return is400ErrorCode
|
|
193
197
|
}
|
|
194
198
|
|
|
195
199
|
function getFilter (config) {
|
|
@@ -162,13 +162,17 @@ function hasAmazonSignature (headers, path) {
|
|
|
162
162
|
return false
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
function is400ErrorCode (code) {
|
|
166
|
+
return code < 400 || code >= 500
|
|
167
|
+
}
|
|
168
|
+
|
|
165
169
|
function getStatusValidator (config) {
|
|
166
170
|
if (typeof config.validateStatus === 'function') {
|
|
167
171
|
return config.validateStatus
|
|
168
172
|
} else if (config.hasOwnProperty('validateStatus')) {
|
|
169
173
|
log.error('Expected `validateStatus` to be a function.')
|
|
170
174
|
}
|
|
171
|
-
return
|
|
175
|
+
return is400ErrorCode
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
function normalizeConfig (config) {
|
|
@@ -107,8 +107,33 @@ function constructChatCompletionResponseFromStreamedChunks (chunks, n) {
|
|
|
107
107
|
})
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Constructs the entire response from a stream of OpenAI responses chunks.
|
|
112
|
+
* The responses API uses event-based streaming with delta chunks.
|
|
113
|
+
* @param {Array<Record<string, any>>} chunks
|
|
114
|
+
* @returns {Record<string, any>}
|
|
115
|
+
*/
|
|
116
|
+
function constructResponseResponseFromStreamedChunks (chunks) {
|
|
117
|
+
// The responses API streams events with different types:
|
|
118
|
+
// - response.output_text.delta: incremental text deltas
|
|
119
|
+
// - response.output_text.done: complete text for a content part
|
|
120
|
+
// - response.output_item.done: complete output item with role
|
|
121
|
+
// - response.done/response.incomplete/response.completed: final response with output array and usage
|
|
122
|
+
|
|
123
|
+
// Find the last chunk with a complete response object (status: done, incomplete, or completed)
|
|
124
|
+
const responseStatusSet = new Set(['done', 'incomplete', 'completed'])
|
|
125
|
+
|
|
126
|
+
for (let i = chunks.length - 1; i >= 0; i--) {
|
|
127
|
+
const chunk = chunks[i]
|
|
128
|
+
if (chunk.response && responseStatusSet.has(chunk.response.status)) {
|
|
129
|
+
return chunk.response
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
110
134
|
module.exports = {
|
|
111
135
|
convertBuffersToObjects,
|
|
112
136
|
constructCompletionResponseFromStreamedChunks,
|
|
113
|
-
constructChatCompletionResponseFromStreamedChunks
|
|
137
|
+
constructChatCompletionResponseFromStreamedChunks,
|
|
138
|
+
constructResponseResponseFromStreamedChunks
|
|
114
139
|
}
|