Class: Datadog::CI::TestRetries::Component
- Inherits:
-
Object
- Object
- Datadog::CI::TestRetries::Component
- Defined in:
- lib/datadog/ci/test_retries/component.rb
Overview
Encapsulates the logic to enable test retries, including:
-
retrying failed tests - improve success rate of CI pipelines
-
retrying new tests - detect flaky tests as early as possible to prevent them from being merged
Direct Known Subclasses
Constant Summary collapse
- FIBER_LOCAL_CURRENT_RETRY_DRIVER_KEY =
:__dd_current_retry_driver
Instance Method Summary collapse
- #build_driver(test_span) ⇒ Object
- #configure(library_settings, test_session) ⇒ Object
-
#initialize(retry_failed_tests_enabled:, retry_failed_tests_max_attempts:, retry_failed_tests_total_limit:, retry_new_tests_enabled:, unique_tests_client:) ⇒ Component
constructor
A new instance of Component.
- #record_test_finished(test_span) ⇒ Object
- #record_test_span_duration(tracer_span) ⇒ Object
-
#reset_retries! ⇒ Object
this API is targeted on Cucumber instrumentation or any other that cannot leverage #with_retries method.
- #should_retry? ⇒ Boolean
- #with_retries(&block) ⇒ Object
Constructor Details
#initialize(retry_failed_tests_enabled:, retry_failed_tests_max_attempts:, retry_failed_tests_total_limit:, retry_new_tests_enabled:, unique_tests_client:) ⇒ Component
Returns a new instance of Component.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/datadog/ci/test_retries/component.rb', line 23 def initialize( retry_failed_tests_enabled:, retry_failed_tests_max_attempts:, retry_failed_tests_total_limit:, retry_new_tests_enabled:, unique_tests_client: ) no_retries_strategy = Strategy::NoRetry.new retry_failed_strategy = Strategy::RetryFailed.new( enabled: retry_failed_tests_enabled, max_attempts: retry_failed_tests_max_attempts, total_limit: retry_failed_tests_total_limit ) retry_new_strategy = Strategy::RetryNew.new( enabled: retry_new_tests_enabled, unique_tests_client: unique_tests_client ) # order is important, we should try to retry new tests first @retry_strategies = [retry_new_strategy, retry_failed_strategy, no_retries_strategy] @mutex = Mutex.new end |
Instance Method Details
#build_driver(test_span) ⇒ Object
67 68 69 70 71 72 73 74 75 76 |
# File 'lib/datadog/ci/test_retries/component.rb', line 67 def build_driver(test_span) @mutex.synchronize do # find the first strategy that covers the test span and let it build the driver strategy = @retry_strategies.find { |strategy| strategy.covers?(test_span) } raise "No retry strategy found for test span: #{test_span.name}" if strategy.nil? strategy.build_driver(test_span) end end |
#configure(library_settings, test_session) ⇒ Object
48 49 50 51 52 53 |
# File 'lib/datadog/ci/test_retries/component.rb', line 48 def configure(library_settings, test_session) # let all strategies configure themselves @retry_strategies.each do |strategy| strategy.configure(library_settings, test_session) end end |
#record_test_finished(test_span) ⇒ Object
78 79 80 81 82 83 84 85 86 |
# File 'lib/datadog/ci/test_retries/component.rb', line 78 def record_test_finished(test_span) if current_retry_driver.nil? # we always run test at least once and after the first pass create a correct retry driver self.current_retry_driver = build_driver(test_span) else # after each retry we record the result, the driver will decide if we should retry again current_retry_driver&.record_retry(test_span) end end |
#record_test_span_duration(tracer_span) ⇒ Object
88 89 90 |
# File 'lib/datadog/ci/test_retries/component.rb', line 88 def record_test_span_duration(tracer_span) current_retry_driver&.record_duration(tracer_span.duration) end |
#reset_retries! ⇒ Object
this API is targeted on Cucumber instrumentation or any other that cannot leverage #with_retries method
93 94 95 |
# File 'lib/datadog/ci/test_retries/component.rb', line 93 def reset_retries! self.current_retry_driver = nil end |
#should_retry? ⇒ Boolean
97 98 99 |
# File 'lib/datadog/ci/test_retries/component.rb', line 97 def should_retry? !!current_retry_driver&.should_retry? end |
#with_retries(&block) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/datadog/ci/test_retries/component.rb', line 55 def with_retries(&block) reset_retries! loop do yield break unless should_retry? end ensure reset_retries! end |