datadog-ci 1.11.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -2
- data/lib/datadog/ci/configuration/components.rb +27 -15
- data/lib/datadog/ci/configuration/settings.rb +12 -0
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +5 -2
- data/lib/datadog/ci/contrib/cuprite/configuration/settings.rb +34 -0
- data/lib/datadog/ci/contrib/cuprite/driver.rb +94 -0
- data/lib/datadog/ci/contrib/cuprite/ext.rb +15 -0
- data/lib/datadog/ci/contrib/cuprite/integration.rb +44 -0
- data/lib/datadog/ci/contrib/cuprite/patcher.rb +24 -0
- data/lib/datadog/ci/contrib/cuprite/script_executor.rb +32 -0
- data/lib/datadog/ci/contrib/minitest/test.rb +3 -3
- data/lib/datadog/ci/contrib/rspec/example.rb +3 -3
- data/lib/datadog/ci/contrib/selenium/capybara_driver.rb +4 -4
- data/lib/datadog/ci/contrib/selenium/configuration/settings.rb +3 -1
- data/lib/datadog/ci/contrib/selenium/driver.rb +4 -4
- data/lib/datadog/ci/contrib/selenium/ext.rb +0 -15
- data/lib/datadog/ci/contrib/selenium/navigation.rb +2 -2
- data/lib/datadog/ci/ext/app_types.rb +1 -1
- data/lib/datadog/ci/ext/environment/providers/github_actions.rb +3 -0
- data/lib/datadog/ci/ext/environment.rb +4 -0
- data/lib/datadog/ci/ext/rum.rb +26 -0
- data/lib/datadog/ci/ext/settings.rb +2 -0
- data/lib/datadog/ci/ext/telemetry.rb +17 -5
- data/lib/datadog/ci/ext/test.rb +42 -4
- data/lib/datadog/ci/ext/transport.rb +6 -0
- data/lib/datadog/ci/remote/component.rb +11 -1
- data/lib/datadog/ci/remote/library_settings.rb +31 -0
- data/lib/datadog/ci/remote/library_settings_client.rb +2 -1
- data/lib/datadog/ci/test.rb +67 -9
- data/lib/datadog/ci/test_management/component.rb +61 -0
- data/lib/datadog/ci/test_management/null_component.rb +25 -0
- data/lib/datadog/ci/test_management/tests_properties.rb +128 -0
- data/lib/datadog/ci/test_optimisation/component.rb +5 -3
- data/lib/datadog/ci/test_retries/component.rb +37 -7
- data/lib/datadog/ci/test_retries/driver/base.rb +5 -0
- data/lib/datadog/ci/test_retries/driver/retry_failed.rb +4 -0
- data/lib/datadog/ci/test_retries/driver/retry_flaky_fixed.rb +38 -0
- data/lib/datadog/ci/test_retries/driver/retry_new.rb +2 -7
- data/lib/datadog/ci/test_retries/strategy/retry_flaky_fixed.rb +43 -0
- data/lib/datadog/ci/test_retries/strategy/retry_new.rb +4 -46
- data/lib/datadog/ci/test_suite.rb +21 -2
- data/lib/datadog/ci/test_visibility/capabilities.rb +36 -0
- data/lib/datadog/ci/test_visibility/component.rb +70 -2
- data/lib/datadog/ci/test_visibility/context.rb +0 -4
- data/lib/datadog/ci/{test_retries/unique_tests_client.rb → test_visibility/known_tests.rb} +10 -10
- data/lib/datadog/ci/test_visibility/null_component.rb +3 -0
- data/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb +1 -1
- data/lib/datadog/ci/test_visibility/telemetry.rb +11 -2
- data/lib/datadog/ci/test_visibility/transport.rb +29 -3
- data/lib/datadog/ci/utils/rum.rb +42 -0
- data/lib/datadog/ci/version.rb +1 -1
- data/lib/datadog/ci.rb +14 -5
- metadata +20 -10
- data/lib/datadog/ci/contrib/selenium/rum.rb +0 -43
@@ -7,6 +7,7 @@ require_relative "driver/retry_new"
|
|
7
7
|
require_relative "strategy/no_retry"
|
8
8
|
require_relative "strategy/retry_failed"
|
9
9
|
require_relative "strategy/retry_new"
|
10
|
+
require_relative "strategy/retry_flaky_fixed"
|
10
11
|
|
11
12
|
require_relative "../ext/telemetry"
|
12
13
|
require_relative "../utils/telemetry"
|
@@ -25,23 +26,33 @@ module Datadog
|
|
25
26
|
retry_failed_tests_max_attempts:,
|
26
27
|
retry_failed_tests_total_limit:,
|
27
28
|
retry_new_tests_enabled:,
|
28
|
-
|
29
|
+
retry_flaky_fixed_tests_enabled:,
|
30
|
+
retry_flaky_fixed_tests_max_attempts:
|
29
31
|
)
|
30
32
|
no_retries_strategy = Strategy::NoRetry.new
|
31
33
|
|
32
|
-
retry_failed_strategy = Strategy::RetryFailed.new(
|
34
|
+
@retry_failed_strategy = Strategy::RetryFailed.new(
|
33
35
|
enabled: retry_failed_tests_enabled,
|
34
36
|
max_attempts: retry_failed_tests_max_attempts,
|
35
37
|
total_limit: retry_failed_tests_total_limit
|
36
38
|
)
|
37
39
|
|
38
|
-
retry_new_strategy = Strategy::RetryNew.new(
|
39
|
-
enabled: retry_new_tests_enabled
|
40
|
-
unique_tests_client: unique_tests_client
|
40
|
+
@retry_new_strategy = Strategy::RetryNew.new(
|
41
|
+
enabled: retry_new_tests_enabled
|
41
42
|
)
|
42
43
|
|
43
|
-
|
44
|
-
|
44
|
+
retry_flaky_fixed_strategy = Strategy::RetryFlakyFixed.new(
|
45
|
+
enabled: retry_flaky_fixed_tests_enabled,
|
46
|
+
max_attempts: retry_flaky_fixed_tests_max_attempts
|
47
|
+
)
|
48
|
+
|
49
|
+
# order is important, we apply the first matching strategy
|
50
|
+
@retry_strategies = [
|
51
|
+
retry_flaky_fixed_strategy,
|
52
|
+
@retry_new_strategy,
|
53
|
+
@retry_failed_strategy,
|
54
|
+
no_retries_strategy
|
55
|
+
]
|
45
56
|
@mutex = Mutex.new
|
46
57
|
end
|
47
58
|
|
@@ -82,6 +93,8 @@ module Datadog
|
|
82
93
|
else
|
83
94
|
# after each retry we record the result, the driver will decide if we should retry again
|
84
95
|
current_retry_driver&.record_retry(test_span)
|
96
|
+
|
97
|
+
tag_last_retry(test_span) unless should_retry?
|
85
98
|
end
|
86
99
|
end
|
87
100
|
|
@@ -94,10 +107,27 @@ module Datadog
|
|
94
107
|
self.current_retry_driver = nil
|
95
108
|
end
|
96
109
|
|
110
|
+
def tag_last_retry(test_span)
|
111
|
+
test_span&.set_tag(Ext::Test::TAG_HAS_FAILED_ALL_RETRIES, "true") if test_span&.all_executions_failed?
|
112
|
+
|
113
|
+
# if we are attempting to fix the test and all retries passed, we indicate that the fix might have worked
|
114
|
+
if test_span&.attempt_to_fix? && test_span.all_executions_passed?
|
115
|
+
test_span&.set_tag(Ext::Test::TAG_ATTEMPT_TO_FIX_PASSED, "true")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
97
119
|
def should_retry?
|
98
120
|
!!current_retry_driver&.should_retry?
|
99
121
|
end
|
100
122
|
|
123
|
+
def auto_test_retries_feature_enabled
|
124
|
+
@retry_failed_strategy.enabled
|
125
|
+
end
|
126
|
+
|
127
|
+
def early_flake_detection_feature_enabled
|
128
|
+
@retry_new_strategy.enabled
|
129
|
+
end
|
130
|
+
|
101
131
|
private
|
102
132
|
|
103
133
|
def current_retry_driver
|
@@ -13,11 +13,16 @@ module Datadog
|
|
13
13
|
|
14
14
|
def record_retry(test_span)
|
15
15
|
test_span&.set_tag(Ext::Test::TAG_IS_RETRY, "true")
|
16
|
+
test_span&.set_tag(Ext::Test::TAG_RETRY_REASON, retry_reason)
|
16
17
|
end
|
17
18
|
|
18
19
|
# duration in float seconds
|
19
20
|
def record_duration(duration)
|
20
21
|
end
|
22
|
+
|
23
|
+
def retry_reason
|
24
|
+
"unknown"
|
25
|
+
end
|
21
26
|
end
|
22
27
|
end
|
23
28
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
require_relative "../../ext/test"
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module CI
|
9
|
+
module TestRetries
|
10
|
+
module Driver
|
11
|
+
class RetryFlakyFixed < Base
|
12
|
+
attr_reader :max_attempts
|
13
|
+
|
14
|
+
def initialize(max_attempts:)
|
15
|
+
@attempts = 0
|
16
|
+
@max_attempts = max_attempts
|
17
|
+
end
|
18
|
+
|
19
|
+
def should_retry?
|
20
|
+
@attempts < @max_attempts
|
21
|
+
end
|
22
|
+
|
23
|
+
def record_retry(test_span)
|
24
|
+
super
|
25
|
+
|
26
|
+
@attempts += 1
|
27
|
+
|
28
|
+
Datadog.logger.debug { "Retry Attempts [#{@attempts} / #{@max_attempts}]" }
|
29
|
+
end
|
30
|
+
|
31
|
+
def retry_reason
|
32
|
+
Ext::Test::RetryReason::RETRY_FLAKY_FIXED
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -15,8 +15,6 @@ module Datadog
|
|
15
15
|
@attempts = 0
|
16
16
|
# will be changed based on test span duration
|
17
17
|
@max_attempts = 10
|
18
|
-
|
19
|
-
mark_new_test(test_span)
|
20
18
|
end
|
21
19
|
|
22
20
|
def should_retry?
|
@@ -27,7 +25,6 @@ module Datadog
|
|
27
25
|
super
|
28
26
|
|
29
27
|
@attempts += 1
|
30
|
-
mark_new_test(test_span)
|
31
28
|
|
32
29
|
Datadog.logger.debug { "Retry Attempts [#{@attempts} / #{@max_attempts}]" }
|
33
30
|
end
|
@@ -38,10 +35,8 @@ module Datadog
|
|
38
35
|
Datadog.logger.debug { "Recorded test duration of [#{duration}], new Max Attempts value is [#{@max_attempts}]" }
|
39
36
|
end
|
40
37
|
|
41
|
-
|
42
|
-
|
43
|
-
def mark_new_test(test_span)
|
44
|
-
test_span.set_tag(Ext::Test::TAG_IS_NEW, "true")
|
38
|
+
def retry_reason
|
39
|
+
Ext::Test::RetryReason::RETRY_NEW
|
45
40
|
end
|
46
41
|
end
|
47
42
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
require_relative "../driver/retry_flaky_fixed"
|
6
|
+
|
7
|
+
module Datadog
|
8
|
+
module CI
|
9
|
+
module TestRetries
|
10
|
+
module Strategy
|
11
|
+
# This strategy retries tests that are flaky and were marked as attempted to be fixed in Datadog Test Management UI.
|
12
|
+
class RetryFlakyFixed < Base
|
13
|
+
attr_reader :enabled, :max_attempts
|
14
|
+
|
15
|
+
def initialize(
|
16
|
+
enabled:,
|
17
|
+
max_attempts:
|
18
|
+
)
|
19
|
+
@enabled = enabled
|
20
|
+
@max_attempts = max_attempts
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(library_settings, test_session)
|
24
|
+
@enabled &&= library_settings.test_management_enabled?
|
25
|
+
@max_attempts = library_settings.attempt_to_fix_retries_count || @max_attempts
|
26
|
+
end
|
27
|
+
|
28
|
+
def covers?(test_span)
|
29
|
+
return false unless @enabled
|
30
|
+
|
31
|
+
!!test_span&.attempt_to_fix?
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_driver(test_span)
|
35
|
+
Datadog.logger.debug { "#{test_span.name} is attempt_to_fix, will be retried" }
|
36
|
+
|
37
|
+
Driver::RetryFlakyFixed.new(max_attempts: max_attempts)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -11,19 +11,13 @@ module Datadog
|
|
11
11
|
class RetryNew < Base
|
12
12
|
DEFAULT_TOTAL_TESTS_COUNT = 100
|
13
13
|
|
14
|
-
attr_reader :enabled, :max_attempts_thresholds, :
|
14
|
+
attr_reader :enabled, :max_attempts_thresholds, :total_limit, :retried_count
|
15
15
|
|
16
|
-
def initialize(
|
17
|
-
enabled:,
|
18
|
-
unique_tests_client:
|
19
|
-
)
|
16
|
+
def initialize(enabled:)
|
20
17
|
@enabled = enabled
|
21
|
-
@unique_tests_set = Set.new
|
22
18
|
# total maximum number of new tests to retry (will be set based on the total number of tests in the session)
|
23
19
|
@total_limit = 0
|
24
20
|
@retried_count = 0
|
25
|
-
|
26
|
-
@unique_tests_client = unique_tests_client
|
27
21
|
end
|
28
22
|
|
29
23
|
def covers?(test_span)
|
@@ -37,11 +31,11 @@ module Datadog
|
|
37
31
|
mark_test_session_faulty(Datadog::CI.active_test_session)
|
38
32
|
end
|
39
33
|
|
40
|
-
@enabled && !test_span.skipped? &&
|
34
|
+
@enabled && !test_span.skipped? && test_span.is_new?
|
41
35
|
end
|
42
36
|
|
43
37
|
def configure(library_settings, test_session)
|
44
|
-
@enabled &&= library_settings.early_flake_detection_enabled?
|
38
|
+
@enabled &&= library_settings.early_flake_detection_enabled? && library_settings.known_tests_enabled?
|
45
39
|
|
46
40
|
return unless @enabled
|
47
41
|
|
@@ -50,7 +44,6 @@ module Datadog
|
|
50
44
|
|
51
45
|
set_max_attempts_thresholds(library_settings)
|
52
46
|
calculate_total_retries_limit(library_settings, test_session)
|
53
|
-
fetch_known_unique_tests(test_session)
|
54
47
|
end
|
55
48
|
|
56
49
|
def build_driver(test_span)
|
@@ -68,20 +61,6 @@ module Datadog
|
|
68
61
|
test_session&.set_tag(Ext::Test::TAG_EARLY_FLAKE_ABORT_REASON, Ext::Test::EARLY_FLAKE_FAULTY)
|
69
62
|
end
|
70
63
|
|
71
|
-
def is_new_test?(test_span)
|
72
|
-
test_id = Utils::TestRun.datadog_test_id(test_span.name, test_span.test_suite_name)
|
73
|
-
|
74
|
-
result = !@unique_tests_set.include?(test_id)
|
75
|
-
|
76
|
-
if result
|
77
|
-
Datadog.logger.debug do
|
78
|
-
"#{test_id} is not found in the unique tests set, it is a new test"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
result
|
83
|
-
end
|
84
|
-
|
85
64
|
def set_max_attempts_thresholds(library_settings)
|
86
65
|
@max_attempts_thresholds = library_settings.slow_test_retries
|
87
66
|
Datadog.logger.debug do
|
@@ -104,27 +83,6 @@ module Datadog
|
|
104
83
|
"Retry new tests total limit is [#{@total_limit}] (#{percentage_limit}% of #{tests_count})"
|
105
84
|
end
|
106
85
|
end
|
107
|
-
|
108
|
-
def fetch_known_unique_tests(test_session)
|
109
|
-
@unique_tests_set = @unique_tests_client.fetch_unique_tests(test_session)
|
110
|
-
if @unique_tests_set.empty?
|
111
|
-
@enabled = false
|
112
|
-
mark_test_session_faulty(test_session)
|
113
|
-
|
114
|
-
Datadog.logger.warn(
|
115
|
-
"Disabling early flake detection because there are no known tests (possible reason: no test runs in default branch)"
|
116
|
-
)
|
117
|
-
end
|
118
|
-
|
119
|
-
# report how many unique tests were found
|
120
|
-
Datadog.logger.debug do
|
121
|
-
"Found [#{@unique_tests_set.size}] known unique tests"
|
122
|
-
end
|
123
|
-
Utils::Telemetry.distribution(
|
124
|
-
Ext::Telemetry::METRIC_EFD_UNIQUE_TESTS_RESPONSE_TESTS,
|
125
|
-
@unique_tests_set.size.to_f
|
126
|
-
)
|
127
|
-
end
|
128
86
|
end
|
129
87
|
end
|
130
88
|
end
|
@@ -59,6 +59,24 @@ module Datadog
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
# @internal
|
63
|
+
def all_executions_failed?(test_id)
|
64
|
+
synchronize do
|
65
|
+
stats = @execution_stats_per_test[test_id]
|
66
|
+
stats && (stats[Ext::Test::Status::FAIL] > 0 || stats[Ext::Test::ExecutionStatsStatus::FAIL_IGNORED] > 0) &&
|
67
|
+
stats[Ext::Test::Status::PASS] == 0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @internal
|
72
|
+
def all_executions_passed?(test_id)
|
73
|
+
synchronize do
|
74
|
+
stats = @execution_stats_per_test[test_id]
|
75
|
+
stats && stats[Ext::Test::Status::PASS] > 0 && stats[Ext::Test::Status::FAIL] == 0 &&
|
76
|
+
stats[Ext::Test::ExecutionStatsStatus::FAIL_IGNORED] == 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
62
80
|
# @internal
|
63
81
|
def test_executed?(test_id)
|
64
82
|
synchronize do
|
@@ -89,8 +107,9 @@ module Datadog
|
|
89
107
|
end
|
90
108
|
|
91
109
|
def derive_test_status_from_execution_stats(test_execution_stats)
|
92
|
-
# test is passed if it passed at least once
|
93
|
-
if test_execution_stats[Ext::Test::Status::PASS] > 0
|
110
|
+
# test is passed if it passed at least once or it failed but fail was ignored
|
111
|
+
if test_execution_stats[Ext::Test::Status::PASS] > 0 ||
|
112
|
+
test_execution_stats[Ext::Test::ExecutionStatsStatus::FAIL_IGNORED] > 0
|
94
113
|
Ext::Test::Status::PASS
|
95
114
|
# if test was never passed, it is failed if it failed at least once
|
96
115
|
elsif test_execution_stats[Ext::Test::Status::FAIL] > 0
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../ext/test"
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module CI
|
7
|
+
module TestVisibility
|
8
|
+
# Generates internal tags for library capabilities
|
9
|
+
module Capabilities
|
10
|
+
def self.tags
|
11
|
+
tags = {}
|
12
|
+
|
13
|
+
test_optimisation = Datadog::CI.send(:test_optimisation)
|
14
|
+
tags[Ext::Test::LibraryCapabilities::TAG_TEST_IMPACT_ANALYSIS] = test_optimisation.enabled.to_s
|
15
|
+
|
16
|
+
test_management = Datadog::CI.send(:test_management)
|
17
|
+
test_management_tag_value = test_management.enabled.to_s
|
18
|
+
|
19
|
+
[
|
20
|
+
Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_ATTEMPT_TO_FIX,
|
21
|
+
Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_QUARANTINE,
|
22
|
+
Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_DISABLE
|
23
|
+
].each do |tag|
|
24
|
+
tags[tag] = test_management_tag_value
|
25
|
+
end
|
26
|
+
|
27
|
+
test_retries = Datadog::CI.send(:test_retries)
|
28
|
+
tags[Ext::Test::LibraryCapabilities::TAG_AUTO_TEST_RETRIES] = test_retries.auto_test_retries_feature_enabled.to_s
|
29
|
+
tags[Ext::Test::LibraryCapabilities::TAG_EARLY_FLAKE_DETECTION] = test_retries.early_flake_detection_feature_enabled.to_s
|
30
|
+
|
31
|
+
tags
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -18,9 +18,10 @@ module Datadog
|
|
18
18
|
module TestVisibility
|
19
19
|
# Common behavior for CI tests
|
20
20
|
class Component
|
21
|
-
attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name
|
21
|
+
attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name, :known_tests, :known_tests_enabled
|
22
22
|
|
23
23
|
def initialize(
|
24
|
+
known_tests_client:,
|
24
25
|
test_suite_level_visibility_enabled: false,
|
25
26
|
codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse,
|
26
27
|
logical_test_session_name: nil
|
@@ -29,6 +30,21 @@ module Datadog
|
|
29
30
|
@context = Context.new
|
30
31
|
@codeowners = codeowners
|
31
32
|
@logical_test_session_name = logical_test_session_name
|
33
|
+
|
34
|
+
# "Known tests" feature fetches a list of all tests known to Datadog for this repository
|
35
|
+
# and uses this list to determine if a test is new or not. New tests are marked with "test.is_new" tag.
|
36
|
+
@known_tests_enabled = false
|
37
|
+
@known_tests_client = known_tests_client
|
38
|
+
@known_tests = Set.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure(library_configuration, test_session)
|
42
|
+
return unless test_suite_level_visibility_enabled
|
43
|
+
|
44
|
+
if library_configuration.known_tests_enabled?
|
45
|
+
@known_tests_enabled = true
|
46
|
+
fetch_known_tests(test_session)
|
47
|
+
end
|
32
48
|
end
|
33
49
|
|
34
50
|
def start_test_session(service: nil, tags: {}, total_tests_count: 0)
|
@@ -158,7 +174,8 @@ module Datadog
|
|
158
174
|
# sets logical test session name if none provided by the user
|
159
175
|
override_logical_test_session_name!(test_session) if logical_test_session_name.nil?
|
160
176
|
|
161
|
-
#
|
177
|
+
# Signal Remote::Component to configure the library.
|
178
|
+
# Note that it will call this component back (unfortunate circular dependency).
|
162
179
|
remote.configure(test_session)
|
163
180
|
end
|
164
181
|
|
@@ -182,6 +199,10 @@ module Datadog
|
|
182
199
|
|
183
200
|
Telemetry.event_created(test)
|
184
201
|
|
202
|
+
mark_test_as_new(test) if new_test?(test)
|
203
|
+
|
204
|
+
test_management.tag_test_from_properties(test)
|
205
|
+
|
185
206
|
test_optimisation.mark_if_skippable(test)
|
186
207
|
test_optimisation.start_coverage(test)
|
187
208
|
end
|
@@ -287,6 +308,49 @@ module Datadog
|
|
287
308
|
end
|
288
309
|
end
|
289
310
|
|
311
|
+
def new_test?(test_span)
|
312
|
+
return false unless @known_tests_enabled
|
313
|
+
|
314
|
+
test_id = Utils::TestRun.datadog_test_id(test_span.name, test_span.test_suite_name)
|
315
|
+
result = !@known_tests.include?(test_id)
|
316
|
+
|
317
|
+
if result
|
318
|
+
Datadog.logger.debug do
|
319
|
+
"#{test_id} is not found in the known tests set, it is a new test"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
result
|
324
|
+
end
|
325
|
+
|
326
|
+
def fetch_known_tests(test_session)
|
327
|
+
@known_tests = @known_tests_client.fetch(test_session)
|
328
|
+
|
329
|
+
if @known_tests.empty?
|
330
|
+
@known_tests_enabled = false
|
331
|
+
|
332
|
+
# this adds unfortunate knowledge on EFD from Testvisibility, rethink this
|
333
|
+
test_session&.set_tag(Ext::Test::TAG_EARLY_FLAKE_ABORT_REASON, Ext::Test::EARLY_FLAKE_FAULTY)
|
334
|
+
|
335
|
+
Datadog.logger.warn("Empty set of tests known to Datadog")
|
336
|
+
end
|
337
|
+
|
338
|
+
# report how many known tests were found
|
339
|
+
Datadog.logger.debug do
|
340
|
+
"Found [#{@known_tests.size}] known tests"
|
341
|
+
end
|
342
|
+
Utils::Telemetry.distribution(
|
343
|
+
Ext::Telemetry::METRIC_KNOWN_TESTS_RESPONSE_TESTS,
|
344
|
+
@known_tests.size.to_f
|
345
|
+
)
|
346
|
+
|
347
|
+
@known_tests
|
348
|
+
end
|
349
|
+
|
350
|
+
def mark_test_as_new(test_span)
|
351
|
+
test_span.set_tag(Ext::Test::TAG_IS_NEW, "true")
|
352
|
+
end
|
353
|
+
|
290
354
|
def test_optimisation
|
291
355
|
Datadog.send(:components).test_optimisation
|
292
356
|
end
|
@@ -302,6 +366,10 @@ module Datadog
|
|
302
366
|
def remote
|
303
367
|
Datadog.send(:components).ci_remote
|
304
368
|
end
|
369
|
+
|
370
|
+
def test_management
|
371
|
+
Datadog.send(:components).test_management
|
372
|
+
end
|
305
373
|
end
|
306
374
|
end
|
307
375
|
end
|
@@ -208,10 +208,6 @@ module Datadog
|
|
208
208
|
ci_span.set_tags(@environment_tags)
|
209
209
|
|
210
210
|
ci_span.set_metric(Ext::Test::METRIC_CPU_COUNT, Utils::TestRun.virtual_cpu_count)
|
211
|
-
ci_span.set_tag(
|
212
|
-
Ext::Test::TAG_USER_PROVIDED_TEST_SERVICE,
|
213
|
-
Utils::Configuration.service_name_provided_by_user?.to_s
|
214
|
-
)
|
215
211
|
end
|
216
212
|
|
217
213
|
# PROPAGATING CONTEXT FROM TOP-LEVEL TO THE LOWER LEVELS
|
@@ -10,9 +10,9 @@ require_relative "../utils/test_run"
|
|
10
10
|
|
11
11
|
module Datadog
|
12
12
|
module CI
|
13
|
-
module
|
14
|
-
#
|
15
|
-
class
|
13
|
+
module TestVisibility
|
14
|
+
# fetches and stores a list of known tests from the backend
|
15
|
+
class KnownTests
|
16
16
|
class Response
|
17
17
|
def initialize(http_response)
|
18
18
|
@http_response = http_response
|
@@ -66,7 +66,7 @@ module Datadog
|
|
66
66
|
@config_tags = config_tags
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
69
|
+
def fetch(test_session)
|
70
70
|
api = @api
|
71
71
|
return Set.new unless api
|
72
72
|
|
@@ -78,21 +78,21 @@ module Datadog
|
|
78
78
|
payload: request_payload
|
79
79
|
)
|
80
80
|
|
81
|
-
Transport::Telemetry.api_requests(
|
82
|
-
Ext::Telemetry::
|
81
|
+
CI::Transport::Telemetry.api_requests(
|
82
|
+
Ext::Telemetry::METRIC_KNOWN_TESTS_REQUEST,
|
83
83
|
1,
|
84
84
|
compressed: http_response.request_compressed
|
85
85
|
)
|
86
|
-
Utils::Telemetry.distribution(Ext::Telemetry::
|
86
|
+
Utils::Telemetry.distribution(Ext::Telemetry::METRIC_KNOWN_TESTS_REQUEST_MS, http_response.duration_ms)
|
87
87
|
Utils::Telemetry.distribution(
|
88
|
-
Ext::Telemetry::
|
88
|
+
Ext::Telemetry::METRIC_KNOWN_TESTS_RESPONSE_BYTES,
|
89
89
|
http_response.response_size.to_f,
|
90
90
|
{Ext::Telemetry::TAG_RESPONSE_COMPRESSED => http_response.gzipped_content?.to_s}
|
91
91
|
)
|
92
92
|
|
93
93
|
unless http_response.ok?
|
94
|
-
Transport::Telemetry.api_requests_errors(
|
95
|
-
Ext::Telemetry::
|
94
|
+
CI::Transport::Telemetry.api_requests_errors(
|
95
|
+
Ext::Telemetry::METRIC_KNOWN_TESTS_REQUEST_ERRORS,
|
96
96
|
1,
|
97
97
|
error_type: http_response.telemetry_error_type,
|
98
98
|
status_code: http_response.code
|
@@ -9,7 +9,7 @@ module Datadog
|
|
9
9
|
module Serializers
|
10
10
|
module Factories
|
11
11
|
# This factory takes care of creating msgpack serializers when test-level visibility is enabled
|
12
|
-
# NOTE: citestcycle is a protocol Datadog uses to submit test execution tracing information to
|
12
|
+
# NOTE: citestcycle is a protocol Datadog uses to submit test execution tracing information to Test Optimization
|
13
13
|
# backend
|
14
14
|
module TestLevel
|
15
15
|
module_function
|
@@ -54,8 +54,11 @@ module Datadog
|
|
54
54
|
# codeowner tag
|
55
55
|
tags[Ext::Telemetry::TAG_HAS_CODEOWNER] = "true" if span.get_tag(Ext::Test::TAG_CODEOWNERS)
|
56
56
|
|
57
|
-
# set is_retry
|
58
|
-
|
57
|
+
# set is_retry and retry_reason tags if span represents a retried test
|
58
|
+
if span.get_tag(Ext::Test::TAG_IS_RETRY)
|
59
|
+
tags[Ext::Telemetry::TAG_IS_RETRY] = "true"
|
60
|
+
tags[Ext::Telemetry::TAG_RETRY_REASON] = span.get_tag(Ext::Test::TAG_RETRY_REASON)
|
61
|
+
end
|
59
62
|
|
60
63
|
# is_new
|
61
64
|
tags[Ext::Telemetry::TAG_IS_NEW] = "true" if span.get_tag(Ext::Test::TAG_IS_NEW)
|
@@ -66,6 +69,12 @@ module Datadog
|
|
66
69
|
tags[Ext::Telemetry::TAG_EARLY_FLAKE_DETECTION_ABORT_REASON] = early_flake_detection_abort_reason
|
67
70
|
end
|
68
71
|
|
72
|
+
# test management tags
|
73
|
+
tags[Ext::Telemetry::TAG_IS_ATTEMPT_TO_FIX] = "true" if span.get_tag(Ext::Test::TAG_IS_ATTEMPT_TO_FIX)
|
74
|
+
tags[Ext::Telemetry::TAG_IS_QUARANTINED] = "true" if span.get_tag(Ext::Test::TAG_IS_QUARANTINED)
|
75
|
+
tags[Ext::Telemetry::TAG_IS_TEST_DISABLED] = "true" if span.get_tag(Ext::Test::TAG_IS_TEST_DISABLED)
|
76
|
+
tags[Ext::Telemetry::TAG_HAS_FAILED_ALL_RETRIES] = "true" if span.get_tag(Ext::Test::TAG_HAS_FAILED_ALL_RETRIES)
|
77
|
+
|
69
78
|
tags
|
70
79
|
end
|
71
80
|
|