datadog-ci 1.12.0 → 1.13.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -2
  3. data/lib/datadog/ci/configuration/components.rb +27 -15
  4. data/lib/datadog/ci/configuration/settings.rb +12 -0
  5. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +5 -2
  6. data/lib/datadog/ci/contrib/minitest/test.rb +3 -3
  7. data/lib/datadog/ci/contrib/rspec/example.rb +3 -3
  8. data/lib/datadog/ci/ext/app_types.rb +1 -1
  9. data/lib/datadog/ci/ext/settings.rb +2 -0
  10. data/lib/datadog/ci/ext/telemetry.rb +17 -5
  11. data/lib/datadog/ci/ext/test.rb +42 -4
  12. data/lib/datadog/ci/ext/transport.rb +6 -0
  13. data/lib/datadog/ci/remote/component.rb +11 -1
  14. data/lib/datadog/ci/remote/library_settings.rb +31 -0
  15. data/lib/datadog/ci/remote/library_settings_client.rb +2 -1
  16. data/lib/datadog/ci/test.rb +67 -9
  17. data/lib/datadog/ci/test_management/component.rb +61 -0
  18. data/lib/datadog/ci/test_management/null_component.rb +25 -0
  19. data/lib/datadog/ci/test_management/tests_properties.rb +128 -0
  20. data/lib/datadog/ci/test_optimisation/component.rb +3 -3
  21. data/lib/datadog/ci/test_retries/component.rb +37 -7
  22. data/lib/datadog/ci/test_retries/driver/base.rb +5 -0
  23. data/lib/datadog/ci/test_retries/driver/retry_failed.rb +4 -0
  24. data/lib/datadog/ci/test_retries/driver/retry_flaky_fixed.rb +38 -0
  25. data/lib/datadog/ci/test_retries/driver/retry_new.rb +2 -7
  26. data/lib/datadog/ci/test_retries/strategy/retry_flaky_fixed.rb +43 -0
  27. data/lib/datadog/ci/test_retries/strategy/retry_new.rb +4 -46
  28. data/lib/datadog/ci/test_suite.rb +21 -2
  29. data/lib/datadog/ci/test_visibility/capabilities.rb +36 -0
  30. data/lib/datadog/ci/test_visibility/component.rb +70 -2
  31. data/lib/datadog/ci/test_visibility/context.rb +0 -4
  32. data/lib/datadog/ci/{test_retries/unique_tests_client.rb → test_visibility/known_tests.rb} +10 -10
  33. data/lib/datadog/ci/test_visibility/null_component.rb +3 -0
  34. data/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb +1 -1
  35. data/lib/datadog/ci/test_visibility/telemetry.rb +11 -2
  36. data/lib/datadog/ci/test_visibility/transport.rb +15 -2
  37. data/lib/datadog/ci/version.rb +1 -1
  38. data/lib/datadog/ci.rb +13 -5
  39. metadata +11 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccfa630b807e5675fd68f68e571aeda530a0923e4cd4bdd29451f3065f8c4c7c
4
- data.tar.gz: 0a777e031ade13b09619a034206a1258285fd3e63c4bd36a5a3e24a3840590e0
3
+ metadata.gz: bc134bf501f298c7803572320d3c82d93b64b0dbfc59b2d8219d42fd5fed24e6
4
+ data.tar.gz: 4714f599fef9eae12cb3dc99dfb17dc0431a9dfee7d9337da9fada542429c6c5
5
5
  SHA512:
6
- metadata.gz: c47398d3cc2557b047741b7f8699e6464ee323bf3a32da43442fad8e666ca7cbc3fa973a88a006be3b86d0d3a61b44573755589b909fc21b75feb9b1f374de23
7
- data.tar.gz: e183e41a31344d2beb1f03790d48f31259d52b043f23a340b1480db065e23909ce3f90204dbc9e98a4ef88a22a3fe16d759bf47fca080701c0a3a750ef7adfc9
6
+ metadata.gz: e54fa5b48885accd1c304fca925292470930f6c916e318c5a02eed24989d089e431b99aa56c3eab75f1ed4445c3ab8bd14b1783baa01c32e52bf3d0df5f3813b
7
+ data.tar.gz: 0f42913850d53736f3b058db3c7bea7e2f4cc0c5ccf511545d052afb142967084185075888511887185dbf5b82ee4b6931b7da76f91b91fe0c99760efb1b9574
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.13.0] - 2025-02-25
4
+
5
+ ### Added
6
+
7
+ * Flaky test management support ([#289][])
8
+ * Always request the list of known tests and mark new tests ([#286][])
9
+
3
10
  ## [1.12.0] - 2025-01-23
4
11
 
5
12
  ### Added
@@ -386,7 +393,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
386
393
 
387
394
  - Ruby versions < 2.7 no longer supported ([#8][])
388
395
 
389
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...main
396
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.13.0...main
397
+ [1.13.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...v1.13.0
390
398
  [1.12.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.11.0...v1.12.0
391
399
  [1.11.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.10.0...v1.11.0
392
400
  [1.10.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.9.0...v1.10.0
@@ -554,4 +562,6 @@ Currently test suite level visibility is not used by our instrumentation: it wil
554
562
  [#271]: https://github.com/DataDog/datadog-ci-rb/issues/271
555
563
  [#272]: https://github.com/DataDog/datadog-ci-rb/issues/272
556
564
  [#275]: https://github.com/DataDog/datadog-ci-rb/issues/275
557
- [#283]: https://github.com/DataDog/datadog-ci-rb/issues/283
565
+ [#283]: https://github.com/DataDog/datadog-ci-rb/issues/283
566
+ [#286]: https://github.com/DataDog/datadog-ci-rb/issues/286
567
+ [#289]: https://github.com/DataDog/datadog-ci-rb/issues/289
@@ -6,14 +6,17 @@ require_relative "../ext/settings"
6
6
  require_relative "../git/tree_uploader"
7
7
  require_relative "../remote/component"
8
8
  require_relative "../remote/library_settings_client"
9
+ require_relative "../test_management/component"
10
+ require_relative "../test_management/null_component"
11
+ require_relative "../test_management/tests_properties"
9
12
  require_relative "../test_optimisation/component"
10
13
  require_relative "../test_optimisation/coverage/transport"
11
14
  require_relative "../test_optimisation/coverage/writer"
12
15
  require_relative "../test_retries/component"
13
16
  require_relative "../test_retries/null_component"
14
- require_relative "../test_retries/unique_tests_client"
15
17
  require_relative "../test_visibility/component"
16
18
  require_relative "../test_visibility/flush"
19
+ require_relative "../test_visibility/known_tests"
17
20
  require_relative "../test_visibility/null_component"
18
21
  require_relative "../test_visibility/serializers/factories/test_level"
19
22
  require_relative "../test_visibility/serializers/factories/test_suite_level"
@@ -30,7 +33,7 @@ module Datadog
30
33
  module Configuration
31
34
  # Adds CI behavior to Datadog trace components
32
35
  module Components
33
- attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries
36
+ attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries, :test_management
34
37
 
35
38
  def initialize(settings)
36
39
  @test_optimisation = nil
@@ -38,6 +41,7 @@ module Datadog
38
41
  @git_tree_upload_worker = DummyWorker.new
39
42
  @ci_remote = nil
40
43
  @test_retries = TestRetries::NullComponent.new
44
+ @test_management = TestManagement::NullComponent.new
41
45
 
42
46
  # Activate CI mode if enabled
43
47
  if settings.ci.enabled
@@ -58,7 +62,7 @@ module Datadog
58
62
  def activate_ci!(settings)
59
63
  unless settings.tracing.enabled
60
64
  Datadog.logger.error(
61
- "CI visibility requires tracing to be enabled. Disabling CI visibility. " \
65
+ "Test Optimization requires tracing to be enabled. Disabling Test Optimization. " \
62
66
  "NOTE: if you didn't disable tracing intentionally, add `c.tracing.enabled = true` to " \
63
67
  "your Datadog.configure block."
64
68
  )
@@ -111,13 +115,21 @@ module Datadog
111
115
  retry_failed_tests_max_attempts: settings.ci.retry_failed_tests_max_attempts,
112
116
  retry_failed_tests_total_limit: settings.ci.retry_failed_tests_total_limit,
113
117
  retry_new_tests_enabled: settings.ci.retry_new_tests_enabled,
114
- unique_tests_client: build_unique_tests_client(settings, test_visibility_api)
118
+ retry_flaky_fixed_tests_enabled: settings.ci.test_management_enabled,
119
+ retry_flaky_fixed_tests_max_attempts: settings.ci.test_management_attempt_to_fix_retries_count
115
120
  )
121
+
122
+ @test_management = TestManagement::Component.new(
123
+ enabled: settings.ci.test_management_enabled,
124
+ tests_properties_client: TestManagement::TestsProperties.new(api: test_visibility_api)
125
+ )
126
+
116
127
  # @type ivar @test_optimisation: Datadog::CI::TestOptimisation::Component
117
128
  @test_optimisation = build_test_optimisation(settings, test_visibility_api)
118
129
  @test_visibility = TestVisibility::Component.new(
119
130
  test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
120
- logical_test_session_name: settings.ci.test_session_name
131
+ logical_test_session_name: settings.ci.test_session_name,
132
+ known_tests_client: build_known_tests_client(settings, test_visibility_api)
121
133
  )
122
134
  end
123
135
 
@@ -125,7 +137,7 @@ module Datadog
125
137
  if settings.ci.itr_code_coverage_use_single_threaded_mode &&
126
138
  settings.ci.itr_test_impact_analysis_use_allocation_tracing
127
139
  Datadog.logger.warn(
128
- "Intelligent test runner: Single threaded coverage mode is incompatible with allocation tracing. " \
140
+ "Test Impact Analysis: Single threaded coverage mode is incompatible with allocation tracing. " \
129
141
  "Allocation tracing will be disabled. It means that test impact analysis will not be able to detect " \
130
142
  "instantiations of objects in your code, which is important for ActiveRecord models. " \
131
143
  "Please add your app/model folder to the list of tracked files or disable single threaded coverage mode."
@@ -137,7 +149,7 @@ module Datadog
137
149
  if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3" &&
138
150
  settings.ci.itr_test_impact_analysis_use_allocation_tracing
139
151
  Datadog.logger.warn(
140
- "Intelligent test runner: Allocation tracing is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
152
+ "Test Impact Analysis: Allocation tracing is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
141
153
  "disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). " \
142
154
  "Please update your Ruby version or add your app/model folder to the list of tracked files." \
143
155
  "Set env variable DD_CIVISIBILITY_ITR_TEST_IMPACT_ANALYSIS_USE_ALLOCATION_TRACING to 0 to disable this warning."
@@ -161,21 +173,21 @@ module Datadog
161
173
  if settings.ci.agentless_mode_enabled
162
174
  check_dd_site(settings)
163
175
 
164
- Datadog.logger.debug("CI visibility configured to use agentless transport")
176
+ Datadog.logger.debug("Test Optimization configured to use agentless transport")
165
177
 
166
178
  api = Transport::Api::Builder.build_agentless_api(settings)
167
179
  if api.nil?
168
180
  Datadog.logger.error do
169
- "DATADOG CONFIGURATION - CI VISIBILITY - ATTENTION - " \
170
- "Agentless mode was enabled but DD_API_KEY is not set: CI visibility is disabled. " \
181
+ "DATADOG CONFIGURATION - TEST OPTIMIZATION - ATTENTION - " \
182
+ "Agentless mode was enabled but DD_API_KEY is not set: Test Optimization is disabled. " \
171
183
  "Please make sure to set valid api key in DD_API_KEY environment variable"
172
184
  end
173
185
 
174
- # Tests are running without CI visibility enabled
186
+ # Tests are running without Test Optimization enabled
175
187
  settings.ci.enabled = false
176
188
  end
177
189
  else
178
- Datadog.logger.debug("CI visibility configured to use agent transport via EVP proxy")
190
+ Datadog.logger.debug("Test Optimization configured to use agent transport via EVP proxy")
179
191
 
180
192
  api = Transport::Api::Builder.build_evp_proxy_api(settings)
181
193
  if api.nil?
@@ -235,8 +247,8 @@ module Datadog
235
247
  )
236
248
  end
237
249
 
238
- def build_unique_tests_client(settings, api)
239
- TestRetries::UniqueTestsClient.new(
250
+ def build_known_tests_client(settings, api)
251
+ TestVisibility::KnownTests.new(
240
252
  api: api,
241
253
  dd_env: settings.env,
242
254
  config_tags: custom_configuration(settings)
@@ -262,7 +274,7 @@ module Datadog
262
274
  return if Ext::Settings::DD_SITE_ALLOWLIST.include?(settings.site)
263
275
 
264
276
  Datadog.logger.warn do
265
- "CI VISIBILITY CONFIGURATION " \
277
+ "TEST OPTIMIZATION CONFIGURATION " \
266
278
  "Agentless mode was enabled but DD_SITE is not set to one of the following: #{Ext::Settings::DD_SITE_ALLOWLIST.join(", ")}. " \
267
279
  "Please make sure to set valid site in DD_SITE environment variable"
268
280
  end
@@ -116,6 +116,18 @@ module Datadog
116
116
  o.default true
117
117
  end
118
118
 
119
+ option :test_management_enabled do |o|
120
+ o.type :bool
121
+ o.env CI::Ext::Settings::ENV_TEST_MANAGEMENT_ENABLED
122
+ o.default true
123
+ end
124
+
125
+ option :test_management_attempt_to_fix_retries_count do |o|
126
+ o.type :int
127
+ o.env CI::Ext::Settings::ENV_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES
128
+ o.default 20
129
+ end
130
+
119
131
  # internal only
120
132
  option :discard_traces do |o|
121
133
  o.type :bool
@@ -37,8 +37,11 @@ module Datadog
37
37
  end
38
38
 
39
39
  def begin_scenario(test_case)
40
- if Datadog::CI.active_test&.skipped_by_itr?
41
- raise ::Cucumber::Core::Test::Result::Skipped, CI::Ext::Test::ITR_TEST_SKIP_REASON
40
+ datadog_test = Datadog::CI.active_test
41
+
42
+ # special case for cucumber-ruby: we skip quarantined tests, thus for cucumber quarantined is the same as disabled
43
+ if datadog_test&.should_skip? || datadog_test&.quarantined?
44
+ raise ::Cucumber::Core::Test::Result::Skipped, datadog_test.datadog_skip_reason
42
45
  end
43
46
 
44
47
  super
@@ -44,7 +44,7 @@ module Datadog
44
44
  service: datadog_configuration[:service_name]
45
45
  )
46
46
  test_span&.itr_unskippable! if self.class.dd_suite_unskippable? || self.class.dd_test_unskippable?(name)
47
- skip(CI::Ext::Test::ITR_TEST_SKIP_REASON) if test_span&.skipped_by_itr?
47
+ skip(test_span&.datadog_skip_reason) if test_span&.should_skip?
48
48
  end
49
49
 
50
50
  def after_teardown
@@ -53,8 +53,8 @@ module Datadog
53
53
 
54
54
  finish_with_result(test_span, result_code)
55
55
 
56
- # remove failures if test passed at least once on retries
57
- self.failures = [] if test_span.any_retry_passed?
56
+ # remove failures if test passed at least once on retries or quarantined
57
+ self.failures = [] if test_span.should_ignore_failures?
58
58
 
59
59
  if Helpers.parallel?(self.class)
60
60
  finish_with_result(test_span.test_suite, result_code)
@@ -41,7 +41,7 @@ module Datadog
41
41
  ) do |test_span|
42
42
  test_span&.itr_unskippable! if datadog_unskippable?
43
43
 
44
- metadata[:skip] = CI::Ext::Test::ITR_TEST_SKIP_REASON if test_span&.skipped_by_itr?
44
+ metadata[:skip] = test_span&.datadog_skip_reason if test_span&.should_skip?
45
45
 
46
46
  # before each run remove any previous exception
47
47
  @exception = nil
@@ -58,8 +58,8 @@ module Datadog
58
58
  test_span&.passed!
59
59
  when :failed
60
60
  test_span&.failed!(exception: execution_result.exception)
61
- # if any of the retries passed, we don't fail the test run
62
- @exception = nil if test_span&.any_retry_passed?
61
+ # if any of the retries passed or test is quarantined, we don't fail the test run
62
+ @exception = nil if test_span&.should_ignore_failures?
63
63
  else
64
64
  # :pending or nil
65
65
  test_span&.skipped!(
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module CI
5
5
  module Ext
6
- # Defines span types for CI visibility
6
+ # Defines span types for Test Optimization
7
7
  # @public_api
8
8
  module AppTypes
9
9
  TYPE_TEST = "test"
@@ -20,6 +20,8 @@ module Datadog
20
20
  ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT = "DD_CIVISIBILITY_TOTAL_FLAKY_RETRY_COUNT"
21
21
  ENV_RETRY_NEW_TESTS_ENABLED = "DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED"
22
22
  ENV_TEST_SESSION_NAME = "DD_TEST_SESSION_NAME"
23
+ ENV_TEST_MANAGEMENT_ENABLED = "DD_TEST_MANAGEMENT_ENABLED"
24
+ ENV_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES = "DD_TEST_MANAGEMENT_ATTEMPT_TO_FIX_RETRIES"
23
25
 
24
26
  # Source: https://docs.datadoghq.com/getting_started/site/
25
27
  DD_SITE_ALLOWLIST = %w[
@@ -54,11 +54,17 @@ module Datadog
54
54
  METRIC_CODE_COVERAGE_IS_EMPTY = "code_coverage.is_empty"
55
55
  METRIC_CODE_COVERAGE_FILES = "code_coverage.files"
56
56
 
57
- METRIC_EFD_UNIQUE_TESTS_REQUEST = "early_flake_detection.request"
58
- METRIC_EFD_UNIQUE_TESTS_REQUEST_MS = "early_flake_detection.request_ms"
59
- METRIC_EFD_UNIQUE_TESTS_REQUEST_ERRORS = "early_flake_detection.request_errors"
60
- METRIC_EFD_UNIQUE_TESTS_RESPONSE_BYTES = "early_flake_detection.response_bytes"
61
- METRIC_EFD_UNIQUE_TESTS_RESPONSE_TESTS = "early_flake_detection.response_tests"
57
+ METRIC_KNOWN_TESTS_REQUEST = "known_tests.request"
58
+ METRIC_KNOWN_TESTS_REQUEST_MS = "known_tests.request_ms"
59
+ METRIC_KNOWN_TESTS_REQUEST_ERRORS = "known_tests.request_errors"
60
+ METRIC_KNOWN_TESTS_RESPONSE_BYTES = "known_tests.response_bytes"
61
+ METRIC_KNOWN_TESTS_RESPONSE_TESTS = "known_tests.response_tests"
62
+
63
+ METRIC_TEST_MANAGEMENT_TESTS_REQUEST = "test_management_tests.request"
64
+ METRIC_TEST_MANAGEMENT_TESTS_REQUEST_MS = "test_management_tests.request_ms"
65
+ METRIC_TEST_MANAGEMENT_TESTS_REQUEST_ERRORS = "test_management_tests.request_errors"
66
+ METRIC_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES = "test_management_tests.response_bytes"
67
+ METRIC_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS = "test_management_tests.response_tests"
62
68
 
63
69
  METRIC_TEST_SESSION = "test_session"
64
70
 
@@ -69,6 +75,7 @@ module Datadog
69
75
  TAG_BROWSER_DRIVER = "browser_driver"
70
76
  TAG_IS_RUM = "is_rum"
71
77
  TAG_IS_RETRY = "is_retry"
78
+ TAG_RETRY_REASON = "retry_reason"
72
79
  TAG_EARLY_FLAKE_DETECTION_ABORT_REASON = "early_flake_detection_abort_reason"
73
80
  TAG_IS_NEW = "is_new"
74
81
  TAG_LIBRARY = "library"
@@ -79,6 +86,10 @@ module Datadog
79
86
  TAG_REQUEST_COMPRESSED = "rq_compressed"
80
87
  TAG_RESPONSE_COMPRESSED = "rs_compressed"
81
88
  TAG_COMMAND = "command"
89
+ TAG_IS_ATTEMPT_TO_FIX = "is_attempt_to_fix"
90
+ TAG_IS_QUARANTINED = "is_quarantined"
91
+ TAG_IS_TEST_DISABLED = "is_disabled"
92
+ TAG_HAS_FAILED_ALL_RETRIES = "has_failed_all_retries"
82
93
  # tags for git_requests.settings_response metric
83
94
  TAG_COVERAGE_ENABLED = "coverage_enabled"
84
95
  TAG_ITR_ENABLED = "itr_enabled"
@@ -86,6 +97,7 @@ module Datadog
86
97
  TAG_REQUIRE_GIT = "require_git"
87
98
  TAG_EARLY_FLAKE_DETECTION_ENABLED = "early_flake_detection_enabled"
88
99
  TAG_FLAKY_TEST_RETRIES_ENABLED = "flaky_test_retries_enabled"
100
+ TAG_KNOWN_TESTS_ENABLED = "known_tests_enabled"
89
101
  # tags for test_session metric
90
102
  TAG_PROVIDER = "provider"
91
103
  TAG_AUTO_INJECTED = "auto_injected"
@@ -58,21 +58,42 @@ module Datadog
58
58
  # version of the browser, if multiple browsers or multiple versions then this tag is empty
59
59
  TAG_BROWSER_VERSION = "test.browser.version"
60
60
 
61
+ # known and new tests
62
+ TAG_IS_NEW = "test.is_new" # true if test is new (it was not known to Datadog before)
63
+
61
64
  # Tags for retries
62
65
  TAG_IS_RETRY = "test.is_retry" # true if test was retried by datadog-ci library
63
- TAG_IS_NEW = "test.is_new" # true if test was marked as new by new test retries (early flake detection)
66
+ TAG_RETRY_REASON = "test.retry_reason" # reason why test was retried
64
67
  TAG_EARLY_FLAKE_ENABLED = "test.early_flake.enabled" # true if early flake detection is enabled
65
68
  TAG_EARLY_FLAKE_ABORT_REASON = "test.early_flake.abort_reason" # reason why early flake detection was aborted
66
69
 
67
70
  # Tags for total code coverage
68
71
  TAG_CODE_COVERAGE_LINES_PCT = "test.code_coverage.lines_pct"
69
72
 
73
+ # Tags for test managament
74
+ TAG_TEST_MANAGEMENT_ENABLED = "test.test_management.enabled" # true if test management is enabled, set on test_session_end event
75
+ TAG_IS_ATTEMPT_TO_FIX = "test.test_management.is_attempt_to_fix" # true if test is marked as "attempted to fix"
76
+ TAG_IS_TEST_DISABLED = "test.test_management.is_test_disabled" # true if test is marked as disabled in test management view
77
+ TAG_IS_QUARANTINED = "test.test_management.is_quarantined" # true if test is quarantined in test management view
78
+ TAG_HAS_FAILED_ALL_RETRIES = "test.has_failed_all_retries" # true if test was retried and none of the retries passed
79
+ TAG_ATTEMPT_TO_FIX_PASSED = "test.test_management.attempt_to_fix_passed" # true if test was marked as "attempted to fix" and all of the retries passed
80
+
81
+ # a set of tag indicating which capabilities (features) are supported by the library
82
+ module LibraryCapabilities
83
+ TAG_TEST_IMPACT_ANALYSIS = "_dd.library_capabilities.test_impact_analysis"
84
+ TAG_EARLY_FLAKE_DETECTION = "_dd.library_capabilities.early_flake_detection"
85
+ TAG_AUTO_TEST_RETRIES = "_dd.library_capabilities.auto_test_retries"
86
+ TAG_TEST_MANAGEMENT_QUARANTINE = "_dd.library_capabilities.test_management.quarantine"
87
+ TAG_TEST_MANAGEMENT_DISABLE = "_dd.library_capabilities.test_management.disable"
88
+ TAG_TEST_MANAGEMENT_ATTEMPT_TO_FIX = "_dd.library_capabilities.test_management.attempt_to_fix"
89
+ end
90
+
70
91
  # internal APM tag to mark a span as a test span
71
92
  TAG_SPAN_KIND = "span.kind"
72
93
  SPAN_KIND_TEST = "test"
73
94
 
74
- # common tags that are serialized directly in msgpack header in metadata field
75
- METADATA_TAG_TEST_SESSION_NAME = "test_session.name"
95
+ # DD_TEST_SESSION_NAME value
96
+ TAG_TEST_SESSION_NAME = "test_session.name"
76
97
 
77
98
  # internal tag indicating if datadog service was configured by the user
78
99
  TAG_USER_PROVIDED_TEST_SERVICE = "_dd.test.is_user_provided_service"
@@ -85,7 +106,6 @@ module Datadog
85
106
 
86
107
  # could be either "test" or "suite" depending on whether we skip individual tests or whole suites
87
108
  ITR_TEST_SKIPPING_MODE = "test" # we always skip tests (not suites) in Ruby
88
- ITR_TEST_SKIP_REASON = "Skipped by Datadog's intelligent test runner"
89
109
  ITR_UNSKIPPABLE_OPTION = :datadog_itr_unskippable
90
110
 
91
111
  EARLY_FLAKE_FAULTY = "faulty"
@@ -97,12 +117,30 @@ module Datadog
97
117
  SKIP = "skip"
98
118
  end
99
119
 
120
+ # test statuses that we use for execution stats but don't report to Datadog (e.g. fail_ignored)
121
+ module ExecutionStatsStatus
122
+ FAIL_IGNORED = "fail_ignored"
123
+ end
124
+
100
125
  # test types (e.g. test, benchmark, browser)
101
126
  module Type
102
127
  TEST = "test"
103
128
  BROWSER = "browser"
104
129
  BENCHMARK = "benchmark" # DEV: not used yet, will be used when benchmarks are supported
105
130
  end
131
+
132
+ # possible reasons why a test was retried
133
+ module RetryReason
134
+ RETRY_NEW = "efd"
135
+ RETRY_FAILED = "atr"
136
+ RETRY_FLAKY_FIXED = "attempt_to_fix"
137
+ end
138
+
139
+ # possible reasons why a test was skipped
140
+ module SkipReason
141
+ TEST_IMPACT_ANALYSIS = "Skipped by Datadog's Test Impact Analysis"
142
+ TEST_MANAGEMENT_DISABLED = "Flaky test is disabled by Datadog"
143
+ end
106
144
  end
107
145
  end
108
146
  end
@@ -38,10 +38,13 @@ module Datadog
38
38
  DD_API_SETTINGS_RESPONSE_TESTS_SKIPPING_KEY = "tests_skipping"
39
39
  DD_API_SETTINGS_RESPONSE_REQUIRE_GIT_KEY = "require_git"
40
40
  DD_API_SETTINGS_RESPONSE_FLAKY_TEST_RETRIES_KEY = "flaky_test_retries_enabled"
41
+ DD_API_SETTINGS_RESPONSE_KNOWN_TESTS_ENABLED_KEY = "known_tests_enabled"
41
42
  DD_API_SETTINGS_RESPONSE_EARLY_FLAKE_DETECTION_KEY = "early_flake_detection"
42
43
  DD_API_SETTINGS_RESPONSE_ENABLED_KEY = "enabled"
43
44
  DD_API_SETTINGS_RESPONSE_SLOW_TEST_RETRIES_KEY = "slow_test_retries"
44
45
  DD_API_SETTINGS_RESPONSE_FAULTY_SESSION_THRESHOLD_KEY = "faulty_session_threshold"
46
+ DD_API_SETTINGS_RESPONSE_TEST_MANAGEMENT_KEY = "test_management"
47
+ DD_API_SETTINGS_RESPONSE_ATTEMPT_TO_FIX_RETRIES_KEY = "attempt_to_fix_retries"
45
48
  DD_API_SETTINGS_RESPONSE_DEFAULT = {DD_API_SETTINGS_RESPONSE_ITR_ENABLED_KEY => false}.freeze
46
49
 
47
50
  DD_API_GIT_SEARCH_COMMITS_PATH = "/api/v2/git/repository/search_commits"
@@ -54,6 +57,9 @@ module Datadog
54
57
  DD_API_UNIQUE_TESTS_PATH = "/api/v2/ci/libraries/tests"
55
58
  DD_API_UNIQUE_TESTS_TYPE = "ci_app_libraries_tests_request"
56
59
 
60
+ DD_API_TEST_MANAGEMENT_TESTS_PATH = "/api/v2/test/libraries/test-management/tests"
61
+ DD_API_TEST_MANAGEMENT_TESTS_TYPE = "ci_app_libraries_tests_request"
62
+
57
63
  CONTENT_TYPE_MESSAGEPACK = "application/msgpack"
58
64
  CONTENT_TYPE_JSON = "application/json"
59
65
  CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data"
@@ -32,7 +32,9 @@ module Datadog
32
32
  # configure different components in parallel because they might block on HTTP requests
33
33
  configuration_workers = [
34
34
  Worker.new { test_optimisation.configure(library_configuration, test_session) },
35
- Worker.new { test_retries.configure(library_configuration, test_session) }
35
+ Worker.new { test_retries.configure(library_configuration, test_session) },
36
+ Worker.new { test_visibility.configure(library_configuration, test_session) },
37
+ Worker.new { test_management.configure(library_configuration, test_session) }
36
38
  ]
37
39
 
38
40
  # launch configuration workers
@@ -44,6 +46,14 @@ module Datadog
44
46
 
45
47
  private
46
48
 
49
+ def test_management
50
+ Datadog.send(:components).test_management
51
+ end
52
+
53
+ def test_visibility
54
+ Datadog.send(:components).test_visibility
55
+ end
56
+
47
57
  def test_optimisation
48
58
  Datadog.send(:components).test_optimisation
49
59
  end
@@ -98,6 +98,14 @@ module Datadog
98
98
  )
99
99
  end
100
100
 
101
+ def known_tests_enabled?
102
+ return @known_tests_enabled if defined?(@known_tests_enabled)
103
+
104
+ @known_tests_enabled = Utils::Parsing.convert_to_bool(
105
+ payload.fetch(Ext::Transport::DD_API_SETTINGS_RESPONSE_KNOWN_TESTS_ENABLED_KEY, false)
106
+ )
107
+ end
108
+
101
109
  def slow_test_retries
102
110
  return @slow_test_retries if defined?(@slow_test_retries)
103
111
 
@@ -114,8 +122,31 @@ module Datadog
114
122
  )
115
123
  end
116
124
 
125
+ def test_management_enabled?
126
+ return @test_management_enabled if defined?(@test_management_enabled)
127
+
128
+ @test_management_enabled = Utils::Parsing.convert_to_bool(
129
+ test_management_payload.fetch(Ext::Transport::DD_API_SETTINGS_RESPONSE_ENABLED_KEY, false)
130
+ )
131
+ end
132
+
133
+ def attempt_to_fix_retries_count
134
+ return @attempt_to_fix_retries_count if defined?(@attempt_to_fix_retries_count)
135
+
136
+ @attempt_to_fix_retries_count = test_management_payload.fetch(
137
+ Ext::Transport::DD_API_SETTINGS_RESPONSE_ATTEMPT_TO_FIX_RETRIES_KEY, nil
138
+ )
139
+ end
140
+
117
141
  private
118
142
 
143
+ def test_management_payload
144
+ payload.fetch(
145
+ Ext::Transport::DD_API_SETTINGS_RESPONSE_TEST_MANAGEMENT_KEY,
146
+ {}
147
+ )
148
+ end
149
+
119
150
  def early_flake_detection_payload
120
151
  payload.fetch(
121
152
  Ext::Transport::DD_API_SETTINGS_RESPONSE_EARLY_FLAKE_DETECTION_KEY,
@@ -62,7 +62,8 @@ module Datadog
62
62
  Ext::Telemetry::TAG_EARLY_FLAKE_DETECTION_ENABLED => library_settings.early_flake_detection_enabled?.to_s,
63
63
  Ext::Telemetry::TAG_FLAKY_TEST_RETRIES_ENABLED => library_settings.flaky_test_retries_enabled?.to_s,
64
64
  Ext::Telemetry::TAG_ITR_ENABLED => library_settings.itr_enabled?.to_s,
65
- Ext::Telemetry::TAG_REQUIRE_GIT => library_settings.require_git?.to_s
65
+ Ext::Telemetry::TAG_REQUIRE_GIT => library_settings.require_git?.to_s,
66
+ Ext::Telemetry::TAG_KNOWN_TESTS_ENABLED => library_settings.known_tests_enabled?.to_s
66
67
  }
67
68
  )
68
69
 
@@ -62,19 +62,37 @@ module Datadog
62
62
  get_tag(Ext::Test::TAG_TEST_SESSION_ID)
63
63
  end
64
64
 
65
- # Returns "true" if the test is skipped by the intelligent test runner.
66
- # @return [Boolean] true if the test is skipped by the intelligent test runner, false otherwise.
67
- def skipped_by_itr?
68
- get_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) == "true"
69
- end
70
-
71
65
  # Returns "true" if test span represents a retry.
72
66
  # @return [Boolean] true if this test is a retry, false otherwise.
73
67
  def is_retry?
74
68
  get_tag(Ext::Test::TAG_IS_RETRY) == "true"
75
69
  end
76
70
 
77
- # Marks this test as unskippable by the intelligent test runner.
71
+ # Returns "true" if this span represents a test that wasn't known to Datadog before.
72
+ # @return [Boolean] true if this test is a new one, false otherwise.
73
+ def is_new?
74
+ get_tag(Ext::Test::TAG_IS_NEW) == "true"
75
+ end
76
+
77
+ # Returns "true" if this test is quarantined by Datadog test management.
78
+ # @return [Boolean] true if this test is quarantined, false otherwise.
79
+ def quarantined?
80
+ get_tag(Ext::Test::TAG_IS_QUARANTINED) == "true"
81
+ end
82
+
83
+ # Returns "true" if this test is disabled by Datadog test management.
84
+ # @return [Boolean] true if this test is disabled, false otherwise.
85
+ def disabled?
86
+ get_tag(Ext::Test::TAG_IS_TEST_DISABLED) == "true"
87
+ end
88
+
89
+ # Returns "true" if this flaky test has fixing attempts (determined by Datadog backend).
90
+ # @return [Boolean] true if this test is attempted to be fixed.
91
+ def attempt_to_fix?
92
+ get_tag(Ext::Test::TAG_IS_ATTEMPT_TO_FIX) == "true"
93
+ end
94
+
95
+ # Marks this test as unskippable by the Test Impact Analysis.
78
96
  # This must be done before the test execution starts.
79
97
  #
80
98
  # Examples of tests that should be unskippable:
@@ -88,7 +106,7 @@ module Datadog
88
106
  TestOptimisation::Telemetry.itr_unskippable
89
107
  set_tag(Ext::Test::TAG_ITR_UNSKIPPABLE, "true")
90
108
 
91
- if skipped_by_itr?
109
+ if skipped_by_test_impact_analysis?
92
110
  clear_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR)
93
111
 
94
112
  TestOptimisation::Telemetry.itr_forced_run
@@ -110,7 +128,13 @@ module Datadog
110
128
  def failed!(exception: nil)
111
129
  super
112
130
 
113
- record_test_result(Ext::Test::Status::FAIL)
131
+ # if we should ignore failures, we consider this test to be passed
132
+ if should_ignore_failures?
133
+ # use a special "fail_ignored" status to mark this test as failed but ignored
134
+ record_test_result(Ext::Test::ExecutionStatsStatus::FAIL_IGNORED)
135
+ else
136
+ record_test_result(Ext::Test::Status::FAIL)
137
+ end
114
138
  end
115
139
 
116
140
  # Sets the status of the span to "skip".
@@ -148,6 +172,40 @@ module Datadog
148
172
  !!test_suite&.any_test_retry_passed?(datadog_test_id)
149
173
  end
150
174
 
175
+ # @internal
176
+ def all_executions_failed?
177
+ !!test_suite&.all_executions_failed?(datadog_test_id)
178
+ end
179
+
180
+ # @internal
181
+ def all_executions_passed?
182
+ !!test_suite&.all_executions_passed?(datadog_test_id)
183
+ end
184
+
185
+ # @internal
186
+ def datadog_skip_reason
187
+ if skipped_by_test_impact_analysis?
188
+ Ext::Test::SkipReason::TEST_IMPACT_ANALYSIS
189
+ elsif disabled? || quarantined?
190
+ Ext::Test::SkipReason::TEST_MANAGEMENT_DISABLED
191
+ end
192
+ end
193
+
194
+ # @internal
195
+ def should_skip?
196
+ skipped_by_test_impact_analysis? || (disabled? && !attempt_to_fix?)
197
+ end
198
+
199
+ # @internal
200
+ def should_ignore_failures?
201
+ quarantined? || disabled? || any_retry_passed?
202
+ end
203
+
204
+ # @internal
205
+ def skipped_by_test_impact_analysis?
206
+ get_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) == "true"
207
+ end
208
+
151
209
  private
152
210
 
153
211
  def record_test_result(datadog_status)