dd-trace 4.44.0 → 4.46.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.
Files changed (108) hide show
  1. package/index.d.ts +2 -1
  2. package/package.json +5 -5
  3. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  4. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  5. package/packages/datadog-instrumentations/src/aws-sdk.js +4 -4
  6. package/packages/datadog-instrumentations/src/body-parser.js +17 -5
  7. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  8. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  9. package/packages/datadog-instrumentations/src/connect.js +4 -4
  10. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  11. package/packages/datadog-instrumentations/src/couchbase.js +12 -12
  12. package/packages/datadog-instrumentations/src/cucumber.js +16 -5
  13. package/packages/datadog-instrumentations/src/dns.js +10 -10
  14. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  15. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +3 -3
  16. package/packages/datadog-instrumentations/src/express.js +4 -4
  17. package/packages/datadog-instrumentations/src/fastify.js +6 -6
  18. package/packages/datadog-instrumentations/src/fetch.js +1 -1
  19. package/packages/datadog-instrumentations/src/find-my-way.js +2 -2
  20. package/packages/datadog-instrumentations/src/fs.js +2 -2
  21. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +2 -2
  22. package/packages/datadog-instrumentations/src/grpc/client.js +4 -6
  23. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  24. package/packages/datadog-instrumentations/src/hapi.js +10 -13
  25. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -2
  26. package/packages/datadog-instrumentations/src/helpers/register.js +9 -2
  27. package/packages/datadog-instrumentations/src/http/client.js +3 -3
  28. package/packages/datadog-instrumentations/src/jest.js +5 -4
  29. package/packages/datadog-instrumentations/src/knex.js +2 -2
  30. package/packages/datadog-instrumentations/src/koa.js +5 -5
  31. package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
  32. package/packages/datadog-instrumentations/src/mariadb.js +8 -8
  33. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  34. package/packages/datadog-instrumentations/src/microgateway-core.js +4 -4
  35. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  36. package/packages/datadog-instrumentations/src/mocha/main.js +91 -70
  37. package/packages/datadog-instrumentations/src/mocha/utils.js +2 -3
  38. package/packages/datadog-instrumentations/src/mocha.js +4 -0
  39. package/packages/datadog-instrumentations/src/moleculer/server.js +2 -2
  40. package/packages/datadog-instrumentations/src/mongodb-core.js +7 -7
  41. package/packages/datadog-instrumentations/src/mongoose.js +5 -6
  42. package/packages/datadog-instrumentations/src/mysql.js +3 -3
  43. package/packages/datadog-instrumentations/src/mysql2.js +6 -6
  44. package/packages/datadog-instrumentations/src/net.js +2 -2
  45. package/packages/datadog-instrumentations/src/next.js +5 -5
  46. package/packages/datadog-instrumentations/src/nyc.js +23 -0
  47. package/packages/datadog-instrumentations/src/openai.js +58 -69
  48. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  49. package/packages/datadog-instrumentations/src/passport-http.js +1 -1
  50. package/packages/datadog-instrumentations/src/passport-local.js +1 -1
  51. package/packages/datadog-instrumentations/src/passport-utils.js +1 -1
  52. package/packages/datadog-instrumentations/src/pg.js +1 -1
  53. package/packages/datadog-instrumentations/src/pino.js +4 -4
  54. package/packages/datadog-instrumentations/src/playwright.js +6 -4
  55. package/packages/datadog-instrumentations/src/redis.js +2 -2
  56. package/packages/datadog-instrumentations/src/restify.js +4 -4
  57. package/packages/datadog-instrumentations/src/rhea.js +4 -4
  58. package/packages/datadog-instrumentations/src/router.js +5 -5
  59. package/packages/datadog-instrumentations/src/sharedb.js +2 -2
  60. package/packages/datadog-instrumentations/src/vitest.js +22 -5
  61. package/packages/datadog-instrumentations/src/winston.js +2 -3
  62. package/packages/datadog-plugin-cucumber/src/index.js +12 -2
  63. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +21 -10
  64. package/packages/datadog-plugin-hapi/src/index.js +2 -2
  65. package/packages/datadog-plugin-jest/src/index.js +18 -4
  66. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  67. package/packages/datadog-plugin-nyc/src/index.js +35 -0
  68. package/packages/datadog-plugin-openai/src/index.js +58 -47
  69. package/packages/datadog-plugin-playwright/src/index.js +9 -4
  70. package/packages/datadog-plugin-vitest/src/index.js +30 -4
  71. package/packages/datadog-shimmer/src/shimmer.js +144 -10
  72. package/packages/dd-trace/src/appsec/blocking.js +23 -17
  73. package/packages/dd-trace/src/appsec/graphql.js +3 -1
  74. package/packages/dd-trace/src/appsec/iast/iast-log.js +2 -1
  75. package/packages/dd-trace/src/appsec/remote_config/manager.js +4 -1
  76. package/packages/dd-trace/src/appsec/rule_manager.js +8 -0
  77. package/packages/dd-trace/src/appsec/telemetry.js +3 -3
  78. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +40 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -4
  80. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -4
  81. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +2 -1
  82. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +8 -7
  83. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -4
  84. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -4
  85. package/packages/dd-trace/src/ci-visibility/telemetry.js +29 -2
  86. package/packages/dd-trace/src/config.js +157 -142
  87. package/packages/dd-trace/src/lambda/handler.js +1 -0
  88. package/packages/dd-trace/src/lambda/index.js +12 -1
  89. package/packages/dd-trace/src/opentelemetry/context_manager.js +22 -39
  90. package/packages/dd-trace/src/opentelemetry/span_context.js +2 -2
  91. package/packages/dd-trace/src/opentelemetry/tracer.js +23 -14
  92. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +9 -1
  93. package/packages/dd-trace/src/opentracing/propagation/log.js +1 -1
  94. package/packages/dd-trace/src/opentracing/propagation/text_map.js +61 -6
  95. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  96. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  97. package/packages/dd-trace/src/plugins/index.js +1 -0
  98. package/packages/dd-trace/src/plugins/util/git.js +14 -1
  99. package/packages/dd-trace/src/plugins/util/test.js +1 -5
  100. package/packages/dd-trace/src/profiler.js +15 -5
  101. package/packages/dd-trace/src/profiling/config.js +2 -4
  102. package/packages/dd-trace/src/profiling/exporter_cli.js +13 -1
  103. package/packages/dd-trace/src/profiling/exporters/agent.js +7 -1
  104. package/packages/dd-trace/src/profiling/profiler.js +0 -9
  105. package/packages/dd-trace/src/profiling/ssi-heuristics.js +49 -58
  106. package/packages/dd-trace/src/proxy.js +21 -21
  107. package/packages/dd-trace/src/telemetry/index.js +24 -7
  108. package/packages/dd-trace/src/telemetry/logs/index.js +20 -0
@@ -88,12 +88,10 @@ function wrapMethod (method, path, type, hasPeer) {
88
88
  return method
89
89
  }
90
90
 
91
- const wrapped = function () {
91
+ const wrapped = shimmer.wrapFunction(method, method => function () {
92
92
  const args = ensureMetadata(this, arguments, 1)
93
93
  return callMethod(this, method, args, path, args[1], type, hasPeer)
94
- }
95
-
96
- Object.assign(wrapped, method)
94
+ })
97
95
 
98
96
  patched.add(wrapped)
99
97
 
@@ -101,7 +99,7 @@ function wrapMethod (method, path, type, hasPeer) {
101
99
  }
102
100
 
103
101
  function wrapCallback (ctx, callback = () => { }) {
104
- return function (err) {
102
+ return shimmer.wrapFunction(callback, callback => function (err) {
105
103
  if (err) {
106
104
  ctx.error = err
107
105
  errorChannel.publish(ctx)
@@ -111,7 +109,7 @@ function wrapCallback (ctx, callback = () => { }) {
111
109
  return callback.apply(this, arguments)
112
110
  // No async end channel needed
113
111
  })
114
- }
112
+ })
115
113
  }
116
114
 
117
115
  function createWrapEmit (ctx, hasPeer = false) {
@@ -119,7 +119,7 @@ function wrapStream (call, ctx, onCancel) {
119
119
  }
120
120
 
121
121
  function wrapCallback (callback = () => {}, call, ctx, onCancel) {
122
- return function (err, value, trailer, flags) {
122
+ return shimmer.wrapFunction(callback, callback => function (err, value, trailer, flags) {
123
123
  if (err) {
124
124
  ctx.error = err
125
125
  errorChannel.publish(ctx)
@@ -136,7 +136,7 @@ function wrapCallback (callback = () => {}, call, ctx, onCancel) {
136
136
  return callback.apply(this, arguments)
137
137
  // No async end channel needed
138
138
  })
139
- }
139
+ })
140
140
  }
141
141
 
142
142
  function wrapSendStatus (sendStatus, ctx) {
@@ -1,12 +1,13 @@
1
1
  'use strict'
2
2
 
3
+ const tracingChannel = require('dc-polyfill').tracingChannel
3
4
  const shimmer = require('../../datadog-shimmer')
4
- const { addHook, channel, AsyncResource } = require('./helpers/instrument')
5
+ const { addHook, channel } = require('./helpers/instrument')
5
6
 
6
7
  const handleChannel = channel('apm:hapi:request:handle')
7
8
  const routeChannel = channel('apm:hapi:request:route')
8
9
  const errorChannel = channel('apm:hapi:request:error')
9
- const enterChannel = channel('apm:hapi:extension:enter')
10
+ const hapiTracingChannel = tracingChannel('apm:hapi:extension')
10
11
 
11
12
  function wrapServer (server) {
12
13
  return function (options) {
@@ -27,17 +28,17 @@ function wrapServer (server) {
27
28
  }
28
29
 
29
30
  function wrapStart (start) {
30
- return function () {
31
+ return shimmer.wrapFunction(start, start => function () {
31
32
  if (this && typeof this.ext === 'function') {
32
33
  this.ext('onPreResponse', onPreResponse)
33
34
  }
34
35
 
35
36
  return start.apply(this, arguments)
36
- }
37
+ })
37
38
  }
38
39
 
39
40
  function wrapExt (ext) {
40
- return function (events, method, options) {
41
+ return shimmer.wrapFunction(ext, ext => function (events, method, options) {
41
42
  if (events !== null && typeof events === 'object') {
42
43
  arguments[0] = wrapEvents(events)
43
44
  } else {
@@ -45,7 +46,7 @@ function wrapExt (ext) {
45
46
  }
46
47
 
47
48
  return ext.apply(this, arguments)
48
- }
49
+ })
49
50
  }
50
51
 
51
52
  function wrapDispatch (dispatch) {
@@ -91,19 +92,15 @@ function wrapEvents (events) {
91
92
  function wrapHandler (handler) {
92
93
  if (typeof handler !== 'function') return handler
93
94
 
94
- return function (request, h) {
95
+ return shimmer.wrapFunction(handler, handler => function (request, h) {
95
96
  const req = request && request.raw && request.raw.req
96
97
 
97
98
  if (!req) return handler.apply(this, arguments)
98
99
 
99
- const asyncResource = new AsyncResource('bound-anonymous-fn')
100
-
101
- return asyncResource.runInAsyncScope(() => {
102
- enterChannel.publish({ req })
103
-
100
+ return hapiTracingChannel.traceSync(() => {
104
101
  return handler.apply(this, arguments)
105
102
  })
106
- }
103
+ })
107
104
  }
108
105
 
109
106
  function onPreResponse (request, h) {
@@ -72,7 +72,6 @@ module.exports = {
72
72
  'microgateway-core': () => require('../microgateway-core'),
73
73
  mocha: () => require('../mocha'),
74
74
  'mocha-each': () => require('../mocha'),
75
- workerpool: () => require('../mocha'),
76
75
  moleculer: () => require('../moleculer'),
77
76
  mongodb: () => require('../mongodb'),
78
77
  'mongodb-core': () => require('../mongodb-core'),
@@ -89,6 +88,7 @@ module.exports = {
89
88
  'node:http2': () => require('../http2'),
90
89
  'node:https': () => require('../http'),
91
90
  'node:net': () => require('../net'),
91
+ nyc: () => require('../nyc'),
92
92
  oracledb: () => require('../oracledb'),
93
93
  openai: () => require('../openai'),
94
94
  paperplane: () => require('../paperplane'),
@@ -113,5 +113,6 @@ module.exports = {
113
113
  undici: () => require('../undici'),
114
114
  vitest: { esmFirst: true, fn: () => require('../vitest') },
115
115
  when: () => require('../when'),
116
- winston: () => require('../winston')
116
+ winston: () => require('../winston'),
117
+ workerpool: () => require('../mocha')
117
118
  }
@@ -90,8 +90,15 @@ for (const packageName of names) {
90
90
  }
91
91
 
92
92
  if (matchesFile) {
93
- const version = moduleVersion || getVersion(moduleBaseDir)
94
- if (!Object.hasOwnProperty(namesAndSuccesses, name)) {
93
+ let version = moduleVersion
94
+ try {
95
+ version = version || getVersion(moduleBaseDir)
96
+ } catch (e) {
97
+ log.error(`Error getting version for "${name}": ${e.message}`)
98
+ log.error(e)
99
+ continue
100
+ }
101
+ if (typeof namesAndSuccesses[`${name}@${version}`] === 'undefined') {
95
102
  namesAndSuccesses[`${name}@${version}`] = false
96
103
  }
97
104
 
@@ -52,11 +52,11 @@ function patch (http, methodName) {
52
52
  let callback = args.callback
53
53
 
54
54
  if (callback) {
55
- callback = function () {
55
+ callback = shimmer.wrapFunction(args.callback, cb => function () {
56
56
  return asyncStartChannel.runStores(ctx, () => {
57
- return args.callback.apply(this, arguments)
57
+ return cb.apply(this, arguments)
58
58
  })
59
- }
59
+ })
60
60
  }
61
61
 
62
62
  const options = args.options
@@ -12,8 +12,7 @@ const {
12
12
  getTestParametersString,
13
13
  addEfdStringToTestName,
14
14
  removeEfdStringFromTestName,
15
- getIsFaultyEarlyFlakeDetection,
16
- NUM_FAILED_TEST_RETRIES
15
+ getIsFaultyEarlyFlakeDetection
17
16
  } = require('../../dd-trace/src/plugins/util/test')
18
17
  const {
19
18
  getFormattedJestTestParameters,
@@ -132,6 +131,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
132
131
 
133
132
  this.isEarlyFlakeDetectionEnabled = this.testEnvironmentOptions._ddIsEarlyFlakeDetectionEnabled
134
133
  this.isFlakyTestRetriesEnabled = this.testEnvironmentOptions._ddIsFlakyTestRetriesEnabled
134
+ this.flakyTestRetriesCount = this.testEnvironmentOptions._ddFlakyTestRetriesCount
135
135
 
136
136
  if (this.isEarlyFlakeDetectionEnabled) {
137
137
  const hasKnownTests = !!knownTests.jest
@@ -149,7 +149,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
149
149
  if (this.isFlakyTestRetriesEnabled) {
150
150
  const currentNumRetries = this.global[RETRY_TIMES]
151
151
  if (!currentNumRetries) {
152
- this.global[RETRY_TIMES] = NUM_FAILED_TEST_RETRIES
152
+ this.global[RETRY_TIMES] = this.flakyTestRetriesCount
153
153
  }
154
154
  }
155
155
  }
@@ -638,7 +638,7 @@ addHook({
638
638
 
639
639
  function jestAdapterWrapper (jestAdapter, jestVersion) {
640
640
  const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
641
- const newAdapter = shimmer.wrap(adapter, function () {
641
+ const newAdapter = shimmer.wrapFunction(adapter, adapter => function () {
642
642
  const environment = arguments[2]
643
643
  if (!environment) {
644
644
  return adapter.apply(this, arguments)
@@ -773,6 +773,7 @@ addHook({
773
773
  _ddEarlyFlakeDetectionNumRetries,
774
774
  _ddRepositoryRoot,
775
775
  _ddIsFlakyTestRetriesEnabled,
776
+ _ddFlakyTestRetriesCount,
776
777
  ...restOfTestEnvironmentOptions
777
778
  } = testEnvironmentOptions
778
779
 
@@ -81,8 +81,8 @@ addHook({
81
81
  function wrapCallbackWithFinish (callback, finish) {
82
82
  if (typeof callback !== 'function') return callback
83
83
 
84
- return function () {
84
+ return shimmer.wrapFunction(callback, callback => function () {
85
85
  finish()
86
86
  callback.apply(this, arguments)
87
- }
87
+ })
88
88
  }
@@ -71,7 +71,7 @@ function wrapStack (layer) {
71
71
 
72
72
  middleware = original || middleware
73
73
 
74
- const handler = shimmer.wrap(middleware, wrapMiddleware(middleware, layer))
74
+ const handler = shimmer.wrapFunction(middleware, middleware => wrapMiddleware(middleware, layer))
75
75
 
76
76
  originals.set(handler, middleware)
77
77
 
@@ -84,7 +84,7 @@ function wrapMiddleware (fn, layer) {
84
84
 
85
85
  const name = fn.name
86
86
 
87
- return function (ctx, next) {
87
+ return shimmer.wrapFunction(fn, fn => function (ctx, next) {
88
88
  if (!ctx || !enterChannel.hasSubscribers) return fn.apply(this, arguments)
89
89
 
90
90
  const req = ctx.req
@@ -122,7 +122,7 @@ function wrapMiddleware (fn, layer) {
122
122
  } finally {
123
123
  exitChannel.publish({ req })
124
124
  }
125
- }
125
+ })
126
126
  }
127
127
 
128
128
  function fulfill (ctx, error) {
@@ -142,11 +142,11 @@ function fulfill (ctx, error) {
142
142
  }
143
143
 
144
144
  function wrapNext (req, next) {
145
- return function () {
145
+ return shimmer.wrapFunction(next, next => function () {
146
146
  nextChannel.publish({ req })
147
147
 
148
148
  return next.apply(this, arguments)
149
- }
149
+ })
150
150
  }
151
151
 
152
152
  addHook({ name: 'koa', versions: ['>=2'] }, Koa => {
@@ -77,7 +77,7 @@ addHook({ name: 'ldapjs', versions: ['>=2'] }, ldapjs => {
77
77
  if (callbackIndex > -1) {
78
78
  const callback = arguments[callbackIndex]
79
79
  // eslint-disable-next-line n/handle-callback-err
80
- arguments[callbackIndex] = shimmer.wrap(callback, function (err, corkedEmitter) {
80
+ arguments[callbackIndex] = shimmer.wrapFunction(callback, callback => function (err, corkedEmitter) {
81
81
  if (corkedEmitter !== null && typeof corkedEmitter === 'object' && typeof corkedEmitter.on === 'function') {
82
82
  wrapEmitter(corkedEmitter)
83
83
  }
@@ -11,7 +11,7 @@ const skipCh = channel('apm:mariadb:pool:skip')
11
11
  const unskipCh = channel('apm:mariadb:pool:unskip')
12
12
 
13
13
  function wrapCommandStart (start, callbackResource) {
14
- return function () {
14
+ return shimmer.wrapFunction(start, start => function () {
15
15
  if (!startCh.hasSubscribers) return start.apply(this, arguments)
16
16
 
17
17
  const resolve = callbackResource.bind(this.resolve)
@@ -44,7 +44,7 @@ function wrapCommandStart (start, callbackResource) {
44
44
  startCh.publish({ sql: this.sql, conf: this.opts })
45
45
  return start.apply(this, arguments)
46
46
  })
47
- }
47
+ })
48
48
  }
49
49
 
50
50
  function wrapCommand (Command) {
@@ -98,7 +98,7 @@ function createWrapQueryCallback (options) {
98
98
  arguments.length = arguments.length + 1
99
99
  }
100
100
 
101
- arguments[arguments.length - 1] = asyncResource.bind(function (err) {
101
+ arguments[arguments.length - 1] = shimmer.wrapFunction(cb, cb => asyncResource.bind(function (err) {
102
102
  if (err) {
103
103
  errorCh.publish(err)
104
104
  }
@@ -108,7 +108,7 @@ function createWrapQueryCallback (options) {
108
108
  if (typeof cb === 'function') {
109
109
  return callbackResource.runInAsyncScope(() => cb.apply(this, arguments))
110
110
  }
111
- })
111
+ }))
112
112
 
113
113
  return asyncResource.runInAsyncScope(() => {
114
114
  startCh.publish({ sql, conf: options })
@@ -119,7 +119,7 @@ function createWrapQueryCallback (options) {
119
119
  }
120
120
  }
121
121
 
122
- function wrapConnection (Connection, promiseMethod) {
122
+ function wrapConnection (promiseMethod, Connection) {
123
123
  return function (options) {
124
124
  Connection.apply(this, arguments)
125
125
 
@@ -170,13 +170,13 @@ addHook({ name, file: 'lib/pool.js', versions: ['>=3'] }, (Pool) => {
170
170
  })
171
171
 
172
172
  addHook({ name, file: 'lib/connection.js', versions: ['>=2.5.2 <3'] }, (Connection) => {
173
- return shimmer.wrap(Connection, wrapConnection(Connection, '_queryPromise'))
173
+ return shimmer.wrapFunction(Connection, wrapConnection.bind(null, '_queryPromise'))
174
174
  })
175
175
 
176
176
  addHook({ name, file: 'lib/connection.js', versions: ['>=2.0.4 <=2.5.1'] }, (Connection) => {
177
- return shimmer.wrap(Connection, wrapConnection(Connection, 'query'))
177
+ return shimmer.wrapFunction(Connection, wrapConnection.bind(null, 'query'))
178
178
  })
179
179
 
180
180
  addHook({ name, file: 'lib/pool-base.js', versions: ['>=2.0.4 <3'] }, (PoolBase) => {
181
- return shimmer.wrap(PoolBase, wrapPoolBase(PoolBase))
181
+ return shimmer.wrapFunction(PoolBase, wrapPoolBase)
182
182
  })
@@ -26,14 +26,14 @@ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
26
26
  const query = queryCompiler.apply(this, arguments)
27
27
  const callback = callbackResource.bind(query.callback)
28
28
 
29
- query.callback = asyncResource.bind(function (err) {
29
+ query.callback = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err) {
30
30
  if (err) {
31
31
  errorCh.publish(err)
32
32
  }
33
33
  finishCh.publish()
34
34
 
35
35
  return callback.apply(this, arguments)
36
- })
36
+ }))
37
37
  startCh.publish({ client, server, query })
38
38
 
39
39
  return query
@@ -40,7 +40,7 @@ function wrapPluginsFactory (pluginsFactory) {
40
40
  }
41
41
 
42
42
  function wrapNext (req, res, next) {
43
- return function nextWithTrace (err) {
43
+ return shimmer.wrapFunction(next, next => function nextWithTrace (err) {
44
44
  const requestResource = requestResources.get(req)
45
45
 
46
46
  requestResource.runInAsyncScope(() => {
@@ -54,13 +54,13 @@ function wrapNext (req, res, next) {
54
54
  })
55
55
 
56
56
  return next.apply(this, arguments)
57
- }
57
+ })
58
58
  }
59
59
 
60
60
  addHook({ name, versions, file: 'lib/config-proxy-middleware.js' }, configProxyFactory => {
61
- return shimmer.wrap(configProxyFactory, wrapConfigProxyFactory(configProxyFactory))
61
+ return shimmer.wrapFunction(configProxyFactory, wrapConfigProxyFactory)
62
62
  })
63
63
 
64
64
  addHook({ name, versions, file: 'lib/plugins-middleware.js' }, pluginsFactory => {
65
- return shimmer.wrap(pluginsFactory, wrapPluginsFactory(pluginsFactory))
65
+ return shimmer.wrapFunction(pluginsFactory, wrapPluginsFactory)
66
66
  })
@@ -15,7 +15,7 @@ addHook({
15
15
 
16
16
  patched.add(mochaEach)
17
17
 
18
- return shimmer.wrap(mochaEach, function () {
18
+ return shimmer.wrapFunction(mochaEach, mochaEach => function () {
19
19
  const [params] = arguments
20
20
  const { it, ...rest } = mochaEach.apply(this, arguments)
21
21
  return {
@@ -47,6 +47,7 @@ const config = {}
47
47
 
48
48
  // We'll preserve the original coverage here
49
49
  const originalCoverageMap = createCoverageMap()
50
+ let untestedCoverage
50
51
 
51
52
  // test channels
52
53
  const testStartCh = channel('ci:mocha:test:start')
@@ -66,6 +67,8 @@ const testSessionStartCh = channel('ci:mocha:session:start')
66
67
  const testSessionFinishCh = channel('ci:mocha:session:finish')
67
68
  const itrSkippedSuitesCh = channel('ci:mocha:itr:skipped-suites')
68
69
 
70
+ const getCodeCoverageCh = channel('ci:nyc:get-coverage')
71
+
69
72
  function getFilteredSuites (originalSuites) {
70
73
  return originalSuites.reduce((acc, suite) => {
71
74
  const testPath = getTestSuitePath(suite.file, process.cwd())
@@ -131,6 +134,9 @@ function getOnEndHandler (isParallel) {
131
134
  let testCodeCoverageLinesTotal
132
135
  if (global.__coverage__) {
133
136
  try {
137
+ if (untestedCoverage) {
138
+ originalCoverageMap.merge(fromCoverageMapToCoverage(untestedCoverage))
139
+ }
134
140
  testCodeCoverageLinesTotal = originalCoverageMap.getCoverageSummary().lines.pct
135
141
  } catch (e) {
136
142
  // ignore errors
@@ -153,6 +159,84 @@ function getOnEndHandler (isParallel) {
153
159
  })
154
160
  }
155
161
 
162
+ function getExecutionConfiguration (runner, onFinishRequest) {
163
+ const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
164
+
165
+ const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
166
+ if (err) {
167
+ suitesToSkip = []
168
+ } else {
169
+ suitesToSkip = skippableSuites
170
+ itrCorrelationId = responseItrCorrelationId
171
+ }
172
+ // We remove the suites that we skip through ITR
173
+ const filteredSuites = getFilteredSuites(runner.suite.suites)
174
+ const { suitesToRun } = filteredSuites
175
+
176
+ isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
177
+
178
+ log.debug(
179
+ () => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
180
+ )
181
+
182
+ runner.suite.suites = suitesToRun
183
+
184
+ skippedSuites = Array.from(filteredSuites.skippedSuites)
185
+
186
+ onFinishRequest()
187
+ }
188
+
189
+ const onReceivedKnownTests = ({ err, knownTests: receivedKnownTests }) => {
190
+ if (err) {
191
+ knownTests = []
192
+ isEarlyFlakeDetectionEnabled = false
193
+ } else {
194
+ knownTests = receivedKnownTests
195
+ }
196
+
197
+ if (isSuitesSkippingEnabled) {
198
+ skippableSuitesCh.publish({
199
+ onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
200
+ })
201
+ } else {
202
+ onFinishRequest()
203
+ }
204
+ }
205
+
206
+ const onReceivedConfiguration = ({ err, libraryConfig }) => {
207
+ if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
208
+ return onFinishRequest()
209
+ }
210
+
211
+ isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
212
+ isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
213
+ earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
214
+ isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
215
+
216
+ config.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
217
+ config.isSuitesSkippingEnabled = isSuitesSkippingEnabled
218
+ config.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
219
+ config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
220
+ config.flakyTestRetriesCount = libraryConfig.flakyTestRetriesCount
221
+
222
+ if (isEarlyFlakeDetectionEnabled) {
223
+ knownTestsCh.publish({
224
+ onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
225
+ })
226
+ } else if (isSuitesSkippingEnabled) {
227
+ skippableSuitesCh.publish({
228
+ onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
229
+ })
230
+ } else {
231
+ onFinishRequest()
232
+ }
233
+ }
234
+
235
+ libraryConfigurationCh.publish({
236
+ onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
237
+ })
238
+ }
239
+
156
240
  // In this hook we delay the execution with options.delay to grab library configuration,
157
241
  // skippable and known tests.
158
242
  // It is called but skipped in parallel mode.
@@ -161,7 +245,6 @@ addHook({
161
245
  versions: ['>=5.2.0'],
162
246
  file: 'lib/mocha.js'
163
247
  }, (Mocha) => {
164
- const mochaRunAsyncResource = new AsyncResource('bound-anonymous-fn')
165
248
  shimmer.wrap(Mocha.prototype, 'run', run => function () {
166
249
  // Workers do not need to request any data, just run the tests
167
250
  if (!testStartCh.hasSubscribers || process.env.MOCHA_WORKER_ID || this.options.parallel) {
@@ -181,79 +264,17 @@ addHook({
181
264
  }
182
265
  })
183
266
 
184
- const onReceivedSkippableSuites = ({ err, skippableSuites, itrCorrelationId: responseItrCorrelationId }) => {
185
- if (err) {
186
- suitesToSkip = []
187
- } else {
188
- suitesToSkip = skippableSuites
189
- itrCorrelationId = responseItrCorrelationId
190
- }
191
- // We remove the suites that we skip through ITR
192
- const filteredSuites = getFilteredSuites(runner.suite.suites)
193
- const { suitesToRun } = filteredSuites
194
-
195
- isSuitesSkipped = suitesToRun.length !== runner.suite.suites.length
196
-
197
- log.debug(
198
- () => `${suitesToRun.length} out of ${runner.suite.suites.length} suites are going to run.`
199
- )
200
-
201
- runner.suite.suites = suitesToRun
202
-
203
- skippedSuites = Array.from(filteredSuites.skippedSuites)
204
-
205
- global.run()
206
- }
207
-
208
- const onReceivedKnownTests = ({ err, knownTests: receivedKnownTests }) => {
209
- if (err) {
210
- knownTests = []
211
- isEarlyFlakeDetectionEnabled = false
212
- } else {
213
- knownTests = receivedKnownTests
214
- }
215
-
216
- if (isSuitesSkippingEnabled) {
217
- skippableSuitesCh.publish({
218
- onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
267
+ getExecutionConfiguration(runner, () => {
268
+ if (getCodeCoverageCh.hasSubscribers) {
269
+ getCodeCoverageCh.publish({
270
+ onDone: (receivedCodeCoverage) => {
271
+ untestedCoverage = receivedCodeCoverage
272
+ global.run()
273
+ }
219
274
  })
220
275
  } else {
221
276
  global.run()
222
277
  }
223
- }
224
-
225
- const onReceivedConfiguration = ({ err, libraryConfig }) => {
226
- if (err || !skippableSuitesCh.hasSubscribers || !knownTestsCh.hasSubscribers) {
227
- return global.run()
228
- }
229
-
230
- isEarlyFlakeDetectionEnabled = libraryConfig.isEarlyFlakeDetectionEnabled
231
- isSuitesSkippingEnabled = libraryConfig.isSuitesSkippingEnabled
232
- earlyFlakeDetectionNumRetries = libraryConfig.earlyFlakeDetectionNumRetries
233
- isFlakyTestRetriesEnabled = libraryConfig.isFlakyTestRetriesEnabled
234
-
235
- config.isEarlyFlakeDetectionEnabled = isEarlyFlakeDetectionEnabled
236
- config.isSuitesSkippingEnabled = isSuitesSkippingEnabled
237
- config.earlyFlakeDetectionNumRetries = earlyFlakeDetectionNumRetries
238
- config.isFlakyTestRetriesEnabled = isFlakyTestRetriesEnabled
239
-
240
- if (isEarlyFlakeDetectionEnabled) {
241
- knownTestsCh.publish({
242
- onDone: mochaRunAsyncResource.bind(onReceivedKnownTests)
243
- })
244
- } else if (isSuitesSkippingEnabled) {
245
- skippableSuitesCh.publish({
246
- onDone: mochaRunAsyncResource.bind(onReceivedSkippableSuites)
247
- })
248
- } else {
249
- global.run()
250
- }
251
- }
252
-
253
- mochaRunAsyncResource.runInAsyncScope(() => {
254
- libraryConfigurationCh.publish({
255
- onDone: mochaRunAsyncResource.bind(onReceivedConfiguration)
256
- })
257
278
  })
258
279
 
259
280
  return runner
@@ -3,8 +3,7 @@
3
3
  const {
4
4
  getTestSuitePath,
5
5
  removeEfdStringFromTestName,
6
- addEfdStringToTestName,
7
- NUM_FAILED_TEST_RETRIES
6
+ addEfdStringToTestName
8
7
  } = require('../../../dd-trace/src/plugins/util/test')
9
8
  const { channel, AsyncResource } = require('../helpers/instrument')
10
9
  const shimmer = require('../../../datadog-shimmer')
@@ -114,7 +113,7 @@ function runnableWrapper (RunnablePackage, libraryConfig) {
114
113
  }
115
114
  // Flaky test retries does not work in parallel mode
116
115
  if (libraryConfig?.isFlakyTestRetriesEnabled) {
117
- this.retries(NUM_FAILED_TEST_RETRIES)
116
+ this.retries(libraryConfig?.flakyTestRetriesCount)
118
117
  }
119
118
  // The reason why the wrapping logic is here is because we need to cover
120
119
  // `afterEach` and `beforeEach` hooks as well.
@@ -3,3 +3,7 @@ if (process.env.MOCHA_WORKER_ID) {
3
3
  } else {
4
4
  require('./mocha/main')
5
5
  }
6
+
7
+ // TODO add appropriate calls to wrapFunction whenever we're adding a callback
8
+ // wrapper. Right now this is less of an issue since that only has effect in
9
+ // SSI, where CI Vis isn't supported.
@@ -24,7 +24,7 @@ function createMiddleware () {
24
24
  localAction (next, action) {
25
25
  const broker = this
26
26
 
27
- return function datadogMiddleware (ctx) {
27
+ return shimmer.wrapFunction(next, next => function datadogMiddleware (ctx) {
28
28
  const actionResource = new AsyncResource('bound-anonymous-fn')
29
29
 
30
30
  return actionResource.runInAsyncScope(() => {
@@ -47,7 +47,7 @@ function createMiddleware () {
47
47
  finishChannel.publish()
48
48
  }
49
49
  })
50
- }
50
+ })
51
51
  }
52
52
  }
53
53
  }