datadog-ci 1.33.0 → 1.35.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -2
  3. data/lib/datadog/ci/configuration/components.rb +2 -0
  4. data/lib/datadog/ci/configuration/settings.rb +11 -0
  5. data/lib/datadog/ci/contrib/cucumber/formatter.rb +51 -1
  6. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +5 -0
  7. data/lib/datadog/ci/contrib/minitest/helpers.rb +54 -6
  8. data/lib/datadog/ci/contrib/minitest/runnable.rb +5 -0
  9. data/lib/datadog/ci/contrib/minitest/runnable_minitest_6.rb +5 -0
  10. data/lib/datadog/ci/contrib/minitest/test.rb +21 -27
  11. data/lib/datadog/ci/contrib/patcher.rb +0 -4
  12. data/lib/datadog/ci/contrib/rspec/anonymous_example_name.rb +515 -0
  13. data/lib/datadog/ci/contrib/rspec/example.rb +23 -5
  14. data/lib/datadog/ci/contrib/rspec/example_group.rb +11 -1
  15. data/lib/datadog/ci/contrib/simplecov/result_extractor.rb +9 -1
  16. data/lib/datadog/ci/ext/settings.rb +1 -0
  17. data/lib/datadog/ci/ext/telemetry.rb +1 -0
  18. data/lib/datadog/ci/ext/test.rb +8 -1
  19. data/lib/datadog/ci/remote/library_settings_client.rb +3 -2
  20. data/lib/datadog/ci/source_code/method_inspect.rb +0 -3
  21. data/lib/datadog/ci/test_discovery/component.rb +4 -0
  22. data/lib/datadog/ci/test_impact_analysis/component.rb +176 -59
  23. data/lib/datadog/ci/test_impact_analysis/coverage/event.rb +6 -4
  24. data/lib/datadog/ci/test_impact_analysis/null_component.rb +25 -2
  25. data/lib/datadog/ci/test_impact_analysis/skippable.rb +20 -5
  26. data/lib/datadog/ci/test_impact_analysis/skippable_percentage/estimator.rb +3 -3
  27. data/lib/datadog/ci/test_optimization_cache/readers/legacy.rb +1 -1
  28. data/lib/datadog/ci/test_suite.rb +20 -0
  29. data/lib/datadog/ci/test_tracing/component.rb +10 -0
  30. data/lib/datadog/ci/test_tracing/deprecated_total_coverage_metric.rb +11 -1
  31. data/lib/datadog/ci/utils/configuration.rb +12 -0
  32. data/lib/datadog/ci/utils/test_name.rb +112 -0
  33. data/lib/datadog/ci/version.rb +1 -1
  34. metadata +3 -1
@@ -16,11 +16,8 @@ module Datadog
16
16
  return nil if target.nil?
17
17
  return nil unless LAST_LINE_AVAILABLE
18
18
 
19
- # Ruby has outdated RBS for RubyVM::InstructionSequence where method `of` is not defined
20
- # steep:ignore:start
21
19
  iseq = RubyVM::InstructionSequence.of(target)
22
20
  return nil unless iseq.is_a?(RubyVM::InstructionSequence)
23
- # steep:ignore:end
24
21
 
25
22
  # this function is implemented in ext/datadog_ci_native/datadog_method_inspect.c
26
23
  _native_last_line_from_iseq(iseq)
@@ -4,6 +4,7 @@ require "fileutils"
4
4
  require "json"
5
5
  require_relative "../ext/test"
6
6
  require_relative "../ext/test_discovery"
7
+ require_relative "../utils/test_name"
7
8
 
8
9
  module Datadog
9
10
  module CI
@@ -76,6 +77,9 @@ module Datadog
76
77
  end
77
78
 
78
79
  def record_test(name:, suite:, module_name:, parameters:, source_file:)
80
+ name = name.nil? ? nil : Utils::TestName.normalize(name)
81
+ suite = suite.nil? ? nil : Utils::TestName.normalize(suite)
82
+
79
83
  test_info = {
80
84
  "name" => name,
81
85
  "suite" => suite,
@@ -30,8 +30,8 @@ module Datadog
30
30
 
31
31
  FILE_STORAGE_KEY = "test_impact_analysis_component_state"
32
32
 
33
- attr_reader :correlation_id, :skippable_tests, :skippable_tests_fetch_error,
34
- :enabled, :test_skipping_enabled, :code_coverage_enabled
33
+ attr_reader :correlation_id, :skippable_tests, :skippable_suites, :skippable_tests_fetch_error,
34
+ :enabled, :test_skipping_enabled, :code_coverage_enabled, :test_skipping_mode
35
35
 
36
36
  def initialize(
37
37
  dd_env:,
@@ -39,6 +39,7 @@ module Datadog
39
39
  api: nil,
40
40
  coverage_writer: nil,
41
41
  enabled: false,
42
+ test_skipping_mode: Ext::Test::TIATestSkippingMode::TEST,
42
43
  bundle_location: nil,
43
44
  use_single_threaded_coverage: false,
44
45
  use_allocation_tracing: true,
@@ -48,6 +49,7 @@ module Datadog
48
49
  @api = api
49
50
  @dd_env = dd_env
50
51
  @config_tags = config_tags || {}
52
+ @test_skipping_mode = test_skipping_mode
51
53
 
52
54
  @bundle_location = if bundle_location && !File.absolute_path?(bundle_location)
53
55
  File.join(Git::LocalRepository.root, bundle_location)
@@ -65,6 +67,7 @@ module Datadog
65
67
 
66
68
  @correlation_id = nil
67
69
  @skippable_tests = Set.new
70
+ @skippable_suites = Set.new
68
71
 
69
72
  @mutex = Mutex.new
70
73
 
@@ -92,8 +95,7 @@ module Datadog
92
95
 
93
96
  test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED, @test_skipping_enabled)
94
97
  test_session.set_tag(Ext::Test::TAG_CODE_COVERAGE_ENABLED, @code_coverage_enabled)
95
- # we skip tests, not suites
96
- test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_TYPE, Ext::Test::ITR_TEST_SKIPPING_MODE)
98
+ test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_TYPE, @test_skipping_mode)
97
99
 
98
100
  if @code_coverage_enabled
99
101
  load_datadog_cov!
@@ -102,10 +104,10 @@ module Datadog
102
104
  end
103
105
 
104
106
  # Load external cache or component state first, and if successful, skip fetching skippable tests
105
- if skipping_tests?
107
+ if skipping_tests? || skipping_suites?
106
108
  return if load_component_state
107
109
 
108
- fetch_skippable_tests(test_session)
110
+ fetch_skippables(test_session)
109
111
  store_component_state if test_session.distributed
110
112
  end
111
113
 
@@ -117,7 +119,19 @@ module Datadog
117
119
  end
118
120
 
119
121
  def skipping_tests?
120
- @test_skipping_enabled
122
+ @test_skipping_enabled && test_skipping_mode?
123
+ end
124
+
125
+ def skipping_suites?
126
+ @test_skipping_enabled && suite_skipping_mode?
127
+ end
128
+
129
+ def test_skipping_mode?
130
+ @test_skipping_mode == Ext::Test::TIATestSkippingMode::TEST
131
+ end
132
+
133
+ def suite_skipping_mode?
134
+ @test_skipping_mode == Ext::Test::TIATestSkippingMode::SUITE
121
135
  end
122
136
 
123
137
  def code_coverage?
@@ -174,6 +188,7 @@ module Datadog
174
188
  # @return [void]
175
189
  def on_test_started(test)
176
190
  return if !enabled? || !code_coverage?
191
+ return if suite_skipping_mode?
177
192
 
178
193
  # Stop any in-progress context coverage and store it
179
194
  stop_context_coverage_and_store
@@ -200,6 +215,7 @@ module Datadog
200
215
  # @return [Datadog::CI::TestImpactAnalysis::Coverage::Event, nil] The coverage event or nil
201
216
  def on_test_finished(test, context)
202
217
  return unless enabled?
218
+ return if suite_skipping_mode?
203
219
 
204
220
  # Handle ITR statistics
205
221
  if test.skipped_by_test_impact_analysis?
@@ -222,33 +238,13 @@ module Datadog
222
238
  context_ids = test.context_ids || []
223
239
  merge_context_coverages_into_test(coverage, context_ids)
224
240
 
225
- if coverage.empty?
226
- Telemetry.code_coverage_is_empty
227
- return
228
- end
229
-
230
- # cucumber's gherkin files are not covered by the code coverage collector - we add them here explicitly
231
- test_source_file = test.source_file
232
- ensure_test_source_covered(test_source_file, coverage) unless test_source_file.nil?
233
-
234
- # if we have static dependencies tracking enabled then we can make the coverage
235
- # more precise by fetching which files we depend on based on constants usage
236
- enrich_coverage_with_static_dependencies(coverage)
237
-
238
- Telemetry.code_coverage_files(coverage.size)
239
-
240
- coverage_event = Coverage::Event.new(
241
+ write_coverage_event(
241
242
  test_id: test.id.to_s,
242
243
  test_suite_id: test.test_suite_id.to_s,
243
244
  test_session_id: test.test_session_id.to_s,
245
+ source_file: test.source_file,
244
246
  coverage: coverage
245
247
  )
246
-
247
- Datadog.logger.debug { "Writing coverage event \n #{coverage_event.pretty_inspect}" }
248
-
249
- write(coverage_event)
250
-
251
- coverage_event
252
248
  end
253
249
 
254
250
  # Clears stored context coverage for a specific context.
@@ -271,7 +267,7 @@ module Datadog
271
267
  #
272
268
  # @return [Boolean]
273
269
  def context_coverage_enabled?
274
- enabled? && code_coverage? && !@use_single_threaded_coverage
270
+ enabled? && code_coverage? && !suite_skipping_mode? && !@use_single_threaded_coverage
275
271
  end
276
272
 
277
273
  def skippable?(datadog_test_id)
@@ -280,6 +276,12 @@ module Datadog
280
276
  @mutex.synchronize { @skippable_tests.include?(datadog_test_id) }
281
277
  end
282
278
 
279
+ def skippable_suite?(test_suite_name)
280
+ return false if !enabled? || !skipping_suites?
281
+
282
+ @mutex.synchronize { @skippable_suites.include?(test_suite_name) }
283
+ end
284
+
283
285
  def mark_if_skippable(test)
284
286
  return if !enabled? || !skipping_tests?
285
287
 
@@ -292,6 +294,66 @@ module Datadog
292
294
  end
293
295
  end
294
296
 
297
+ def mark_if_suite_skippable(test_suite)
298
+ return if !enabled? || !skipping_suites?
299
+
300
+ unskippable = test_suite.itr_unskippable?
301
+ Telemetry.itr_unskippable if unskippable
302
+
303
+ unless skippable_suite?(test_suite.name)
304
+ Datadog.logger.debug { "Test suite is not skippable: #{test_suite.name}" }
305
+ return
306
+ end
307
+
308
+ if unskippable
309
+ Telemetry.itr_forced_run
310
+ test_suite.set_tag(Ext::Test::TAG_ITR_FORCED_RUN, "true")
311
+
312
+ Datadog.logger.debug { "Forced run of skippable test suite: #{test_suite.name}" }
313
+ return
314
+ end
315
+
316
+ test_suite.set_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR, "true")
317
+ test_suite.skipped!(reason: Ext::Test::SkipReason::TEST_IMPACT_ANALYSIS)
318
+
319
+ Datadog.logger.debug { "Marked test suite as skippable: #{test_suite.name}" }
320
+ end
321
+
322
+ def on_test_suite_started(test_suite)
323
+ return unless enabled? && suite_skipping_mode?
324
+
325
+ mark_if_suite_skippable(test_suite)
326
+ return if test_suite.should_skip?
327
+ return unless code_coverage?
328
+
329
+ Telemetry.code_coverage_started(test_suite)
330
+ coverage_collector&.start
331
+ end
332
+
333
+ def on_test_suite_finished(test_suite, context)
334
+ return unless enabled? && suite_skipping_mode?
335
+
336
+ if test_suite.skipped_by_test_impact_analysis?
337
+ Telemetry.itr_skipped
338
+ context.incr_tests_skipped_by_tia_count
339
+ return
340
+ end
341
+
342
+ return unless code_coverage?
343
+
344
+ Telemetry.code_coverage_finished(test_suite)
345
+
346
+ coverage = coverage_collector&.stop
347
+
348
+ write_coverage_event(
349
+ test_id: nil,
350
+ test_suite_id: test_suite.id.to_s,
351
+ test_session_id: test_suite.get_tag(Ext::Test::TAG_TEST_SESSION_ID).to_s,
352
+ source_file: test_suite.source_file,
353
+ coverage: coverage
354
+ )
355
+ end
356
+
295
357
  def write_test_session_tags(test_session, skipped_tests_count)
296
358
  return if !enabled?
297
359
 
@@ -302,8 +364,8 @@ module Datadog
302
364
  test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_COUNT, skipped_tests_count)
303
365
  end
304
366
 
305
- def skippable_tests_count
306
- skippable_tests.count
367
+ def skippables_count
368
+ current_skippables.count
307
369
  end
308
370
 
309
371
  def shutdown!
@@ -314,15 +376,17 @@ module Datadog
314
376
  def serialize_state
315
377
  {
316
378
  correlation_id: @correlation_id,
317
- skippable_tests: @skippable_tests
379
+ skippable_tests: @skippable_tests,
380
+ skippable_suites: @skippable_suites
318
381
  }
319
382
  end
320
383
 
321
384
  def restore_state(state)
322
- @mutex.synchronize do
323
- @correlation_id = state[:correlation_id]
324
- @skippable_tests = state[:skippable_tests]
325
- end
385
+ set_skippables(
386
+ correlation_id: state[:correlation_id],
387
+ tests: state[:skippable_tests] || Set.new,
388
+ suites: state[:skippable_suites] || Set.new
389
+ )
326
390
  end
327
391
 
328
392
  def storage_key
@@ -330,24 +394,20 @@ module Datadog
330
394
  end
331
395
 
332
396
  def restore_state_from_datadog_test_runner
333
- Datadog.logger.debug { "Restoring skippable tests from Test Optimization cache" }
397
+ Datadog.logger.debug { "Restoring skippables from Test Optimization cache" }
334
398
 
335
- skippable_tests_data = load_cached_skippable_tests
336
- if skippable_tests_data.nil?
337
- Datadog.logger.debug { "Restoring skippable tests failed, will request again" }
399
+ skippables_data = load_cached_skippable_tests
400
+ if skippables_data.nil?
401
+ Datadog.logger.debug { "Restoring skippables failed, will request again" }
338
402
  return false
339
403
  end
340
404
 
341
- Datadog.logger.debug { "Restored skippable tests from Test Optimization: #{skippable_tests_data}" }
405
+ Datadog.logger.debug { "Restored skippables from Test Optimization: #{skippables_data}" }
342
406
 
343
- skippable_response = Skippable::Response.from_json(skippable_tests_data)
407
+ skippable_response = Skippable::Response.from_json(skippables_data)
408
+ apply_skippable_response(skippable_response)
344
409
 
345
- @mutex.synchronize do
346
- @correlation_id = skippable_response.correlation_id
347
- @skippable_tests = skippable_response.tests
348
- end
349
-
350
- Datadog.logger.debug { "Found [#{@skippable_tests.size}] skippable tests from context" }
410
+ Datadog.logger.debug { "Found [#{skippables_count}] skippable #{@test_skipping_mode}s from context" }
351
411
  Datadog.logger.debug { "ITR correlation ID from context: #{@correlation_id}" }
352
412
 
353
413
  true
@@ -406,27 +466,84 @@ module Datadog
406
466
  coverage[absolute_test_source_file_path] = true
407
467
  end
408
468
 
409
- def fetch_skippable_tests(test_session)
410
- return unless skipping_tests?
469
+ def write_coverage_event(test_id:, test_suite_id:, test_session_id:, source_file:, coverage:)
470
+ coverage ||= {}
471
+ if coverage.empty?
472
+ Telemetry.code_coverage_is_empty
473
+ return
474
+ end
475
+
476
+ ensure_test_source_covered(source_file, coverage) unless source_file.nil?
477
+
478
+ enrich_coverage_with_static_dependencies(coverage)
479
+
480
+ Telemetry.code_coverage_files(coverage.size)
481
+
482
+ coverage_event = Coverage::Event.new(
483
+ test_id: test_id,
484
+ test_suite_id: test_suite_id,
485
+ test_session_id: test_session_id,
486
+ coverage: coverage
487
+ )
488
+
489
+ Datadog.logger.debug { "Writing coverage event \n #{coverage_event.pretty_inspect}" }
490
+
491
+ write(coverage_event)
492
+
493
+ coverage_event
494
+ end
495
+
496
+ def fetch_skippables(test_session)
497
+ return unless skipping_tests? || skipping_suites?
411
498
 
412
499
  # we can only request skippable tests if git metadata is already uploaded
413
500
  git_tree_upload_worker.wait_until_done
414
501
 
415
502
  skippable_response =
416
- Skippable.new(api: @api, dd_env: @dd_env, config_tags: @config_tags)
417
- .fetch_skippable_tests(test_session)
503
+ Skippable.new(
504
+ api: @api,
505
+ dd_env: @dd_env,
506
+ config_tags: @config_tags,
507
+ test_skipping_mode: @test_skipping_mode
508
+ )
509
+ .fetch_skippables(test_session)
418
510
  @skippable_tests_fetch_error = skippable_response.error_message unless skippable_response.ok?
419
511
 
512
+ apply_skippable_response(skippable_response)
513
+
514
+ Datadog.logger.debug { "Fetched skippable #{@test_skipping_mode}s: \n #{current_skippables}" }
515
+ Datadog.logger.debug { "Found #{skippables_count} skippable #{@test_skipping_mode}s." }
516
+ Datadog.logger.debug { "ITR correlation ID: #{@correlation_id}" }
517
+
518
+ Utils::Telemetry.inc(skippable_response_metric, skippables_count)
519
+ end
520
+
521
+ def apply_skippable_response(skippable_response)
522
+ set_skippables(
523
+ correlation_id: skippable_response.correlation_id,
524
+ tests: skippable_response.tests,
525
+ suites: skippable_response.suites
526
+ )
527
+ end
528
+
529
+ def set_skippables(correlation_id:, tests:, suites:)
420
530
  @mutex.synchronize do
421
- @correlation_id = skippable_response.correlation_id
422
- @skippable_tests = skippable_response.tests
531
+ @correlation_id = correlation_id
532
+ @skippable_tests = tests
533
+ @skippable_suites = suites
423
534
  end
535
+ end
424
536
 
425
- Datadog.logger.debug { "Fetched skippable tests: \n #{@skippable_tests}" }
426
- Datadog.logger.debug { "Found #{@skippable_tests.count} skippable tests." }
427
- Datadog.logger.debug { "ITR correlation ID: #{@correlation_id}" }
537
+ def current_skippables
538
+ suite_skipping_mode? ? @skippable_suites : @skippable_tests
539
+ end
428
540
 
429
- Utils::Telemetry.inc(Ext::Telemetry::METRIC_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS, @skippable_tests.count)
541
+ def skippable_response_metric
542
+ if skipping_suites?
543
+ Ext::Telemetry::METRIC_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES
544
+ else
545
+ Ext::Telemetry::METRIC_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS
546
+ end
430
547
  end
431
548
 
432
549
  def code_coverage_mode
@@ -21,7 +21,7 @@ module Datadog
21
21
  def valid?
22
22
  valid = true
23
23
 
24
- %i[test_id test_suite_id test_session_id coverage].each do |key|
24
+ %i[test_suite_id test_session_id coverage].each do |key|
25
25
  next unless send(key).nil?
26
26
 
27
27
  Datadog.logger.warn("citestcov event is invalid: [#{key}] is nil. Event: #{self}")
@@ -34,7 +34,7 @@ module Datadog
34
34
  def to_msgpack(packer = nil)
35
35
  packer ||= MessagePack::Packer.new
36
36
 
37
- packer.write_map_header(4)
37
+ packer.write_map_header(test_id.nil? ? 3 : 4)
38
38
 
39
39
  packer.write("test_session_id")
40
40
  packer.write(test_session_id.to_i)
@@ -42,8 +42,10 @@ module Datadog
42
42
  packer.write("test_suite_id")
43
43
  packer.write(test_suite_id.to_i)
44
44
 
45
- packer.write("span_id")
46
- packer.write(test_id.to_i)
45
+ unless test_id.nil?
46
+ packer.write("span_id")
47
+ packer.write(test_id.to_i)
48
+ end
47
49
 
48
50
  files = coverage.keys
49
51
  packer.write("files")
@@ -2,13 +2,16 @@
2
2
 
3
3
  require "set"
4
4
 
5
+ require_relative "../ext/test"
6
+
5
7
  module Datadog
6
8
  module CI
7
9
  module TestImpactAnalysis
8
10
  # No-op implementation used when test impact analysis is disabled.
9
11
  class NullComponent
10
12
  attr_reader :enabled, :skippable_tests_fetch_error, :test_skipping_enabled,
11
- :code_coverage_enabled, :skippable_tests, :correlation_id
13
+ :code_coverage_enabled, :skippable_tests, :skippable_suites, :correlation_id,
14
+ :test_skipping_mode
12
15
 
13
16
  def initialize
14
17
  @enabled = false
@@ -16,7 +19,9 @@ module Datadog
16
19
  @code_coverage_enabled = false
17
20
  @skippable_tests_fetch_error = nil
18
21
  @skippable_tests = Set.new
22
+ @skippable_suites = Set.new
19
23
  @correlation_id = nil
24
+ @test_skipping_mode = Ext::Test::TIATestSkippingMode::TEST
20
25
  end
21
26
 
22
27
  def configure(_remote_configuration = nil, _test_session = nil)
@@ -30,6 +35,10 @@ module Datadog
30
35
  false
31
36
  end
32
37
 
38
+ def skipping_suites?
39
+ false
40
+ end
41
+
33
42
  def code_coverage?
34
43
  false
35
44
  end
@@ -51,6 +60,13 @@ module Datadog
51
60
  nil
52
61
  end
53
62
 
63
+ def on_test_suite_started(_test_suite)
64
+ end
65
+
66
+ def on_test_suite_finished(_test_suite, _context)
67
+ nil
68
+ end
69
+
54
70
  def clear_context_coverage(_context_id)
55
71
  end
56
72
 
@@ -65,10 +81,17 @@ module Datadog
65
81
  false
66
82
  end
67
83
 
84
+ def skippable_suite?(_test_suite_name)
85
+ false
86
+ end
87
+
68
88
  def write_test_session_tags(_test_session, _skipped_tests_count)
69
89
  end
70
90
 
71
- def skippable_tests_count
91
+ def mark_if_suite_skippable(_test_suite)
92
+ end
93
+
94
+ def skippables_count
72
95
  0
73
96
  end
74
97
 
@@ -36,7 +36,7 @@ module Datadog
36
36
 
37
37
  payload.fetch("data", [])
38
38
  .each do |test_data|
39
- next unless test_data["type"] == Ext::Test::ITR_TEST_SKIPPING_MODE
39
+ next unless test_data["type"] == Ext::Test::TIATestSkippingMode::TEST
40
40
 
41
41
  attrs = test_data["attributes"] || {}
42
42
  res << Utils::TestRun.datadog_test_id(attrs["name"], attrs["suite"], attrs["parameters"])
@@ -45,6 +45,20 @@ module Datadog
45
45
  res
46
46
  end
47
47
 
48
+ def suites
49
+ res = Set.new
50
+
51
+ payload.fetch("data", [])
52
+ .each do |test_data|
53
+ next unless test_data["type"] == Ext::Test::TIATestSkippingMode::SUITE
54
+
55
+ suite = (test_data["attributes"] || {})["suite"]
56
+ res << suite unless suite.nil?
57
+ end
58
+
59
+ res
60
+ end
61
+
48
62
  def error_message
49
63
  return nil if ok?
50
64
 
@@ -74,18 +88,19 @@ module Datadog
74
88
  end
75
89
  end
76
90
 
77
- def initialize(dd_env:, api: nil, config_tags: {})
91
+ def initialize(dd_env:, api: nil, config_tags: {}, test_skipping_mode: Ext::Test::TIATestSkippingMode::TEST)
78
92
  @api = api
79
93
  @dd_env = dd_env
80
94
  @config_tags = config_tags
95
+ @test_skipping_mode = test_skipping_mode
81
96
  end
82
97
 
83
- def fetch_skippable_tests(test_session)
98
+ def fetch_skippables(test_session)
84
99
  api = @api
85
100
  return Response.from_http_response(nil) unless api
86
101
 
87
102
  request_payload = payload(test_session)
88
- Datadog.logger.debug("Fetching skippable tests with request: #{request_payload}")
103
+ Datadog.logger.debug("Fetching skippable #{@test_skipping_mode}s with request: #{request_payload}")
89
104
 
90
105
  http_response = api.api_request(
91
106
  path: Ext::Transport::DD_API_SKIPPABLE_TESTS_PATH,
@@ -127,7 +142,7 @@ module Datadog
127
142
  "data" => {
128
143
  "type" => Ext::Transport::DD_API_SKIPPABLE_TESTS_TYPE,
129
144
  "attributes" => {
130
- "test_level" => Ext::Test::ITR_TEST_SKIPPING_MODE,
145
+ "test_level" => @test_skipping_mode,
131
146
  "service" => test_session.service,
132
147
  "env" => @dd_env,
133
148
  "repository_url" => test_session.git_repository_url,
@@ -48,13 +48,13 @@ module Datadog
48
48
 
49
49
  # starting and finishing a test session is required to get the skippable tests response
50
50
  Datadog::CI.start_test_session(total_tests_count: estimated_tests_count)&.finish
51
- skippable_tests_count = test_impact_analysis.skippable_tests_count
51
+ skippables_count = test_impact_analysis.skippables_count
52
52
 
53
53
  log("Estimated tests count: #{estimated_tests_count}")
54
- log("Skippable tests count: #{skippable_tests_count}")
54
+ log("Skippables count: #{skippables_count}")
55
55
  validate_test_impact_analysis_state!
56
56
 
57
- [(skippable_tests_count.to_f / estimated_tests_count).floor(2), 0.99].min || 0.0
57
+ [(skippables_count.to_f / estimated_tests_count).floor(2), 0.99].min || 0.0
58
58
  end
59
59
  end
60
60
  end
@@ -49,7 +49,7 @@ module Datadog
49
49
  tests_hash.each_value.flat_map do |test_configs|
50
50
  test_configs.map do |test_config|
51
51
  {
52
- "type" => Ext::Test::ITR_TEST_SKIPPING_MODE,
52
+ "type" => Ext::Test::DEFAULT_TIA_TEST_SKIPPING_MODE,
53
53
  "attributes" => {
54
54
  "suite" => test_config["suite"],
55
55
  "name" => test_config["name"],
@@ -111,6 +111,26 @@ module Datadog
111
111
  end
112
112
  end
113
113
 
114
+ # @internal
115
+ def datadog_skip_reason
116
+ get_tag(Ext::Test::TAG_SKIP_REASON)
117
+ end
118
+
119
+ # @internal
120
+ def should_skip?
121
+ skipped_by_test_impact_analysis?
122
+ end
123
+
124
+ # @internal
125
+ def skipped_by_test_impact_analysis?
126
+ get_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) == "true"
127
+ end
128
+
129
+ # @internal
130
+ def itr_unskippable?
131
+ get_tag(Ext::Test::TAG_ITR_UNSKIPPABLE) == "true"
132
+ end
133
+
114
134
  private
115
135
 
116
136
  def set_status_from_stats!
@@ -16,6 +16,7 @@ require_relative "../ext/test"
16
16
  require_relative "../git/local_repository"
17
17
  require_relative "../utils/file_storage"
18
18
  require_relative "../utils/stateful"
19
+ require_relative "../utils/test_name"
19
20
 
20
21
  require_relative "../worker"
21
22
 
@@ -109,6 +110,7 @@ module Datadog
109
110
  def start_test_suite(test_suite_name, service: nil, tags: {})
110
111
  return skip_tracing unless test_suite_level_visibility_enabled
111
112
 
113
+ test_suite_name = Utils::TestName.normalize(test_suite_name)
112
114
  context = @local_test_suites_mode ? @context : maybe_remote_context
113
115
 
114
116
  test_suite = context.start_test_suite(test_suite_name, service: service, tags: tags)
@@ -117,6 +119,9 @@ module Datadog
117
119
  end
118
120
 
119
121
  def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
122
+ test_name = Utils::TestName.normalize(test_name)
123
+ test_suite_name = Utils::TestName.normalize(test_suite_name)
124
+
120
125
  test_suite = active_test_suite(test_suite_name)
121
126
  tags[Ext::Test::TAG_SUITE] ||= test_suite_name
122
127
 
@@ -165,6 +170,8 @@ module Datadog
165
170
  # we return the single active test suite because most of the time there is only one test suite running
166
171
  return single_active_test_suite if test_suite_name.nil?
167
172
 
173
+ test_suite_name = Utils::TestName.normalize(test_suite_name)
174
+
168
175
  # when fetching test_suite to use as test's context, try local context instance first
169
176
  local_test_suite = @context.active_test_suite(test_suite_name)
170
177
  return local_test_suite if local_test_suite
@@ -194,6 +201,7 @@ module Datadog
194
201
  end
195
202
 
196
203
  def deactivate_test_suite(test_suite_name)
204
+ test_suite_name = Utils::TestName.normalize(test_suite_name)
197
205
  test_suite = active_test_suite(test_suite_name)
198
206
  on_test_suite_finished(test_suite) if test_suite
199
207
 
@@ -272,6 +280,7 @@ module Datadog
272
280
 
273
281
  def on_test_suite_started(test_suite)
274
282
  set_codeowners(test_suite)
283
+ test_impact_analysis.on_test_suite_started(test_suite)
275
284
  end
276
285
 
277
286
  def on_test_started(test)
@@ -318,6 +327,7 @@ module Datadog
318
327
  end
319
328
 
320
329
  def on_test_suite_finished(test_suite)
330
+ test_impact_analysis.on_test_suite_finished(test_suite, maybe_remote_context)
321
331
  Telemetry.event_finished(test_suite)
322
332
  end
323
333