datadog-ci 1.1.0 → 1.3.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -2
  3. data/ext/datadog_cov/datadog_cov.c +259 -67
  4. data/lib/datadog/ci/configuration/components.rb +149 -80
  5. data/lib/datadog/ci/configuration/settings.rb +6 -0
  6. data/lib/datadog/ci/contrib/cucumber/formatter.rb +13 -9
  7. data/lib/datadog/ci/contrib/minitest/runnable.rb +5 -1
  8. data/lib/datadog/ci/contrib/minitest/runner.rb +6 -2
  9. data/lib/datadog/ci/contrib/minitest/test.rb +7 -3
  10. data/lib/datadog/ci/contrib/rspec/example.rb +6 -2
  11. data/lib/datadog/ci/contrib/rspec/example_group.rb +5 -1
  12. data/lib/datadog/ci/contrib/rspec/knapsack_pro/runner.rb +6 -2
  13. data/lib/datadog/ci/contrib/rspec/runner.rb +6 -2
  14. data/lib/datadog/ci/ext/environment/providers/appveyor.rb +1 -1
  15. data/lib/datadog/ci/ext/environment/providers/aws_code_pipeline.rb +1 -1
  16. data/lib/datadog/ci/ext/environment/providers/azure.rb +1 -1
  17. data/lib/datadog/ci/ext/environment/providers/bitbucket.rb +1 -1
  18. data/lib/datadog/ci/ext/environment/providers/bitrise.rb +1 -1
  19. data/lib/datadog/ci/ext/environment/providers/buddy.rb +1 -1
  20. data/lib/datadog/ci/ext/environment/providers/buildkite.rb +1 -1
  21. data/lib/datadog/ci/ext/environment/providers/circleci.rb +1 -1
  22. data/lib/datadog/ci/ext/environment/providers/codefresh.rb +1 -1
  23. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +1 -1
  24. data/lib/datadog/ci/ext/environment/providers/gitlab.rb +1 -1
  25. data/lib/datadog/ci/ext/environment/providers/jenkins.rb +1 -1
  26. data/lib/datadog/ci/ext/environment/providers/teamcity.rb +1 -1
  27. data/lib/datadog/ci/ext/environment/providers/travis.rb +1 -1
  28. data/lib/datadog/ci/ext/environment.rb +17 -0
  29. data/lib/datadog/ci/ext/settings.rb +1 -0
  30. data/lib/datadog/ci/ext/telemetry.rb +120 -0
  31. data/lib/datadog/ci/git/local_repository.rb +116 -25
  32. data/lib/datadog/ci/git/search_commits.rb +20 -1
  33. data/lib/datadog/ci/git/telemetry.rb +37 -0
  34. data/lib/datadog/ci/git/tree_uploader.rb +7 -0
  35. data/lib/datadog/ci/git/upload_packfile.rb +22 -1
  36. data/lib/datadog/ci/span.rb +3 -3
  37. data/lib/datadog/ci/test.rb +6 -1
  38. data/lib/datadog/ci/test_module.rb +1 -1
  39. data/lib/datadog/ci/{itr/runner.rb → test_optimisation/component.rb} +29 -12
  40. data/lib/datadog/ci/{itr → test_optimisation}/coverage/ddcov.rb +1 -1
  41. data/lib/datadog/ci/{itr → test_optimisation}/coverage/event.rb +1 -1
  42. data/lib/datadog/ci/{itr → test_optimisation}/coverage/transport.rb +11 -2
  43. data/lib/datadog/ci/{itr → test_optimisation}/coverage/writer.rb +1 -1
  44. data/lib/datadog/ci/{itr → test_optimisation}/skippable.rb +25 -1
  45. data/lib/datadog/ci/test_optimisation/telemetry.rb +56 -0
  46. data/lib/datadog/ci/test_session.rb +1 -1
  47. data/lib/datadog/ci/test_suite.rb +1 -1
  48. data/lib/datadog/ci/test_visibility/component.rb +282 -0
  49. data/lib/datadog/ci/test_visibility/{recorder.rb → context.rb} +39 -187
  50. data/lib/datadog/ci/test_visibility/{null_recorder.rb → null_component.rb} +6 -4
  51. data/lib/datadog/ci/test_visibility/{context → store}/global.rb +1 -1
  52. data/lib/datadog/ci/test_visibility/{context → store}/local.rb +1 -1
  53. data/lib/datadog/ci/test_visibility/telemetry.rb +69 -0
  54. data/lib/datadog/ci/test_visibility/transport.rb +9 -10
  55. data/lib/datadog/ci/transport/adapters/net.rb +42 -11
  56. data/lib/datadog/ci/transport/adapters/net_http_client.rb +17 -0
  57. data/lib/datadog/ci/transport/adapters/telemetry_webmock_safe_adapter.rb +28 -0
  58. data/lib/datadog/ci/transport/event_platform_transport.rb +42 -5
  59. data/lib/datadog/ci/transport/http.rb +49 -21
  60. data/lib/datadog/ci/transport/remote_settings_api.rb +39 -1
  61. data/lib/datadog/ci/transport/telemetry.rb +93 -0
  62. data/lib/datadog/ci/utils/identity.rb +20 -0
  63. data/lib/datadog/ci/utils/parsing.rb +2 -1
  64. data/lib/datadog/ci/utils/telemetry.rb +23 -0
  65. data/lib/datadog/ci/version.rb +1 -1
  66. data/lib/datadog/ci.rb +45 -15
  67. metadata +24 -14
@@ -4,87 +4,49 @@ require "datadog/tracing"
4
4
  require "datadog/tracing/contrib/component"
5
5
  require "datadog/tracing/trace_digest"
6
6
 
7
- require "rbconfig"
7
+ require_relative "store/global"
8
+ require_relative "store/local"
8
9
 
9
- require_relative "context/global"
10
- require_relative "context/local"
11
-
12
- require_relative "../codeowners/parser"
13
- require_relative "../contrib/contrib"
14
10
  require_relative "../ext/app_types"
15
- require_relative "../ext/test"
16
11
  require_relative "../ext/environment"
17
- require_relative "../git/local_repository"
12
+ require_relative "../ext/test"
18
13
 
19
14
  require_relative "../span"
20
15
  require_relative "../test"
21
16
  require_relative "../test_session"
22
17
  require_relative "../test_module"
23
18
  require_relative "../test_suite"
24
- require_relative "../worker"
25
19
 
26
20
  module Datadog
27
21
  module CI
28
22
  module TestVisibility
29
- # Common behavior for CI tests
30
- # Note: this class has too many responsibilities and should be split into multiple classes
31
- class Recorder
32
- attr_reader :environment_tags, :test_suite_level_visibility_enabled
33
-
34
- def initialize(
35
- itr:,
36
- remote_settings_api:,
37
- git_tree_upload_worker: DummyWorker.new,
38
- test_suite_level_visibility_enabled: false,
39
- codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse
40
- )
41
- @test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
42
-
43
- @environment_tags = Ext::Environment.tags(ENV).freeze
44
- @local_context = Context::Local.new
45
- @global_context = Context::Global.new
46
-
47
- @codeowners = codeowners
48
-
49
- @itr = itr
50
- @remote_settings_api = remote_settings_api
51
- @git_tree_upload_worker = git_tree_upload_worker
52
- end
53
-
54
- def shutdown!
55
- @git_tree_upload_worker.stop
23
+ # Manages current in-memory context for test visibility (such as active test session, suite, test, etc.).
24
+ # Its responsibility includes building domain models for test visibility as well.
25
+ # Internally it uses Datadog::Tracing module to create spans.
26
+ class Context
27
+ def initialize
28
+ @local_context = Store::Local.new
29
+ @global_context = Store::Global.new
56
30
  end
57
31
 
58
32
  def start_test_session(service: nil, tags: {})
59
- return skip_tracing unless test_suite_level_visibility_enabled
60
-
61
- # finds and instruments additional test libraries that we support (ex: selenium-webdriver)
62
- Contrib.auto_instrument_on_session_start!
63
-
64
33
  @global_context.fetch_or_activate_test_session do
65
34
  tracer_span = start_datadog_tracer_span(
66
- "test.session", build_span_options(service, Ext::AppTypes::TYPE_TEST_SESSION)
35
+ "test.session", build_tracing_span_options(service, Ext::AppTypes::TYPE_TEST_SESSION)
67
36
  )
68
37
  set_session_context(tags, tracer_span)
69
38
 
70
- test_session = build_test_session(tracer_span, tags)
71
-
72
- @git_tree_upload_worker.perform(test_session.git_repository_url)
73
- configure_library(test_session)
74
-
75
- test_session
39
+ build_test_session(tracer_span, tags)
76
40
  end
77
41
  end
78
42
 
79
43
  def start_test_module(test_module_name, service: nil, tags: {})
80
- return skip_tracing unless test_suite_level_visibility_enabled
81
-
82
44
  @global_context.fetch_or_activate_test_module do
83
45
  set_inherited_globals(tags)
84
46
  set_session_context(tags)
85
47
 
86
48
  tracer_span = start_datadog_tracer_span(
87
- test_module_name, build_span_options(service, Ext::AppTypes::TYPE_TEST_MODULE)
49
+ test_module_name, build_tracing_span_options(service, Ext::AppTypes::TYPE_TEST_MODULE)
88
50
  )
89
51
  set_module_context(tags, tracer_span)
90
52
 
@@ -93,15 +55,13 @@ module Datadog
93
55
  end
94
56
 
95
57
  def start_test_suite(test_suite_name, service: nil, tags: {})
96
- return skip_tracing unless test_suite_level_visibility_enabled
97
-
98
58
  @global_context.fetch_or_activate_test_suite(test_suite_name) do
99
59
  set_inherited_globals(tags)
100
60
  set_session_context(tags)
101
61
  set_module_context(tags)
102
62
 
103
63
  tracer_span = start_datadog_tracer_span(
104
- test_suite_name, build_span_options(service, Ext::AppTypes::TYPE_TEST_SUITE)
64
+ test_suite_name, build_tracing_span_options(service, Ext::AppTypes::TYPE_TEST_SUITE)
105
65
  )
106
66
  set_suite_context(tags, span: tracer_span)
107
67
 
@@ -118,7 +78,7 @@ module Datadog
118
78
  tags[Ext::Test::TAG_NAME] = test_name
119
79
  tags[Ext::Test::TAG_TYPE] ||= Ext::Test::Type::TEST
120
80
 
121
- span_options = build_span_options(
81
+ span_options = build_tracing_span_options(
122
82
  service,
123
83
  Ext::AppTypes::TYPE_TEST,
124
84
  # :resource is needed for the agent APM protocol to work correctly (for older agent versions)
@@ -131,25 +91,19 @@ module Datadog
131
91
  test = build_test(tracer_span, tags)
132
92
 
133
93
  @local_context.activate_test(test) do
134
- on_test_started(test)
135
- res = block.call(test)
136
- on_test_finished(test)
137
- res
94
+ block.call(test)
138
95
  end
139
96
  end
140
97
  else
141
98
  tracer_span = start_datadog_tracer_span(test_name, span_options)
142
99
  test = build_test(tracer_span, tags)
143
-
144
100
  @local_context.activate_test(test)
145
- on_test_started(test)
146
-
147
101
  test
148
102
  end
149
103
  end
150
104
 
151
105
  def trace(span_name, type: "span", tags: {}, &block)
152
- span_options = build_span_options(
106
+ span_options = build_tracing_span_options(
153
107
  nil, # service name is completely optional for custom spans
154
108
  type,
155
109
  {resource: span_name}
@@ -187,17 +141,15 @@ module Datadog
187
141
  @global_context.active_test_suite(test_suite_name)
188
142
  end
189
143
 
190
- def deactivate_test
191
- test = active_test
192
- on_test_finished(test) if test
144
+ def single_active_test_suite
145
+ @global_context.fetch_single_test_suite
146
+ end
193
147
 
148
+ def deactivate_test
194
149
  @local_context.deactivate_test
195
150
  end
196
151
 
197
152
  def deactivate_test_session
198
- test_session = active_test_session
199
- on_test_session_finished(test_session) if test_session
200
-
201
153
  @global_context.deactivate_test_session!
202
154
  end
203
155
 
@@ -209,47 +161,9 @@ module Datadog
209
161
  @global_context.deactivate_test_suite!(test_suite_name)
210
162
  end
211
163
 
212
- def itr_enabled?
213
- @itr.enabled?
214
- end
215
-
216
164
  private
217
165
 
218
- def configure_library(test_session)
219
- # this will change when EFD is implemented
220
- return unless itr_enabled?
221
-
222
- remote_configuration = @remote_settings_api.fetch_library_settings(test_session)
223
- # sometimes we can skip code coverage for default branch if there are no changes in the repository
224
- # backend needs git metadata uploaded for this test session to check if we can skip code coverage
225
- if remote_configuration.require_git?
226
- Datadog.logger.debug { "Library configuration endpoint requires git upload to be finished, waiting..." }
227
- @git_tree_upload_worker.wait_until_done
228
-
229
- Datadog.logger.debug { "Requesting library configuration again..." }
230
- remote_configuration = @remote_settings_api.fetch_library_settings(test_session)
231
-
232
- if remote_configuration.require_git?
233
- Datadog.logger.debug { "git metadata upload did not complete in time when configuring library" }
234
- end
235
- end
236
-
237
- @itr.configure(
238
- remote_configuration.payload,
239
- test_session: test_session,
240
- git_tree_upload_worker: @git_tree_upload_worker
241
- )
242
- end
243
-
244
- def skip_tracing(block = nil)
245
- block&.call(nil)
246
- end
247
-
248
- # Sets trace's origin to ciapp-test
249
- def set_trace_origin(trace)
250
- trace&.origin = Ext::Test::CONTEXT_ORIGIN
251
- end
252
-
166
+ # BUILDING DOMAIN MODELS
253
167
  def build_test_session(tracer_span, tags)
254
168
  test_session = TestSession.new(tracer_span)
255
169
  set_initial_tags(test_session, tags)
@@ -271,14 +185,6 @@ module Datadog
271
185
  def build_test(tracer_span, tags)
272
186
  test = Test.new(tracer_span)
273
187
  set_initial_tags(test, tags)
274
-
275
- # sometimes test suite is not being assigned correctly
276
- # fix it by fetching the one single running test suite from the global context
277
- fix_test_suite!(test) if test.test_suite_id.nil?
278
-
279
- validate_test_suite_level_visibility_correctness(test)
280
- set_codeowners(test)
281
-
282
188
  test
283
189
  end
284
190
 
@@ -288,13 +194,18 @@ module Datadog
288
194
  span
289
195
  end
290
196
 
291
- def build_span_options(service, type, other_options = {})
292
- other_options[:service] = service || @global_context.service
293
- other_options[:type] = type
197
+ # TAGGING
198
+ def set_initial_tags(ci_span, tags)
199
+ @environment_tags ||= Ext::Environment.tags(ENV).freeze
294
200
 
295
- other_options
201
+ ci_span.set_default_tags
202
+ ci_span.set_environment_runtime_tags
203
+
204
+ ci_span.set_tags(tags)
205
+ ci_span.set_tags(@environment_tags)
296
206
  end
297
207
 
208
+ # PROPAGATING CONTEXT FROM TOP-LEVEL TO THE LOWER LEVELS
298
209
  def set_inherited_globals(tags)
299
210
  # this code achieves the same as @global_context.inheritable_session_tags.merge(tags)
300
211
  # but without allocating a new hash
@@ -303,14 +214,6 @@ module Datadog
303
214
  end
304
215
  end
305
216
 
306
- def set_initial_tags(ci_span, tags)
307
- ci_span.set_default_tags
308
- ci_span.set_environment_runtime_tags
309
-
310
- ci_span.set_tags(tags)
311
- ci_span.set_tags(environment_tags)
312
- end
313
-
314
217
  def set_session_context(tags, test_session = nil)
315
218
  test_session ||= active_test_session
316
219
  tags[Ext::Test::TAG_TEST_SESSION_ID] = test_session.id.to_s if test_session
@@ -324,12 +227,6 @@ module Datadog
324
227
  end
325
228
  end
326
229
 
327
- def set_codeowners(test)
328
- source = test.source_file
329
- owners = @codeowners.list_owners(source) if source
330
- test.set_tag(Ext::Test::TAG_CODEOWNERS, owners) unless owners.nil?
331
- end
332
-
333
230
  def set_suite_context(tags, span: nil, name: nil)
334
231
  return if span.nil? && name.nil?
335
232
 
@@ -343,24 +240,7 @@ module Datadog
343
240
  end
344
241
  end
345
242
 
346
- def fix_test_suite!(test)
347
- test_suite = @global_context.fetch_single_test_suite
348
- unless test_suite
349
- Datadog.logger.debug do
350
- "Trying to fix test suite for test [#{test.name}] but no single test suite is running."
351
- end
352
- return
353
- end
354
-
355
- Datadog.logger.debug do
356
- "For test [#{test.name}]: expected test suite [#{test.test_suite_name}] to be running, " \
357
- "but it was not found. Fixing it by assigning test suite [#{test_suite.name}] to the test."
358
- end
359
-
360
- test.set_tag(Ext::Test::TAG_TEST_SUITE_ID, test_suite.id.to_s)
361
- test.set_tag(Ext::Test::TAG_SUITE, test_suite.name)
362
- end
363
-
243
+ # INTERACTIONS WITH TRACING
364
244
  def start_datadog_tracer_span(span_name, span_options, &block)
365
245
  if block
366
246
  Datadog::Tracing.trace(span_name, **span_options) do |tracer_span, trace|
@@ -377,44 +257,16 @@ module Datadog
377
257
  end
378
258
  end
379
259
 
380
- def validate_test_suite_level_visibility_correctness(test)
381
- return unless test_suite_level_visibility_enabled
382
-
383
- if test.test_suite_id.nil?
384
- Datadog.logger.debug do
385
- "Test [#{test.name}] does not have a test suite associated with it. " \
386
- "Expected test suite [#{test.test_suite_name}] to be running."
387
- end
388
- end
389
-
390
- if test.test_module_id.nil?
391
- Datadog.logger.debug do
392
- "Test [#{test.name}] does not have a test module associated with it. " \
393
- "Make sure that there is a test module running within a session."
394
- end
395
- end
396
-
397
- if test.test_session_id.nil?
398
- Datadog.logger.debug do
399
- "Test [#{test.name}] does not have a test session associated with it. " \
400
- "Make sure that there is a test session running."
401
- end
402
- end
403
- end
404
-
405
- # TODO: use kind of event system to notify about test finished?
406
- def on_test_finished(test)
407
- @itr.stop_coverage(test)
408
- @itr.count_skipped_test(test)
260
+ # Sets trace's origin to ciapp-test because tracing requires so
261
+ def set_trace_origin(trace)
262
+ trace&.origin = Ext::Test::CONTEXT_ORIGIN
409
263
  end
410
264
 
411
- def on_test_started(test)
412
- @itr.mark_if_skippable(test)
413
- @itr.start_coverage(test)
414
- end
265
+ def build_tracing_span_options(service, type, other_options = {})
266
+ other_options[:service] = service || @global_context.service
267
+ other_options[:type] = type
415
268
 
416
- def on_test_session_finished(test_session)
417
- @itr.write_test_session_tags(test_session)
269
+ other_options
418
270
  end
419
271
  end
420
272
  end
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "recorder"
4
-
5
3
  module Datadog
6
4
  module CI
7
5
  module TestVisibility
8
- # Special recorder that does not record anything
9
- class NullRecorder
6
+ # Special test visibility component that does not record anything
7
+ class NullComponent
10
8
  def start_test_session(service: nil, tags: {})
11
9
  skip_tracing
12
10
  end
@@ -45,6 +43,10 @@ module Datadog
45
43
  def shutdown!
46
44
  end
47
45
 
46
+ def itr_enabled?
47
+ false
48
+ end
49
+
48
50
  private
49
51
 
50
52
  def skip_tracing(block = nil)
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module CI
5
5
  module TestVisibility
6
- module Context
6
+ module Store
7
7
  # This context is shared between threads and represents the current test session and test module.
8
8
  class Global
9
9
  def initialize
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module CI
5
5
  module TestVisibility
6
- module Context
6
+ module Store
7
7
  class Local
8
8
  def initialize
9
9
  @key = :datadog_ci_active_test
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext/app_types"
4
+ require_relative "../ext/environment"
5
+ require_relative "../ext/telemetry"
6
+ require_relative "../ext/test"
7
+ require_relative "../utils/telemetry"
8
+
9
+ module Datadog
10
+ module CI
11
+ module TestVisibility
12
+ # Telemetry for test visibility
13
+ module Telemetry
14
+ SPAN_TYPE_TO_TELEMETRY_EVENT_TYPE = {
15
+ Ext::AppTypes::TYPE_TEST => Ext::Telemetry::EventType::TEST,
16
+ Ext::AppTypes::TYPE_TEST_SUITE => Ext::Telemetry::EventType::SUITE,
17
+ Ext::AppTypes::TYPE_TEST_MODULE => Ext::Telemetry::EventType::MODULE,
18
+ Ext::AppTypes::TYPE_TEST_SESSION => Ext::Telemetry::EventType::SESSION
19
+ }.freeze
20
+
21
+ def self.event_created(span)
22
+ Utils::Telemetry.inc(Ext::Telemetry::METRIC_EVENT_CREATED, 1, event_tags_from_span(span))
23
+ end
24
+
25
+ def self.event_finished(span)
26
+ tags = event_tags_from_span(span)
27
+ add_browser_tags!(span, tags)
28
+ Utils::Telemetry.inc(Ext::Telemetry::METRIC_EVENT_FINISHED, 1, tags)
29
+ end
30
+
31
+ def self.test_session_started(test_session)
32
+ Utils::Telemetry.inc(
33
+ Ext::Telemetry::METRIC_TEST_SESSION,
34
+ 1,
35
+ {
36
+ Ext::Telemetry::TAG_AUTO_INJECTED => "false", # ruby doesn't support auto injection yet
37
+ Ext::Telemetry::TAG_PROVIDER =>
38
+ test_session.get_tag(Ext::Environment::TAG_PROVIDER_NAME) ||
39
+ Ext::Telemetry::Provider::UNSUPPORTED
40
+ }
41
+ )
42
+ end
43
+
44
+ def self.event_tags_from_span(span)
45
+ # base tags for span
46
+ # @type var tags: Hash[String, String]
47
+ tags = {
48
+ Ext::Telemetry::TAG_EVENT_TYPE => SPAN_TYPE_TO_TELEMETRY_EVENT_TYPE.fetch(span.type, "unknown"),
49
+ Ext::Telemetry::TAG_TEST_FRAMEWORK => span.get_tag(Ext::Test::TAG_FRAMEWORK)
50
+ }
51
+
52
+ # ci provider tag
53
+ tags[Ext::Telemetry::TAG_IS_UNSUPPORTED_CI] = "true" if span.get_tag(Ext::Environment::TAG_PROVIDER_NAME).nil?
54
+
55
+ # codeowner tag
56
+ tags[Ext::Telemetry::TAG_HAS_CODEOWNER] = "true" if span.get_tag(Ext::Test::TAG_CODEOWNERS)
57
+
58
+ tags
59
+ end
60
+
61
+ def self.add_browser_tags!(span, tags)
62
+ tags[Ext::Telemetry::TAG_IS_RUM] = "true" if span.get_tag(Ext::Test::TAG_IS_RUM_ACTIVE)
63
+ browser_driver = span.get_tag(Ext::Test::TAG_BROWSER_DRIVER)
64
+ tags[Ext::Telemetry::TAG_BROWSER_DRIVER] = browser_driver if browser_driver
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -3,8 +3,10 @@
3
3
  require "datadog/core/environment/identity"
4
4
 
5
5
  require_relative "serializers/factories/test_level"
6
+ require_relative "../ext/telemetry"
6
7
  require_relative "../ext/transport"
7
8
  require_relative "../transport/event_platform_transport"
9
+ require_relative "../transport/telemetry"
8
10
 
9
11
  module Datadog
10
12
  module CI
@@ -31,6 +33,10 @@ module Datadog
31
33
 
32
34
  private
33
35
 
36
+ def telemetry_endpoint_tag
37
+ Ext::Telemetry::Endpoint::TEST_CYCLE
38
+ end
39
+
34
40
  def send_payload(encoded_payload)
35
41
  api.citestcycle_request(
36
42
  path: Datadog::CI::Ext::Transport::TEST_VISIBILITY_INTAKE_PATH,
@@ -46,21 +52,14 @@ module Datadog
46
52
 
47
53
  def encode_span(trace, span)
48
54
  serializer = serializers_factory.serializer(trace, span, options: {itr_correlation_id: itr&.correlation_id})
49
-
50
55
  if serializer.valid?
51
56
  encoded = encoder.encode(serializer)
52
-
53
- if encoded.size > max_payload_size
54
- # This single event is too large, we can't flush it
55
- Datadog.logger.warn("Dropping test event. Payload too large: '#{span.inspect}'")
56
- Datadog.logger.warn(encoded)
57
-
58
- return nil
59
- end
57
+ return nil if event_too_large?(span, encoded)
60
58
 
61
59
  encoded
62
60
  else
63
61
  Datadog.logger.warn("Invalid event skipped: #{serializer} Errors: #{serializer.validation_errors}")
62
+ CI::Transport::Telemetry.endpoint_payload_dropped(1, endpoint: telemetry_endpoint_tag)
64
63
  nil
65
64
  end
66
65
  end
@@ -100,7 +99,7 @@ module Datadog
100
99
  end
101
100
 
102
101
  def itr
103
- @itr ||= Datadog::CI.send(:itr_runner)
102
+ @test_optimisation ||= Datadog::CI.send(:test_optimisation)
104
103
  end
105
104
  end
106
105
  end
@@ -3,7 +3,9 @@
3
3
  require "datadog/core/transport/response"
4
4
  require "datadog/core/transport/ext"
5
5
 
6
+ require_relative "net_http_client"
6
7
  require_relative "../gzip"
8
+ require_relative "../../ext/telemetry"
7
9
  require_relative "../../ext/transport"
8
10
 
9
11
  module Datadog
@@ -26,7 +28,7 @@ module Datadog
26
28
  end
27
29
 
28
30
  def open(&block)
29
- req = net_http_client.new(hostname, port)
31
+ req = NetHttpClient.original_net_http.new(hostname, port)
30
32
 
31
33
  req.use_ssl = ssl
32
34
  req.open_timeout = req.read_timeout = timeout
@@ -63,6 +65,8 @@ module Datadog
63
65
  include Datadog::Core::Transport::Response
64
66
 
65
67
  attr_reader :http_response
68
+ # Stats for telemetry
69
+ attr_accessor :duration_ms, :request_compressed, :request_size
66
70
 
67
71
  def initialize(http_response)
68
72
  @http_response = http_response
@@ -77,6 +81,10 @@ module Datadog
77
81
  @decompressed_payload = Gzip.decompress(http_response.body)
78
82
  end
79
83
 
84
+ def response_size
85
+ http_response.body.bytesize
86
+ end
87
+
80
88
  def header(name)
81
89
  http_response[name]
82
90
  end
@@ -86,7 +94,10 @@ module Datadog
86
94
  end
87
95
 
88
96
  def ok?
89
- code.between?(200, 299)
97
+ http_code = code
98
+ return false if http_code.nil?
99
+
100
+ http_code.between?(200, 299)
90
101
  end
91
102
 
92
103
  def unsupported?
@@ -98,11 +109,17 @@ module Datadog
98
109
  end
99
110
 
100
111
  def client_error?
101
- code.between?(400, 499)
112
+ http_code = code
113
+ return false if http_code.nil?
114
+
115
+ http_code.between?(400, 499)
102
116
  end
103
117
 
104
118
  def server_error?
105
- code.between?(500, 599)
119
+ http_code = code
120
+ return false if http_code.nil?
121
+
122
+ http_code.between?(500, 599)
106
123
  end
107
124
 
108
125
  def gzipped_content?
@@ -119,17 +136,31 @@ module Datadog
119
136
  first_bytes.b == Ext::Transport::GZIP_MAGIC_NUMBER
120
137
  end
121
138
 
122
- def inspect
123
- "#{super}, http_response:#{http_response}"
139
+ def error
140
+ nil
124
141
  end
125
- end
126
142
 
127
- private
143
+ def telemetry_error_type
144
+ return nil if ok?
145
+
146
+ case error
147
+ when nil
148
+ Ext::Telemetry::ErrorType::STATUS_CODE
149
+ when Timeout::Error
150
+ Ext::Telemetry::ErrorType::TIMEOUT
151
+ else
152
+ Ext::Telemetry::ErrorType::NETWORK
153
+ end
154
+ end
128
155
 
129
- def net_http_client
130
- return ::Net::HTTP unless defined?(WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
156
+ # compatibility with Datadog::Tracing transport layer
157
+ def trace_count
158
+ 0
159
+ end
131
160
 
132
- WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP
161
+ def inspect
162
+ "#{super}, http_response:#{http_response}"
163
+ end
133
164
  end
134
165
  end
135
166
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Transport
6
+ module Adapters
7
+ module NetHttpClient
8
+ def self.original_net_http
9
+ return ::Net::HTTP unless defined?(WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
10
+
11
+ WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "net_http_client"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Transport
8
+ module Adapters
9
+ module TelemetryWebmockSafeAdapter
10
+ def self.included(base)
11
+ base.prepend(InstanceMethods)
12
+ end
13
+
14
+ module InstanceMethods
15
+ def open(&block)
16
+ req = NetHttpClient.original_net_http.new(@hostname, @port)
17
+
18
+ req.use_ssl = @ssl
19
+ req.open_timeout = req.read_timeout = @timeout
20
+
21
+ req.start(&block)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end