Class: Datadog::CI::Test
- Defined in:
- lib/datadog/ci/test.rb,
sig/datadog/ci/test.rbs
Overview
Represents a single part of a test run.
Constant Summary
Constants inherited from Span
Span::EMPTY_TAGS, Span::ENVIRONMENT_RUNTIME_TAGS
Instance Attribute Summary collapse
-
#context_ids ⇒ Object
Context IDs for this test (used for TIA context coverage merging).
Attributes inherited from Span
Instance Method Summary collapse
-
#add_impacted_files(file_paths) ⇒ void
Adds custom files that Test Impact Analysis should consider capable of impacting this test.
- #all_executions_failed? ⇒ Boolean
- #all_executions_passed? ⇒ Boolean
- #any_retry_passed? ⇒ Boolean
-
#apply_automation_exclusions(prevent_failure_suppression:, no_auto_retry:) ⇒ Object
Records execution exclusions from the framework's test declaration.
-
#attempt_to_fix? ⇒ Boolean
Returns "true" if this flaky test has fixing attempts (determined by Datadog backend).
- #compute_final_status(status) ⇒ String
- #datadog_skip_reason ⇒ String?
-
#datadog_test_id ⇒ String
The test id according to Datadog's test impact analysis.
-
#disabled? ⇒ Boolean
Returns "true" if this test is disabled by Datadog test management.
-
#end_line ⇒ Integer?
Returns the ending line number of the test in the source file.
-
#failed!(exception: nil) ⇒ void
Sets the status of the span to "fail".
-
#finish ⇒ void
Finishes the current test.
-
#inherit_impacted_files(custom_impacted_files) ⇒ void
Inherits suite-level custom impacted files without copying them.
-
#initialize(tracer_span) ⇒ Test
constructor
A new instance of Test.
-
#is_new? ⇒ Boolean
Returns "true" if this span represents a test that wasn't known to Datadog before.
-
#is_retry? ⇒ Boolean
Returns "true" if test span represents a retry.
-
#itr_unskippable! ⇒ void
Marks this test as unskippable by the Test Impact Analysis.
-
#local_test_id ⇒ Object
Distinct declarations can share the backend ID but must not share retry history.
-
#lock_custom_impacted_files ⇒ Array<String>
Locks custom impacted files against further changes and returns them to Test Impact Analysis.
-
#modified? ⇒ Boolean
Returns "true" if this test is marked as modified (e.g., impacted by code changes).
-
#name ⇒ String
The name of the test.
- #no_auto_retry? ⇒ Boolean
-
#parameters ⇒ String?
Gets the parameters for this test (e.g. Cucumber example or RSpec specs) as a serialized JSON.
-
#passed! ⇒ void
Sets the status of the span to "pass".
- #peek_duration ⇒ Float
- #prevent_failure_suppression? ⇒ Boolean
-
#quarantined? ⇒ Boolean
Returns "true" if this test is quarantined by Datadog test management.
- #record_final_status ⇒ void
- #record_test_result(datadog_status) ⇒ void
-
#retry_reason ⇒ String
Returns string with a reason why test was retried.
-
#set_parameters(arguments, metadata = {}) ⇒ void
Sets the parameters for this test (e.g. Cucumber example or RSpec specs).
- #should_disable? ⇒ Boolean
- #should_ignore_failures? ⇒ Boolean
-
#should_quarantine? ⇒ Object
Assigned properties stay observable independently of effective policy.
- #should_retry_attempt_to_fix? ⇒ Boolean
- #should_skip? ⇒ Boolean
-
#skipped!(exception: nil, reason: nil) ⇒ void
Sets the status of the span to "skip".
- #skipped_by_test_impact_analysis? ⇒ Boolean
-
#start_line ⇒ Integer?
Returns the starting line number of the test in the source file.
-
#test_module_id ⇒ String
Span id of the running test module this test belongs to.
-
#test_module_name ⇒ String
Name of the running test module this test belongs to.
-
#test_session_id ⇒ String
Span id of the running test session this test belongs to.
-
#test_suite ⇒ Datadog::CI::TestSuite?
Running test suite that this test is part of (if any).
-
#test_suite_id ⇒ String
Span id of the running test suite this test belongs to.
-
#test_suite_name ⇒ String
Name of the running test suite this test belongs to.
Methods inherited from Span
#base_commit_sha, #clear_internal_tag, #clear_tag, #failed?, #get_metric, #get_tag, #git_branch, #git_commit_message, #git_commit_sha, #git_repository_url, #git_tag, #id, #original_git_commit_message, #original_git_commit_sha, #os_architecture, #os_platform, #os_version, #passed?, #runtime_name, #runtime_version, #service, #set_default_tags, #set_environment_runtime_tags, #set_internal_metric, #set_internal_tag, #set_internal_tags, #set_metric, #set_tag, #set_tags, #shared_tags, #skipped?, #source_file, #status, #test_tracing, #to_s, #trace_id, #type, #undefined?
Constructor Details
#initialize(tracer_span) ⇒ Test
Returns a new instance of Test.
15 16 17 18 19 20 |
# File 'lib/datadog/ci/test.rb', line 15 def initialize(tracer_span) super @custom_impacted_files = [] @inherited_custom_impacted_files = [] end |
Instance Attribute Details
#context_ids ⇒ Object
Context IDs for this test (used for TIA context coverage merging)
25 26 27 |
# File 'lib/datadog/ci/test.rb', line 25 def context_ids @context_ids end |
Instance Method Details
#add_impacted_files(file_paths) ⇒ void
This method returns an undefined value.
Adds custom files that Test Impact Analysis should consider capable of impacting this test.
This is useful for files that Datadog's native Ruby coverage cannot observe, such as JavaScript executed in a browser during a Capybara test. Paths must resolve inside the Git repository. Relative paths must be relative to the repository root. Absolute paths are also accepted.
If paths are relative to the current working directory, convert them to absolute paths with +File.expand_path+ before calling this method. Submitted paths must be lexically normalized without redundant +.+ or +..+ components.
Path resolution does not access the filesystem, so files do not need to exist when they are added. Paths outside the repository are ignored when the coverage event is serialized. Calls are incremental: every call adds files for the remainder of the test.
242 243 244 245 246 247 |
# File 'lib/datadog/ci/test.rb', line 242 def add_impacted_files(file_paths) raise ArgumentError, "file_paths must be an Array" unless file_paths.is_a?(Array) @custom_impacted_files.concat(file_paths) nil end |
#all_executions_failed? ⇒ Boolean
323 324 325 |
# File 'lib/datadog/ci/test.rb', line 323 def all_executions_failed? !!test_suite&.all_executions_failed?(local_test_id) end |
#all_executions_passed? ⇒ Boolean
328 329 330 |
# File 'lib/datadog/ci/test.rb', line 328 def all_executions_passed? !!test_suite&.all_executions_passed?(local_test_id) end |
#any_retry_passed? ⇒ Boolean
318 319 320 |
# File 'lib/datadog/ci/test.rb', line 318 def any_retry_passed? !!test_suite&.any_test_retry_passed?(local_test_id) end |
#apply_automation_exclusions(prevent_failure_suppression:, no_auto_retry:) ⇒ Object
Records execution exclusions from the framework's test declaration. Replaces any user-provided initial tags before execution policy is evaluated.
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/datadog/ci/test.rb', line 142 def apply_automation_exclusions(prevent_failure_suppression:, no_auto_retry:) if prevent_failure_suppression set_internal_tag(Ext::Test::TAG_PREVENT_FAILURE_SUPPRESSION, "true") else clear_internal_tag(Ext::Test::TAG_PREVENT_FAILURE_SUPPRESSION) end if no_auto_retry set_internal_tag(Ext::Test::TAG_NO_AUTO_RETRY, "true") else clear_internal_tag(Ext::Test::TAG_NO_AUTO_RETRY) end end |
#attempt_to_fix? ⇒ Boolean
Returns "true" if this flaky test has fixing attempts (determined by Datadog backend).
135 136 137 |
# File 'lib/datadog/ci/test.rb', line 135 def attempt_to_fix? get_tag(Ext::Test::TAG_IS_ATTEMPT_TO_FIX) == "true" end |
#compute_final_status(status) ⇒ String
394 395 396 397 398 399 400 401 402 403 404 405 406 407 |
# File 'lib/datadog/ci/test.rb', line 394 def compute_final_status(status) # Skip status is always preserved return status if status == Ext::Test::Status::SKIP # attempt_to_fix takes precedence over quarantine/disabled flags: # any failure across attempts means the fix didn't work. if should_retry_attempt_to_fix? return all_executions_passed? ? Ext::Test::Status::PASS : Ext::Test::Status::FAIL end return status if status == Ext::Test::Status::PASS should_ignore_failures? ? Ext::Test::Status::PASS : Ext::Test::Status::FAIL end |
#datadog_skip_reason ⇒ String?
333 334 335 336 337 338 339 |
# File 'lib/datadog/ci/test.rb', line 333 def datadog_skip_reason if skipped_by_test_impact_analysis? Ext::Test::SkipReason::TEST_IMPACT_ANALYSIS elsif should_disable? || should_quarantine? Ext::Test::SkipReason::TEST_MANAGEMENT_DISABLED end end |
#datadog_test_id ⇒ String
Returns the test id according to Datadog's test impact analysis.
33 34 35 |
# File 'lib/datadog/ci/test.rb', line 33 def datadog_test_id @datadog_test_id ||= Utils::TestRun.datadog_test_id(name, test_suite_name, parameters) end |
#disabled? ⇒ Boolean
Returns "true" if this test is disabled by Datadog test management.
129 130 131 |
# File 'lib/datadog/ci/test.rb', line 129 def disabled? get_tag(Ext::Test::TAG_IS_TEST_DISABLED) == "true" end |
#end_line ⇒ Integer?
Returns the ending line number of the test in the source file.
98 99 100 101 |
# File 'lib/datadog/ci/test.rb', line 98 def end_line line = get_tag(Ext::Test::TAG_SOURCE_END) line&.to_i end |
#failed!(exception: nil) ⇒ void
This method returns an undefined value.
Sets the status of the span to "fail".
281 282 283 284 285 |
# File 'lib/datadog/ci/test.rb', line 281 def failed!(exception: nil) super record_test_result(Ext::Test::Status::FAIL) end |
#finish ⇒ void
This method returns an undefined value.
Finishes the current test.
39 40 41 42 43 44 45 46 47 |
# File 'lib/datadog/ci/test.rb', line 39 def finish if is_retry? && retry_reason.nil? set_internal_tag(Ext::Test::TAG_RETRY_REASON, Ext::Test::RetryReason::RETRY_EXTERNAL) end test_tracing.deactivate_test super end |
#inherit_impacted_files(custom_impacted_files) ⇒ void
This method returns an undefined value.
Inherits suite-level custom impacted files without copying them.
253 254 255 256 |
# File 'lib/datadog/ci/test.rb', line 253 def inherit_impacted_files(custom_impacted_files) @inherited_custom_impacted_files = custom_impacted_files nil end |
#is_new? ⇒ Boolean
Returns "true" if this span represents a test that wasn't known to Datadog before.
117 118 119 |
# File 'lib/datadog/ci/test.rb', line 117 def is_new? get_tag(Ext::Test::TAG_IS_NEW) == "true" end |
#is_retry? ⇒ Boolean
Returns "true" if test span represents a retry.
105 106 107 |
# File 'lib/datadog/ci/test.rb', line 105 def is_retry? get_tag(Ext::Test::TAG_IS_RETRY) == "true" end |
#itr_unskippable! ⇒ void
This method returns an undefined value.
Marks this test as unskippable by the Test Impact Analysis. This must be done before the test execution starts.
Examples of tests that should be unskippable:
- tests that read files from disk
- tests that make network requests
- tests that call external processes
- tests that use forking
198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/datadog/ci/test.rb', line 198 def itr_unskippable! Utils::Telemetry.itr_unskippable set_internal_tag(Ext::Test::TAG_ITR_UNSKIPPABLE, "true") if skipped_by_test_impact_analysis? clear_internal_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) Utils::Telemetry.itr_forced_run set_internal_tag(Ext::Test::TAG_ITR_FORCED_RUN, "true") end end |
#local_test_id ⇒ Object
Distinct declarations can share the backend ID but must not share retry history.
381 382 383 384 385 386 387 388 389 390 391 392 |
# File 'lib/datadog/ci/test.rb', line 381 def local_test_id @local_test_id ||= begin source_file = get_tag(Ext::Test::TAG_SOURCE_FILE) source_start = get_tag(Ext::Test::TAG_SOURCE_START) if source_file && source_start [datadog_test_id, source_file, source_start] else datadog_test_id end end end |
#lock_custom_impacted_files ⇒ Array<String>
Locks custom impacted files against further changes and returns them to Test Impact Analysis.
263 264 265 266 267 268 |
# File 'lib/datadog/ci/test.rb', line 263 def lock_custom_impacted_files return @custom_impacted_files if @custom_impacted_files.frozen? @custom_impacted_files = (@inherited_custom_impacted_files | @custom_impacted_files).freeze end |
#modified? ⇒ Boolean
Returns "true" if this test is marked as modified (e.g., impacted by code changes).
184 185 186 |
# File 'lib/datadog/ci/test.rb', line 184 def modified? get_tag(Ext::Test::TAG_TEST_IS_MODIFIED) == "true" end |
#name ⇒ String
Returns the name of the test.
28 29 30 |
# File 'lib/datadog/ci/test.rb', line 28 def name get_tag(Ext::Test::TAG_NAME) end |
#no_auto_retry? ⇒ Boolean
162 163 164 |
# File 'lib/datadog/ci/test.rb', line 162 def no_auto_retry? get_tag(Ext::Test::TAG_NO_AUTO_RETRY) == "true" end |
#parameters ⇒ String?
Gets the parameters for this test (e.g. Cucumber example or RSpec specs) as a serialized JSON.
313 314 315 |
# File 'lib/datadog/ci/test.rb', line 313 def parameters get_tag(Ext::Test::TAG_PARAMETERS) end |
#passed! ⇒ void
This method returns an undefined value.
Sets the status of the span to "pass".
272 273 274 275 276 |
# File 'lib/datadog/ci/test.rb', line 272 def passed! super record_test_result(Ext::Test::Status::PASS) end |
#peek_duration ⇒ Float
370 371 372 373 374 375 376 |
# File 'lib/datadog/ci/test.rb', line 370 def peek_duration end_time = Core::Utils::Time.now.utc start_time = tracer_span.start_time return 0.0 if start_time.nil? || end_time.nil? end_time - start_time end |
#prevent_failure_suppression? ⇒ Boolean
157 158 159 |
# File 'lib/datadog/ci/test.rb', line 157 def prevent_failure_suppression? get_tag(Ext::Test::TAG_PREVENT_FAILURE_SUPPRESSION) == "true" end |
#quarantined? ⇒ Boolean
Returns "true" if this test is quarantined by Datadog test management.
123 124 125 |
# File 'lib/datadog/ci/test.rb', line 123 def quarantined? get_tag(Ext::Test::TAG_IS_QUARANTINED) == "true" end |
#record_final_status ⇒ void
This method returns an undefined value.
360 361 362 363 364 365 366 367 |
# File 'lib/datadog/ci/test.rb', line 360 def record_final_status status = get_tag(Ext::Test::TAG_STATUS) return if status.nil? final_status = compute_final_status(status) set_internal_tag(Ext::Test::TAG_FINAL_STATUS, final_status) test_suite&.record_test_final_status(local_test_id, final_status) end |
#record_test_result(datadog_status) ⇒ void
This method returns an undefined value.
409 410 411 412 413 414 415 416 |
# File 'lib/datadog/ci/test.rb', line 409 def record_test_result(datadog_status) # if this test was already executed in this test suite, mark it as retried if test_suite&.test_executed?(local_test_id) set_internal_tag(Ext::Test::TAG_IS_RETRY, "true") end test_suite&.record_test_result(local_test_id, datadog_status) end |
#retry_reason ⇒ String
Returns string with a reason why test was retried
111 112 113 |
# File 'lib/datadog/ci/test.rb', line 111 def retry_reason get_tag(Ext::Test::TAG_RETRY_REASON) end |
#set_parameters(arguments, metadata = {}) ⇒ void
This method returns an undefined value.
Sets the parameters for this test (e.g. Cucumber example or RSpec specs). Parameters are needed to compute test fingerprint to distinguish between different tests having same names.
303 304 305 306 307 |
# File 'lib/datadog/ci/test.rb', line 303 def set_parameters(arguments, = {}) return if arguments.nil? set_internal_tag(Ext::Test::TAG_PARAMETERS, Utils::TestRun.test_parameters(arguments: arguments, metadata: )) end |
#should_disable? ⇒ Boolean
173 174 175 |
# File 'lib/datadog/ci/test.rb', line 173 def should_disable? disabled? && !prevent_failure_suppression? end |
#should_ignore_failures? ⇒ Boolean
347 348 349 350 351 352 |
# File 'lib/datadog/ci/test.rb', line 347 def should_ignore_failures? return false if should_retry_attempt_to_fix? return true if should_quarantine? || should_disable? any_retry_passed? end |
#should_quarantine? ⇒ Object
Assigned properties stay observable independently of effective policy.
168 169 170 |
# File 'lib/datadog/ci/test.rb', line 168 def should_quarantine? quarantined? && !prevent_failure_suppression? end |
#should_retry_attempt_to_fix? ⇒ Boolean
178 179 180 |
# File 'lib/datadog/ci/test.rb', line 178 def should_retry_attempt_to_fix? attempt_to_fix? && !no_auto_retry? end |
#should_skip? ⇒ Boolean
342 343 344 |
# File 'lib/datadog/ci/test.rb', line 342 def should_skip? skipped_by_test_impact_analysis? || (should_disable? && !should_retry_attempt_to_fix?) end |
#skipped!(exception: nil, reason: nil) ⇒ void
This method returns an undefined value.
Sets the status of the span to "skip".
291 292 293 294 295 |
# File 'lib/datadog/ci/test.rb', line 291 def skipped!(exception: nil, reason: nil) super record_test_result(Ext::Test::Status::SKIP) end |
#skipped_by_test_impact_analysis? ⇒ Boolean
355 356 357 |
# File 'lib/datadog/ci/test.rb', line 355 def skipped_by_test_impact_analysis? get_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) == "true" end |
#start_line ⇒ Integer?
Returns the starting line number of the test in the source file.
90 91 92 93 |
# File 'lib/datadog/ci/test.rb', line 90 def start_line line = get_tag(Ext::Test::TAG_SOURCE_START) line&.to_i end |
#test_module_id ⇒ String
Span id of the running test module this test belongs to.
71 72 73 |
# File 'lib/datadog/ci/test.rb', line 71 def test_module_id get_tag(Ext::Test::TAG_TEST_MODULE_ID) end |
#test_module_name ⇒ String
Name of the running test module this test belongs to.
77 78 79 |
# File 'lib/datadog/ci/test.rb', line 77 def test_module_name get_tag(Ext::Test::TAG_MODULE) end |
#test_session_id ⇒ String
Span id of the running test session this test belongs to.
83 84 85 |
# File 'lib/datadog/ci/test.rb', line 83 def test_session_id get_tag(Ext::Test::TAG_TEST_SESSION_ID) end |
#test_suite ⇒ Datadog::CI::TestSuite?
Running test suite that this test is part of (if any).
52 53 54 55 |
# File 'lib/datadog/ci/test.rb', line 52 def test_suite suite_name = test_suite_name CI.active_test_suite(suite_name) if suite_name end |
#test_suite_id ⇒ String
Span id of the running test suite this test belongs to.
59 60 61 |
# File 'lib/datadog/ci/test.rb', line 59 def test_suite_id get_tag(Ext::Test::TAG_TEST_SUITE_ID) end |