Skip to content

Commit

Permalink
add a first version of retry strategy for new tests
Browse files Browse the repository at this point in the history
  • Loading branch information
anmarchenko committed Sep 4, 2024
1 parent 0adab10 commit 2cfdeb6
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 7 deletions.
30 changes: 26 additions & 4 deletions lib/datadog/ci/test_retries/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require_relative "strategy/no_retry"
require_relative "strategy/retry_failed"
require_relative "strategy/retry_new"

require_relative "../ext/telemetry"
require_relative "../utils/telemetry"
Expand All @@ -17,7 +18,8 @@ class Component

attr_reader :retry_failed_tests_enabled, :retry_failed_tests_max_attempts,
:retry_failed_tests_total_limit, :retry_failed_tests_count,
:retry_new_tests_enabled, :retry_new_tests_duration_thresholds, :retry_new_tests_percentage_limit,
:retry_new_tests_enabled, :retry_new_tests_duration_thresholds,
:retry_new_tests_percentage_limit,
:retry_new_tests_unique_tests_set, :retry_new_tests_fault_reason

def initialize(
Expand Down Expand Up @@ -83,7 +85,11 @@ def with_retries(&block)

def build_strategy(test_span)
@mutex.synchronize do
if should_retry_failed_test?(test_span)
if should_retry_new_test?(test_span)
Datadog.logger.debug("New test retry starts")

Strategy::RetryNew.new(duration_thresholds: @retry_new_tests_duration_thresholds)
elsif should_retry_failed_test?(test_span)
Datadog.logger.debug("Failed test retry starts")
@retry_failed_tests_count += 1

Expand All @@ -105,7 +111,7 @@ def record_test_finished(test_span)
end

def record_test_span_duration(tracer_span)
# noop
current_retry_strategy&.record_duration(tracer_span.duration)
end

private
Expand All @@ -119,12 +125,28 @@ def current_retry_strategy=(strategy)
end

def should_retry_failed_test?(test_span)
@retry_failed_tests_enabled && !!test_span&.failed? && @retry_failed_tests_count < @retry_failed_tests_total_limit
if @retry_failed_tests_count >= @retry_failed_tests_total_limit
@retry_failed_tests_enabled = false
end

@retry_failed_tests_enabled && !!test_span&.failed?
end

def should_retry_new_test?(test_span)
# TODO: check if EFD is faulty here

@retry_new_tests_enabled && is_new_test?(test_span)
end

def test_visibility_component
Datadog.send(:components).test_visibility
end

def is_new_test?(test_span)
test_id = Utils::TestRun.datadog_test_id(test_span.name, test_span.test_suite_name)

@retry_new_tests_unique_tests_set.include?(test_id)
end
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/datadog/ci/test_retries/strategy/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def should_retry?
def record_retry(test_span)
test_span&.set_tag(Ext::Test::TAG_IS_RETRY, "true")
end

# duration in float seconds
def record_duration(duration)
end
end
end
end
Expand Down
41 changes: 41 additions & 0 deletions lib/datadog/ci/test_retries/strategy/retry_new.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

require_relative "base"

require_relative "../../ext/test"

module Datadog
module CI
module TestRetries
module Strategy
# retry every new test up to 10 times (early flake detection)
class RetryNew < Base
def initialize(duration_thresholds:)
@duration_thresholds = duration_thresholds
@attempts = 0
# will be changed based on test span duration
@max_attempts = 10
end

def should_retry?
@attempts < @max_attempts
end

def record_retry(test_span)
super

@attempts += 1

Datadog.logger.debug { "Retry Attempts [#{@attempts} / #{@max_attempts}]" }
end

def record_duration(duration)
@max_attempts = @duration_thresholds.max_attempts_for_duration(duration)

Datadog.logger.debug { "Recorded test duration of [#{@duration}], new Max Attempts value is [#{@max_attempts}]" }
end
end
end
end
end
end
6 changes: 5 additions & 1 deletion sig/datadog/ci/test_retries/component.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module Datadog

attr_reader retry_new_tests_enabled: bool

attr_reader retry_new_tests_duration_thresholds: Datadog::CI::Remote::SlowTestRetries?
attr_reader retry_new_tests_duration_thresholds: Datadog::CI::Remote::SlowTestRetries

attr_reader retry_new_tests_percentage_limit: Integer

Expand Down Expand Up @@ -46,6 +46,10 @@ module Datadog

def should_retry_failed_test?: (Datadog::CI::Test test) -> bool

def should_retry_new_test?: (Datadog::CI::Test test) -> bool

def is_new_test?: (Datadog::CI::Test test) -> bool

def test_visibility_component: () -> Datadog::CI::TestVisibility::Component
end
end
Expand Down
2 changes: 2 additions & 0 deletions sig/datadog/ci/test_retries/strategy/base.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module Datadog
def should_retry?: () -> bool

def record_retry: (Datadog::CI::Test test_span) -> void

def record_duration: (Float duration) -> void
end
end
end
Expand Down
16 changes: 16 additions & 0 deletions sig/datadog/ci/test_retries/strategy/retry_new.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Datadog
module CI
module TestRetries
module Strategy
class RetryNew < Base
@duration_thresholds: Datadog::CI::Remote::SlowTestRetries

@attempts: Integer
@max_attempts: Integer

def initialize: (duration_thresholds: Datadog::CI::Remote::SlowTestRetries) -> void
end
end
end
end
end
6 changes: 4 additions & 2 deletions spec/datadog/ci/test_retries/component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
subject { component.build_strategy(test_span) }

let(:test_failed) { false }
let(:test_span) { instance_double(Datadog::CI::Test, failed?: test_failed) }
let(:test_span) { instance_double(Datadog::CI::Test, failed?: test_failed, name: "test", test_suite_name: "suite") }

before do
component.configure(library_settings, test_session)
Expand Down Expand Up @@ -227,7 +227,9 @@
set_tag: true,
get_tag: true,
skipped?: false,
type: "test"
type: "test",
name: "mytest",
test_suite_name: "mysuite"
)
end

Expand Down

0 comments on commit 2cfdeb6

Please sign in to comment.