datadog-ci 1.13.0 → 1.14.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 +17 -2
- data/lib/datadog/ci/contrib/minitest/helpers.rb +26 -0
- data/lib/datadog/ci/contrib/minitest/runnable.rb +1 -19
- data/lib/datadog/ci/contrib/minitest/runner.rb +9 -5
- data/lib/datadog/ci/contrib/minitest/test.rb +2 -9
- data/lib/datadog/ci/contrib/rspec/runner.rb +1 -1
- data/lib/datadog/ci/span.rb +4 -0
- data/lib/datadog/ci/test_optimisation/component.rb +8 -29
- data/lib/datadog/ci/test_optimisation/skippable_percentage/base.rb +4 -0
- data/lib/datadog/ci/test_optimisation/skippable_percentage/calculator.rb +3 -3
- data/lib/datadog/ci/test_retries/strategy/retry_new.rb +1 -1
- data/lib/datadog/ci/test_session.rb +1 -1
- data/lib/datadog/ci/test_suite.rb +18 -0
- data/lib/datadog/ci/test_visibility/component.rb +58 -12
- data/lib/datadog/ci/test_visibility/context.rb +26 -13
- data/lib/datadog/ci/test_visibility/null_component.rb +1 -1
- data/lib/datadog/ci/test_visibility/store/global.rb +7 -0
- data/lib/datadog/ci/version.rb +1 -1
- data/lib/datadog/ci.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 694421f4e4621608a9aa6d8deb0b1407fa348fec68820a28ced1a567c56ed289
|
4
|
+
data.tar.gz: 12b586d1eabe233af428c7294564f8b7a46ff8bbb64d44f222762afd371a2c1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81c173cb2b22a8e0e3853d21d4e1ac023569142d51bb266c287ef7d4c7c5f2dfd97d2f3914acd1ac766d3e60ac15929cbee849b7284d300644113e6a14dea331
|
7
|
+
data.tar.gz: c1f1f93f35850cf9b6d1e360d53f2a26e2e46961aeed8e69f216327513e4001c45a42c363c20609ad0b525a4aeaf0fdec59e32f38d9302289c9e256ccf5aa81c
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.14.0] - 2025-03-11
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
* Test impact analysis: add rails parallel testing support ([#294][])
|
8
|
+
* Add parallel testing support to minitest framework ([#295][])
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
* Test knapsack_pro v8 ([#292][])
|
13
|
+
|
3
14
|
## [1.13.0] - 2025-02-25
|
4
15
|
|
5
16
|
### Added
|
@@ -393,7 +404,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
393
404
|
|
394
405
|
- Ruby versions < 2.7 no longer supported ([#8][])
|
395
406
|
|
396
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.
|
407
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.14.0...main
|
408
|
+
[1.14.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.13.0...v1.14.0
|
397
409
|
[1.13.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.12.0...v1.13.0
|
398
410
|
[1.12.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.11.0...v1.12.0
|
399
411
|
[1.11.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.10.0...v1.11.0
|
@@ -564,4 +576,7 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
564
576
|
[#275]: https://github.com/DataDog/datadog-ci-rb/issues/275
|
565
577
|
[#283]: https://github.com/DataDog/datadog-ci-rb/issues/283
|
566
578
|
[#286]: https://github.com/DataDog/datadog-ci-rb/issues/286
|
567
|
-
[#289]: https://github.com/DataDog/datadog-ci-rb/issues/289
|
579
|
+
[#289]: https://github.com/DataDog/datadog-ci-rb/issues/289
|
580
|
+
[#292]: https://github.com/DataDog/datadog-ci-rb/issues/292
|
581
|
+
[#294]: https://github.com/DataDog/datadog-ci-rb/issues/294
|
582
|
+
[#295]: https://github.com/DataDog/datadog-ci-rb/issues/295
|
@@ -5,6 +5,32 @@ module Datadog
|
|
5
5
|
module Contrib
|
6
6
|
module Minitest
|
7
7
|
module Helpers
|
8
|
+
def self.start_test_suite(klass)
|
9
|
+
method = klass.runnable_methods.first
|
10
|
+
return nil if method.nil?
|
11
|
+
|
12
|
+
test_suite_name = test_suite_name(klass, method)
|
13
|
+
source_file, line_number = extract_source_location_from_class(klass)
|
14
|
+
|
15
|
+
test_suite_tags = if source_file
|
16
|
+
{
|
17
|
+
CI::Ext::Test::TAG_SOURCE_FILE => (Git::LocalRepository.relative_to_root(source_file) if source_file),
|
18
|
+
CI::Ext::Test::TAG_SOURCE_START => line_number&.to_s
|
19
|
+
}
|
20
|
+
else
|
21
|
+
{}
|
22
|
+
end
|
23
|
+
|
24
|
+
test_visibility_component = Datadog.send(:components).test_visibility
|
25
|
+
test_suite = test_visibility_component.start_test_suite(
|
26
|
+
test_suite_name,
|
27
|
+
tags: test_suite_tags
|
28
|
+
)
|
29
|
+
test_suite&.set_expected_tests!(klass.runnable_methods)
|
30
|
+
|
31
|
+
test_suite
|
32
|
+
end
|
33
|
+
|
8
34
|
def self.test_suite_name(klass, method_name)
|
9
35
|
source_location = extract_source_location_from_class(klass)&.first
|
10
36
|
# if we are in anonymous class, fallback to the method source location
|
@@ -14,25 +14,7 @@ module Datadog
|
|
14
14
|
return super unless datadog_configuration[:enabled]
|
15
15
|
return super if Helpers.parallel?(self)
|
16
16
|
|
17
|
-
|
18
|
-
return super if method.nil?
|
19
|
-
|
20
|
-
test_suite_name = Helpers.test_suite_name(self, method)
|
21
|
-
source_file, line_number = Helpers.extract_source_location_from_class(self)
|
22
|
-
|
23
|
-
test_suite_tags = if source_file
|
24
|
-
{
|
25
|
-
CI::Ext::Test::TAG_SOURCE_FILE => (Git::LocalRepository.relative_to_root(source_file) if source_file),
|
26
|
-
CI::Ext::Test::TAG_SOURCE_START => line_number&.to_s
|
27
|
-
}
|
28
|
-
else
|
29
|
-
{}
|
30
|
-
end
|
31
|
-
|
32
|
-
test_suite = test_visibility_component.start_test_suite(
|
33
|
-
test_suite_name,
|
34
|
-
tags: test_suite_tags
|
35
|
-
)
|
17
|
+
test_suite = Helpers.start_test_suite(self)
|
36
18
|
|
37
19
|
results = super
|
38
20
|
return results unless test_suite
|
@@ -9,8 +9,6 @@ module Datadog
|
|
9
9
|
module Contrib
|
10
10
|
module Minitest
|
11
11
|
module Runner
|
12
|
-
DD_ESTIMATED_TESTS_PER_SUITE = 5
|
13
|
-
|
14
12
|
def self.included(base)
|
15
13
|
base.singleton_class.prepend(ClassMethods)
|
16
14
|
end
|
@@ -21,15 +19,15 @@ module Datadog
|
|
21
19
|
|
22
20
|
return unless datadog_configuration[:enabled]
|
23
21
|
|
24
|
-
|
25
|
-
|
22
|
+
tests_count = ::Minitest::Runnable.runnables.sum { |runnable| runnable.runnable_methods.size }
|
23
|
+
|
26
24
|
test_visibility_component.start_test_session(
|
27
25
|
tags: {
|
28
26
|
CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
|
29
27
|
CI::Ext::Test::TAG_FRAMEWORK_VERSION => datadog_integration.version.to_s
|
30
28
|
},
|
31
29
|
service: datadog_configuration[:service_name],
|
32
|
-
|
30
|
+
estimated_total_tests_count: tests_count
|
33
31
|
)
|
34
32
|
test_visibility_component.start_test_module(Ext::FRAMEWORK)
|
35
33
|
end
|
@@ -43,6 +41,12 @@ module Datadog
|
|
43
41
|
result = super
|
44
42
|
end
|
45
43
|
|
44
|
+
# get the current test suite and mark this method as done, so we can check if all tests were executed
|
45
|
+
# for this test suite
|
46
|
+
test_suite_name = Helpers.test_suite_name(klass, method_name)
|
47
|
+
test_suite = test_visibility_component.active_test_suite(test_suite_name)
|
48
|
+
test_suite&.expected_test_done!(method_name)
|
49
|
+
|
46
50
|
result
|
47
51
|
end
|
48
52
|
|
@@ -22,14 +22,11 @@ module Datadog
|
|
22
22
|
super
|
23
23
|
return unless datadog_configuration[:enabled]
|
24
24
|
|
25
|
-
test_suite_name = Helpers.test_suite_name(self.class, name)
|
26
25
|
if Helpers.parallel?(self.class)
|
27
|
-
|
28
|
-
|
29
|
-
# for parallel execution we need to start a new test suite for each test
|
30
|
-
test_visibility_component.start_test_suite(test_suite_name)
|
26
|
+
Helpers.start_test_suite(self.class)
|
31
27
|
end
|
32
28
|
|
29
|
+
test_suite_name = Helpers.test_suite_name(self.class, name)
|
33
30
|
source_file, line_number = method(name).source_location
|
34
31
|
|
35
32
|
test_span = test_visibility_component.trace_test(
|
@@ -56,10 +53,6 @@ module Datadog
|
|
56
53
|
# remove failures if test passed at least once on retries or quarantined
|
57
54
|
self.failures = [] if test_span.should_ignore_failures?
|
58
55
|
|
59
|
-
if Helpers.parallel?(self.class)
|
60
|
-
finish_with_result(test_span.test_suite, result_code)
|
61
|
-
end
|
62
|
-
|
63
56
|
super
|
64
57
|
end
|
65
58
|
|
@@ -25,7 +25,7 @@ module Datadog
|
|
25
25
|
CI::Ext::Test::TAG_FRAMEWORK_VERSION => datadog_integration.version.to_s
|
26
26
|
},
|
27
27
|
service: datadog_configuration[:service_name],
|
28
|
-
|
28
|
+
estimated_total_tests_count: ::RSpec.world.example_count
|
29
29
|
)
|
30
30
|
|
31
31
|
test_module = test_visibility_component.start_test_module(Ext::FRAMEWORK)
|
data/lib/datadog/ci/span.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "drb"
|
4
|
+
|
3
5
|
require "datadog/core/environment/platform"
|
4
6
|
|
5
7
|
require_relative "ext/test"
|
@@ -12,6 +14,8 @@ module Datadog
|
|
12
14
|
#
|
13
15
|
# @public_api
|
14
16
|
class Span
|
17
|
+
include DRb::DRbUndumped
|
18
|
+
|
15
19
|
attr_reader :tracer_span
|
16
20
|
|
17
21
|
def initialize(tracer_span)
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require "pp"
|
4
4
|
|
5
5
|
require "datadog/core/telemetry/logging"
|
6
|
-
require "datadog/core/utils/forking"
|
7
6
|
|
8
7
|
require_relative "../ext/test"
|
9
8
|
require_relative "../ext/telemetry"
|
@@ -24,10 +23,7 @@ module Datadog
|
|
24
23
|
# Integrates with backend to provide test impact analysis data and
|
25
24
|
# skip tests that are not impacted by the changes
|
26
25
|
class Component
|
27
|
-
include Core::Utils::Forking
|
28
|
-
|
29
26
|
attr_reader :correlation_id, :skippable_tests, :skippable_tests_fetch_error,
|
30
|
-
:skipped_tests_count, :total_tests_count,
|
31
27
|
:enabled, :test_skipping_enabled, :code_coverage_enabled
|
32
28
|
|
33
29
|
def initialize(
|
@@ -61,9 +57,6 @@ module Datadog
|
|
61
57
|
@correlation_id = nil
|
62
58
|
@skippable_tests = Set.new
|
63
59
|
|
64
|
-
@total_tests_count = 0
|
65
|
-
@skipped_tests_count = 0
|
66
|
-
|
67
60
|
@mutex = Mutex.new
|
68
61
|
|
69
62
|
Datadog.logger.debug("TestOptimisation initialized with enabled: #{@enabled}")
|
@@ -155,11 +148,6 @@ module Datadog
|
|
155
148
|
return if !enabled? || !skipping_tests?
|
156
149
|
|
157
150
|
if skippable?(test)
|
158
|
-
if forked?
|
159
|
-
Datadog.logger.warn { "Test Impact Analysis is not supported for forking test runners yet" }
|
160
|
-
return
|
161
|
-
end
|
162
|
-
|
163
151
|
test.set_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR, "true")
|
164
152
|
|
165
153
|
Datadog.logger.debug { "Marked test as skippable: #{test.datadog_test_id}" }
|
@@ -168,31 +156,22 @@ module Datadog
|
|
168
156
|
end
|
169
157
|
end
|
170
158
|
|
171
|
-
def
|
172
|
-
|
173
|
-
@total_tests_count += 1
|
159
|
+
def on_test_finished(test, context)
|
160
|
+
return if !test.skipped? || !test.skipped_by_test_impact_analysis?
|
174
161
|
|
175
|
-
|
162
|
+
Telemetry.itr_skipped
|
176
163
|
|
177
|
-
|
178
|
-
Datadog.logger.warn { "ITR is not supported for forking test runners yet" }
|
179
|
-
return
|
180
|
-
end
|
181
|
-
|
182
|
-
Telemetry.itr_skipped
|
183
|
-
|
184
|
-
@skipped_tests_count += 1
|
185
|
-
end
|
164
|
+
context.incr_tests_skipped_by_tia_count
|
186
165
|
end
|
187
166
|
|
188
|
-
def write_test_session_tags(test_session)
|
167
|
+
def write_test_session_tags(test_session, skipped_tests_count)
|
189
168
|
return if !enabled?
|
190
169
|
|
191
170
|
Datadog.logger.debug { "Finished optimised session with test skipping enabled: #{@test_skipping_enabled}" }
|
192
|
-
Datadog.logger.debug { "#{
|
171
|
+
Datadog.logger.debug { "#{skipped_tests_count} tests were skipped" }
|
193
172
|
|
194
|
-
test_session.set_tag(Ext::Test::TAG_ITR_TESTS_SKIPPED,
|
195
|
-
test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_COUNT,
|
173
|
+
test_session.set_tag(Ext::Test::TAG_ITR_TESTS_SKIPPED, skipped_tests_count.positive?.to_s)
|
174
|
+
test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_COUNT, skipped_tests_count)
|
196
175
|
end
|
197
176
|
|
198
177
|
def skippable_tests_count
|
@@ -34,11 +34,11 @@ module Datadog
|
|
34
34
|
return 0.0
|
35
35
|
end
|
36
36
|
|
37
|
-
log("Total tests count: #{
|
38
|
-
log("Skipped tests count: #{
|
37
|
+
log("Total tests count: #{test_visibility.total_tests_count}")
|
38
|
+
log("Skipped tests count: #{test_visibility.tests_skipped_by_tia_count}")
|
39
39
|
validate_test_optimisation_state!
|
40
40
|
|
41
|
-
(
|
41
|
+
(test_visibility.tests_skipped_by_tia_count.to_f / test_visibility.total_tests_count.to_f).floor(2)
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
@@ -70,7 +70,7 @@ module Datadog
|
|
70
70
|
|
71
71
|
def calculate_total_retries_limit(library_settings, test_session)
|
72
72
|
percentage_limit = library_settings.faulty_session_threshold
|
73
|
-
tests_count = test_session.
|
73
|
+
tests_count = test_session.estimated_total_tests_count.to_i
|
74
74
|
if tests_count.zero?
|
75
75
|
Datadog.logger.debug do
|
76
76
|
"Total tests count is zero, using default value for the total number of tests: [#{DEFAULT_TOTAL_TESTS_COUNT}]"
|
@@ -84,6 +84,24 @@ module Datadog
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
# @internal
|
88
|
+
def set_expected_tests!(expected_tests)
|
89
|
+
synchronize do
|
90
|
+
return if @expected_tests_set
|
91
|
+
|
92
|
+
@expected_tests_set = Set.new(expected_tests)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# @internal
|
97
|
+
def expected_test_done!(test_name)
|
98
|
+
synchronize do
|
99
|
+
@expected_tests_set.delete(test_name)
|
100
|
+
|
101
|
+
finish if @expected_tests_set.empty?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
87
105
|
private
|
88
106
|
|
89
107
|
def set_status_from_stats!
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "drb"
|
3
4
|
require "rbconfig"
|
4
5
|
|
6
|
+
require "datadog/core/utils/forking"
|
7
|
+
|
5
8
|
require_relative "context"
|
6
9
|
require_relative "telemetry"
|
7
10
|
require_relative "total_coverage"
|
@@ -16,9 +19,12 @@ require_relative "../worker"
|
|
16
19
|
module Datadog
|
17
20
|
module CI
|
18
21
|
module TestVisibility
|
19
|
-
#
|
22
|
+
# Core functionality of the library: tracing tests' execution
|
20
23
|
class Component
|
21
|
-
|
24
|
+
include Core::Utils::Forking
|
25
|
+
|
26
|
+
attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name,
|
27
|
+
:known_tests, :known_tests_enabled
|
22
28
|
|
23
29
|
def initialize(
|
24
30
|
known_tests_client:,
|
@@ -27,7 +33,9 @@ module Datadog
|
|
27
33
|
logical_test_session_name: nil
|
28
34
|
)
|
29
35
|
@test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
|
36
|
+
|
30
37
|
@context = Context.new
|
38
|
+
|
31
39
|
@codeowners = codeowners
|
32
40
|
@logical_test_session_name = logical_test_session_name
|
33
41
|
|
@@ -47,11 +55,13 @@ module Datadog
|
|
47
55
|
end
|
48
56
|
end
|
49
57
|
|
50
|
-
def start_test_session(service: nil, tags: {},
|
58
|
+
def start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0)
|
51
59
|
return skip_tracing unless test_suite_level_visibility_enabled
|
52
60
|
|
61
|
+
start_drb_service
|
62
|
+
|
53
63
|
test_session = @context.start_test_session(service: service, tags: tags)
|
54
|
-
test_session.
|
64
|
+
test_session.estimated_total_tests_count = estimated_total_tests_count
|
55
65
|
|
56
66
|
on_test_session_started(test_session)
|
57
67
|
test_session
|
@@ -68,14 +78,17 @@ module Datadog
|
|
68
78
|
def start_test_suite(test_suite_name, service: nil, tags: {})
|
69
79
|
return skip_tracing unless test_suite_level_visibility_enabled
|
70
80
|
|
71
|
-
test_suite =
|
81
|
+
test_suite = maybe_remote_context.start_test_suite(test_suite_name, service: service, tags: tags)
|
72
82
|
on_test_suite_started(test_suite)
|
73
83
|
test_suite
|
74
84
|
end
|
75
85
|
|
76
86
|
def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
|
87
|
+
test_suite = maybe_remote_context.active_test_suite(test_suite_name)
|
88
|
+
tags[Ext::Test::TAG_SUITE] ||= test_suite_name
|
89
|
+
|
77
90
|
if block
|
78
|
-
@context.trace_test(test_name,
|
91
|
+
@context.trace_test(test_name, test_suite, service: service, tags: tags) do |test|
|
79
92
|
subscribe_to_after_stop_event(test.tracer_span)
|
80
93
|
|
81
94
|
on_test_started(test)
|
@@ -84,7 +97,7 @@ module Datadog
|
|
84
97
|
res
|
85
98
|
end
|
86
99
|
else
|
87
|
-
test = @context.trace_test(test_name,
|
100
|
+
test = @context.trace_test(test_name, test_suite, service: service, tags: tags)
|
88
101
|
subscribe_to_after_stop_event(test.tracer_span)
|
89
102
|
on_test_started(test)
|
90
103
|
test
|
@@ -118,7 +131,7 @@ module Datadog
|
|
118
131
|
end
|
119
132
|
|
120
133
|
def active_test_suite(test_suite_name)
|
121
|
-
|
134
|
+
maybe_remote_context.active_test_suite(test_suite_name)
|
122
135
|
end
|
123
136
|
|
124
137
|
def deactivate_test
|
@@ -146,7 +159,15 @@ module Datadog
|
|
146
159
|
test_suite = active_test_suite(test_suite_name)
|
147
160
|
on_test_suite_finished(test_suite) if test_suite
|
148
161
|
|
149
|
-
|
162
|
+
maybe_remote_context.deactivate_test_suite(test_suite_name)
|
163
|
+
end
|
164
|
+
|
165
|
+
def total_tests_count
|
166
|
+
maybe_remote_context.total_tests_count
|
167
|
+
end
|
168
|
+
|
169
|
+
def tests_skipped_by_tia_count
|
170
|
+
maybe_remote_context.tests_skipped_by_tia_count
|
150
171
|
end
|
151
172
|
|
152
173
|
def itr_enabled?
|
@@ -190,6 +211,8 @@ module Datadog
|
|
190
211
|
end
|
191
212
|
|
192
213
|
def on_test_started(test)
|
214
|
+
maybe_remote_context.incr_total_tests_count
|
215
|
+
|
193
216
|
# sometimes test suite is not being assigned correctly
|
194
217
|
# fix it by fetching the one single running test suite from the global context
|
195
218
|
fix_test_suite!(test) if test.test_suite_id.nil?
|
@@ -208,7 +231,7 @@ module Datadog
|
|
208
231
|
end
|
209
232
|
|
210
233
|
def on_test_session_finished(test_session)
|
211
|
-
test_optimisation.write_test_session_tags(test_session)
|
234
|
+
test_optimisation.write_test_session_tags(test_session, maybe_remote_context.tests_skipped_by_tia_count)
|
212
235
|
|
213
236
|
TotalCoverage.extract_lines_pct(test_session)
|
214
237
|
|
@@ -216,6 +239,8 @@ module Datadog
|
|
216
239
|
end
|
217
240
|
|
218
241
|
def on_test_module_finished(test_module)
|
242
|
+
@context.stop_all_test_suites
|
243
|
+
|
219
244
|
Telemetry.event_finished(test_module)
|
220
245
|
end
|
221
246
|
|
@@ -225,7 +250,7 @@ module Datadog
|
|
225
250
|
|
226
251
|
def on_test_finished(test)
|
227
252
|
test_optimisation.stop_coverage(test)
|
228
|
-
test_optimisation.
|
253
|
+
test_optimisation.on_test_finished(test, maybe_remote_context)
|
229
254
|
|
230
255
|
Telemetry.event_finished(test)
|
231
256
|
|
@@ -258,7 +283,7 @@ module Datadog
|
|
258
283
|
def fix_test_suite!(test)
|
259
284
|
return unless test_suite_level_visibility_enabled
|
260
285
|
|
261
|
-
test_suite =
|
286
|
+
test_suite = maybe_remote_context.single_active_test_suite
|
262
287
|
unless test_suite
|
263
288
|
Datadog.logger.debug do
|
264
289
|
"Trying to fix test suite for test [#{test.name}] but no single test suite is running."
|
@@ -370,6 +395,27 @@ module Datadog
|
|
370
395
|
def test_management
|
371
396
|
Datadog.send(:components).test_management
|
372
397
|
end
|
398
|
+
|
399
|
+
# DISTRIBUTED RUBY CONTEXT
|
400
|
+
def start_drb_service
|
401
|
+
return if @context_service_uri
|
402
|
+
return if forked?
|
403
|
+
|
404
|
+
@context_service = DRb.start_service("drbunix:", @context)
|
405
|
+
@context_service_uri = @context_service.uri
|
406
|
+
end
|
407
|
+
|
408
|
+
# depending on whether we are in a forked process or not, returns either the global context or its DRbObject
|
409
|
+
def maybe_remote_context
|
410
|
+
return @context unless forked?
|
411
|
+
return @context_client if defined?(@context_client)
|
412
|
+
|
413
|
+
# once per fork we must stop the running DRb server that was copied from the parent process
|
414
|
+
# otherwise, client will be confused thinking it's server which leads to terrible bugs
|
415
|
+
@context_service.stop_service
|
416
|
+
|
417
|
+
@context_client = DRbObject.new_with_uri(@context_service_uri)
|
418
|
+
end
|
373
419
|
end
|
374
420
|
end
|
375
421
|
end
|
@@ -27,9 +27,16 @@ module Datadog
|
|
27
27
|
# Its responsibility includes building domain models for test visibility as well.
|
28
28
|
# Internally it uses Datadog::Tracing module to create spans.
|
29
29
|
class Context
|
30
|
+
attr_reader :total_tests_count, :tests_skipped_by_tia_count
|
31
|
+
|
30
32
|
def initialize
|
31
33
|
@local_context = Store::Local.new
|
32
34
|
@global_context = Store::Global.new
|
35
|
+
|
36
|
+
@mutex = Mutex.new
|
37
|
+
|
38
|
+
@total_tests_count = 0
|
39
|
+
@tests_skipped_by_tia_count = 0
|
33
40
|
end
|
34
41
|
|
35
42
|
def start_test_session(service: nil, tags: {})
|
@@ -66,17 +73,17 @@ module Datadog
|
|
66
73
|
tracer_span = start_datadog_tracer_span(
|
67
74
|
test_suite_name, build_tracing_span_options(service, Ext::AppTypes::TYPE_TEST_SUITE)
|
68
75
|
)
|
69
|
-
set_suite_context(tags,
|
76
|
+
set_suite_context(tags, test_suite: tracer_span)
|
70
77
|
|
71
78
|
build_test_suite(tracer_span, tags)
|
72
79
|
end
|
73
80
|
end
|
74
81
|
|
75
|
-
def trace_test(test_name,
|
82
|
+
def trace_test(test_name, test_suite, service: nil, tags: {}, &block)
|
76
83
|
set_inherited_globals(tags)
|
77
84
|
set_session_context(tags)
|
78
85
|
set_module_context(tags)
|
79
|
-
set_suite_context(tags,
|
86
|
+
set_suite_context(tags, test_suite: test_suite)
|
80
87
|
|
81
88
|
tags[Ext::Test::TAG_NAME] = test_name
|
82
89
|
tags[Ext::Test::TAG_TYPE] ||= Ext::Test::Type::TEST
|
@@ -148,6 +155,10 @@ module Datadog
|
|
148
155
|
@global_context.fetch_single_test_suite
|
149
156
|
end
|
150
157
|
|
158
|
+
def stop_all_test_suites
|
159
|
+
@global_context.stop_all_test_suites
|
160
|
+
end
|
161
|
+
|
151
162
|
def deactivate_test
|
152
163
|
@local_context.deactivate_test
|
153
164
|
end
|
@@ -164,6 +175,14 @@ module Datadog
|
|
164
175
|
@global_context.deactivate_test_suite!(test_suite_name)
|
165
176
|
end
|
166
177
|
|
178
|
+
def incr_total_tests_count
|
179
|
+
@mutex.synchronize { @total_tests_count += 1 }
|
180
|
+
end
|
181
|
+
|
182
|
+
def incr_tests_skipped_by_tia_count
|
183
|
+
@mutex.synchronize { @tests_skipped_by_tia_count += 1 }
|
184
|
+
end
|
185
|
+
|
167
186
|
private
|
168
187
|
|
169
188
|
# BUILDING DOMAIN MODELS
|
@@ -232,17 +251,11 @@ module Datadog
|
|
232
251
|
end
|
233
252
|
end
|
234
253
|
|
235
|
-
def set_suite_context(tags,
|
236
|
-
return if
|
254
|
+
def set_suite_context(tags, test_suite: nil)
|
255
|
+
return if test_suite.nil?
|
237
256
|
|
238
|
-
|
239
|
-
|
240
|
-
if test_suite
|
241
|
-
tags[Ext::Test::TAG_TEST_SUITE_ID] = test_suite.id.to_s
|
242
|
-
tags[Ext::Test::TAG_SUITE] = test_suite.name
|
243
|
-
else
|
244
|
-
tags[Ext::Test::TAG_SUITE] = name
|
245
|
-
end
|
257
|
+
tags[Ext::Test::TAG_TEST_SUITE_ID] = test_suite.id.to_s
|
258
|
+
tags[Ext::Test::TAG_SUITE] = test_suite.name
|
246
259
|
end
|
247
260
|
|
248
261
|
# INTERACTIONS WITH TRACING
|
@@ -59,6 +59,13 @@ module Datadog
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
def stop_all_test_suites
|
63
|
+
@mutex.synchronize do
|
64
|
+
@test_suites.each_value(&:finish)
|
65
|
+
@test_suites.clear
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
62
69
|
def inheritable_session_tags
|
63
70
|
@mutex.synchronize do
|
64
71
|
test_session = @test_session
|
data/lib/datadog/ci/version.rb
CHANGED
data/lib/datadog/ci.rb
CHANGED
@@ -49,7 +49,7 @@ module Datadog
|
|
49
49
|
1,
|
50
50
|
{Ext::Telemetry::TAG_EVENT_TYPE => Ext::Telemetry::EventType::SESSION}
|
51
51
|
)
|
52
|
-
test_visibility.start_test_session(service: service, tags: tags,
|
52
|
+
test_visibility.start_test_session(service: service, tags: tags, estimated_total_tests_count: total_tests_count)
|
53
53
|
end
|
54
54
|
|
55
55
|
# The active, unfinished test session.
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datadog-ci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: datadog
|
@@ -37,6 +37,20 @@ dependencies:
|
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: drb
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
40
54
|
description: |2
|
41
55
|
datadog-ci is a Datadog's Test Optimization library for Ruby. It traces
|
42
56
|
tests as they are being executed and brings developers visibility into
|