datadog-ci 1.14.0 → 1.15.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 +2 -1
- data/lib/datadog/ci/configuration/settings.rb +6 -0
- data/lib/datadog/ci/contrib/minitest/runner.rb +4 -1
- data/lib/datadog/ci/contrib/parallel_tests/cli.rb +84 -0
- data/lib/datadog/ci/contrib/parallel_tests/configuration/settings.rb +32 -0
- data/lib/datadog/ci/contrib/parallel_tests/ext.rb +16 -0
- data/lib/datadog/ci/contrib/parallel_tests/integration.rb +42 -0
- data/lib/datadog/ci/contrib/parallel_tests/patcher.rb +24 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +7 -0
- data/lib/datadog/ci/contrib/rspec/example_group.rb +18 -8
- data/lib/datadog/ci/contrib/rspec/helpers.rb +18 -0
- data/lib/datadog/ci/contrib/rspec/runner.rb +2 -0
- data/lib/datadog/ci/ext/settings.rb +1 -0
- data/lib/datadog/ci/ext/test.rb +20 -0
- data/lib/datadog/ci/git/local_repository.rb +1 -1
- data/lib/datadog/ci/git/tree_uploader.rb +9 -0
- data/lib/datadog/ci/readonly_test_module.rb +28 -0
- data/lib/datadog/ci/readonly_test_session.rb +31 -0
- data/lib/datadog/ci/remote/component.rb +43 -16
- data/lib/datadog/ci/test_management/component.rb +34 -1
- data/lib/datadog/ci/test_management/tests_properties.rb +2 -1
- data/lib/datadog/ci/test_optimisation/component.rb +31 -5
- data/lib/datadog/ci/test_session.rb +7 -1
- data/lib/datadog/ci/test_visibility/component.rb +82 -28
- data/lib/datadog/ci/test_visibility/context.rb +77 -29
- data/lib/datadog/ci/test_visibility/null_component.rb +4 -0
- data/lib/datadog/ci/test_visibility/store/{local.rb → fiber_local.rb} +1 -1
- data/lib/datadog/ci/test_visibility/store/{global.rb → process.rb} +23 -18
- data/lib/datadog/ci/test_visibility/transport.rb +1 -2
- data/lib/datadog/ci/transport/http.rb +1 -1
- data/lib/datadog/ci/utils/file_storage.rb +57 -0
- data/lib/datadog/ci/utils/stateful.rb +52 -0
- data/lib/datadog/ci/version.rb +1 -1
- data/lib/datadog/ci.rb +4 -3
- metadata +14 -5
- data/lib/datadog/ci/test_visibility/capabilities.rb +0 -36
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require_relative "../ext/telemetry"
|
4
4
|
require_relative "../ext/test"
|
5
|
+
require_relative "../utils/stateful"
|
5
6
|
require_relative "../utils/telemetry"
|
6
7
|
require_relative "../utils/test_run"
|
7
8
|
|
@@ -14,6 +15,10 @@ module Datadog
|
|
14
15
|
# - marking test as disabled causes test to be skipped
|
15
16
|
# - marking test as "attempted to fix" causes test to be retried many times to confirm that fix worked
|
16
17
|
class Component
|
18
|
+
include Datadog::CI::Utils::Stateful
|
19
|
+
|
20
|
+
FILE_STORAGE_KEY = "test_management_component_state"
|
21
|
+
|
17
22
|
attr_reader :enabled, :tests_properties
|
18
23
|
|
19
24
|
def initialize(enabled:, tests_properties_client:)
|
@@ -30,7 +35,11 @@ module Datadog
|
|
30
35
|
|
31
36
|
test_session.set_tag(Ext::Test::TAG_TEST_MANAGEMENT_ENABLED, "true")
|
32
37
|
|
33
|
-
|
38
|
+
# Load component state first, and if successful, skip fetching tests properties
|
39
|
+
if !load_component_state
|
40
|
+
@tests_properties = @tests_properties_client.fetch(test_session)
|
41
|
+
store_component_state if test_session.distributed
|
42
|
+
end
|
34
43
|
|
35
44
|
Utils::Telemetry.distribution(
|
36
45
|
Ext::Telemetry::METRIC_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS,
|
@@ -55,6 +64,30 @@ module Datadog
|
|
55
64
|
test_span.set_tag(Ext::Test::TAG_IS_TEST_DISABLED, "true") if test_properties["disabled"]
|
56
65
|
test_span.set_tag(Ext::Test::TAG_IS_ATTEMPT_TO_FIX, "true") if test_properties["attempt_to_fix"]
|
57
66
|
end
|
67
|
+
|
68
|
+
def attempt_to_fix?(datadog_fqn_test_id)
|
69
|
+
return false unless @enabled
|
70
|
+
|
71
|
+
test_properties = @tests_properties[datadog_fqn_test_id]
|
72
|
+
return false if test_properties.nil?
|
73
|
+
|
74
|
+
test_properties.fetch("attempt_to_fix", false)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Implementation of Stateful interface
|
78
|
+
def serialize_state
|
79
|
+
{
|
80
|
+
tests_properties: @tests_properties
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def restore_state(state)
|
85
|
+
@tests_properties = state[:tests_properties]
|
86
|
+
end
|
87
|
+
|
88
|
+
def storage_key
|
89
|
+
FILE_STORAGE_KEY
|
90
|
+
end
|
58
91
|
end
|
59
92
|
end
|
60
93
|
end
|
@@ -117,7 +117,8 @@ module Datadog
|
|
117
117
|
"id" => Datadog::Core::Environment::Identity.id,
|
118
118
|
"type" => Ext::Transport::DD_API_TEST_MANAGEMENT_TESTS_TYPE,
|
119
119
|
"attributes" => {
|
120
|
-
"repository_url" => test_session.git_repository_url
|
120
|
+
"repository_url" => test_session.git_repository_url,
|
121
|
+
"commit_message" => test_session.git_commit_message
|
121
122
|
}
|
122
123
|
}
|
123
124
|
}.to_json
|
@@ -10,6 +10,7 @@ require_relative "../ext/telemetry"
|
|
10
10
|
require_relative "../git/local_repository"
|
11
11
|
|
12
12
|
require_relative "../utils/parsing"
|
13
|
+
require_relative "../utils/stateful"
|
13
14
|
require_relative "../utils/telemetry"
|
14
15
|
|
15
16
|
require_relative "coverage/event"
|
@@ -23,6 +24,10 @@ module Datadog
|
|
23
24
|
# Integrates with backend to provide test impact analysis data and
|
24
25
|
# skip tests that are not impacted by the changes
|
25
26
|
class Component
|
27
|
+
include Datadog::CI::Utils::Stateful
|
28
|
+
|
29
|
+
FILE_STORAGE_KEY = "test_optimisation_component_state"
|
30
|
+
|
26
31
|
attr_reader :correlation_id, :skippable_tests, :skippable_tests_fetch_error,
|
27
32
|
:enabled, :test_skipping_enabled, :code_coverage_enabled
|
28
33
|
|
@@ -78,9 +83,13 @@ module Datadog
|
|
78
83
|
|
79
84
|
load_datadog_cov! if @code_coverage_enabled
|
80
85
|
|
81
|
-
|
86
|
+
# Load component state first, and if successful, skip fetching skippable tests
|
87
|
+
if skipping_tests? && !load_component_state
|
88
|
+
fetch_skippable_tests(test_session)
|
89
|
+
store_component_state if test_session.distributed
|
90
|
+
end
|
82
91
|
|
83
|
-
|
92
|
+
Datadog.logger.debug("Configured TestOptimisation with enabled: #{@enabled}, skipping_tests: #{@test_skipping_enabled}, code_coverage: #{@code_coverage_enabled}")
|
84
93
|
end
|
85
94
|
|
86
95
|
def enabled?
|
@@ -138,16 +147,16 @@ module Datadog
|
|
138
147
|
event
|
139
148
|
end
|
140
149
|
|
141
|
-
def skippable?(
|
150
|
+
def skippable?(datadog_test_id)
|
142
151
|
return false if !enabled? || !skipping_tests?
|
143
152
|
|
144
|
-
@skippable_tests.include?(
|
153
|
+
@skippable_tests.include?(datadog_test_id)
|
145
154
|
end
|
146
155
|
|
147
156
|
def mark_if_skippable(test)
|
148
157
|
return if !enabled? || !skipping_tests?
|
149
158
|
|
150
|
-
if skippable?(test)
|
159
|
+
if skippable?(test.datadog_test_id) && !test.attempt_to_fix?
|
151
160
|
test.set_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR, "true")
|
152
161
|
|
153
162
|
Datadog.logger.debug { "Marked test as skippable: #{test.datadog_test_id}" }
|
@@ -182,6 +191,23 @@ module Datadog
|
|
182
191
|
@coverage_writer&.stop
|
183
192
|
end
|
184
193
|
|
194
|
+
# Implementation of Stateful interface
|
195
|
+
def serialize_state
|
196
|
+
{
|
197
|
+
correlation_id: @correlation_id,
|
198
|
+
skippable_tests: @skippable_tests
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def restore_state(state)
|
203
|
+
@correlation_id = state[:correlation_id]
|
204
|
+
@skippable_tests = state[:skippable_tests]
|
205
|
+
end
|
206
|
+
|
207
|
+
def storage_key
|
208
|
+
FILE_STORAGE_KEY
|
209
|
+
end
|
210
|
+
|
185
211
|
private
|
186
212
|
|
187
213
|
def write(event)
|
@@ -12,7 +12,7 @@ module Datadog
|
|
12
12
|
#
|
13
13
|
# @public_api
|
14
14
|
class TestSession < ConcurrentSpan
|
15
|
-
attr_accessor :estimated_total_tests_count
|
15
|
+
attr_accessor :estimated_total_tests_count, :distributed
|
16
16
|
|
17
17
|
# Finishes the current test session.
|
18
18
|
# @return [void]
|
@@ -46,6 +46,12 @@ module Datadog
|
|
46
46
|
get_tag(Ext::Environment::TAG_JOB_NAME)
|
47
47
|
end
|
48
48
|
|
49
|
+
# Returns the git commit message extracted from the environment.
|
50
|
+
# @return [String] the commit message.
|
51
|
+
def git_commit_message
|
52
|
+
get_tag(Ext::Git::TAG_COMMIT_MESSAGE)
|
53
|
+
end
|
54
|
+
|
49
55
|
def skipping_tests?
|
50
56
|
get_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED) == "true"
|
51
57
|
end
|
@@ -13,6 +13,8 @@ require_relative "../codeowners/parser"
|
|
13
13
|
require_relative "../contrib/instrumentation"
|
14
14
|
require_relative "../ext/test"
|
15
15
|
require_relative "../git/local_repository"
|
16
|
+
require_relative "../utils/file_storage"
|
17
|
+
require_relative "../utils/stateful"
|
16
18
|
|
17
19
|
require_relative "../worker"
|
18
20
|
|
@@ -22,19 +24,23 @@ module Datadog
|
|
22
24
|
# Core functionality of the library: tracing tests' execution
|
23
25
|
class Component
|
24
26
|
include Core::Utils::Forking
|
27
|
+
include Datadog::CI::Utils::Stateful
|
28
|
+
|
29
|
+
FILE_STORAGE_KEY = "test_visibility_component_state"
|
25
30
|
|
26
31
|
attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name,
|
27
|
-
:known_tests, :known_tests_enabled
|
32
|
+
:known_tests, :known_tests_enabled, :context_service_uri, :local_test_suites_mode
|
28
33
|
|
29
34
|
def initialize(
|
30
35
|
known_tests_client:,
|
31
36
|
test_suite_level_visibility_enabled: false,
|
32
37
|
codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse,
|
33
|
-
logical_test_session_name: nil
|
38
|
+
logical_test_session_name: nil,
|
39
|
+
context_service_uri: nil
|
34
40
|
)
|
35
41
|
@test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
|
36
42
|
|
37
|
-
@context = Context.new
|
43
|
+
@context = Context.new(test_visibility_component: self)
|
38
44
|
|
39
45
|
@codeowners = codeowners
|
40
46
|
@logical_test_session_name = logical_test_session_name
|
@@ -44,47 +50,72 @@ module Datadog
|
|
44
50
|
@known_tests_enabled = false
|
45
51
|
@known_tests_client = known_tests_client
|
46
52
|
@known_tests = Set.new
|
53
|
+
|
54
|
+
# this is used for parallel test runners such as parallel_tests
|
55
|
+
if context_service_uri
|
56
|
+
@context_service_uri = context_service_uri
|
57
|
+
@is_client_process = true
|
58
|
+
end
|
59
|
+
|
60
|
+
# This is used for parallel test runners such as parallel_tests.
|
61
|
+
# If true, then test suites are created in the worker process, not the parent.
|
62
|
+
#
|
63
|
+
# The only test runner that requires creating test suites in the remote process is rails test runner because
|
64
|
+
# it splits workload by test, not by test suite.
|
65
|
+
#
|
66
|
+
# Another test runner that splits workload by test is knapsack_pro, but we lack distributed test sessions/test suties
|
67
|
+
# support for that one (as of 2025-03).
|
68
|
+
@local_test_suites_mode = true
|
47
69
|
end
|
48
70
|
|
49
71
|
def configure(library_configuration, test_session)
|
50
72
|
return unless test_suite_level_visibility_enabled
|
73
|
+
return unless library_configuration.known_tests_enabled?
|
51
74
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
75
|
+
@known_tests_enabled = true
|
76
|
+
return if load_component_state
|
77
|
+
|
78
|
+
fetch_known_tests(test_session)
|
79
|
+
store_component_state if test_session.distributed
|
56
80
|
end
|
57
81
|
|
58
|
-
def start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0)
|
82
|
+
def start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0, distributed: false, local_test_suites_mode: true)
|
59
83
|
return skip_tracing unless test_suite_level_visibility_enabled
|
60
84
|
|
85
|
+
@local_test_suites_mode = local_test_suites_mode
|
86
|
+
|
61
87
|
start_drb_service
|
62
88
|
|
63
|
-
test_session =
|
89
|
+
test_session = maybe_remote_context.start_test_session(service: service, tags: tags)
|
64
90
|
test_session.estimated_total_tests_count = estimated_total_tests_count
|
91
|
+
test_session.distributed = distributed
|
65
92
|
|
66
93
|
on_test_session_started(test_session)
|
94
|
+
|
67
95
|
test_session
|
68
96
|
end
|
69
97
|
|
70
98
|
def start_test_module(test_module_name, service: nil, tags: {})
|
71
99
|
return skip_tracing unless test_suite_level_visibility_enabled
|
72
100
|
|
73
|
-
test_module =
|
101
|
+
test_module = maybe_remote_context.start_test_module(test_module_name, service: service, tags: tags)
|
74
102
|
on_test_module_started(test_module)
|
103
|
+
|
75
104
|
test_module
|
76
105
|
end
|
77
106
|
|
78
107
|
def start_test_suite(test_suite_name, service: nil, tags: {})
|
79
108
|
return skip_tracing unless test_suite_level_visibility_enabled
|
80
109
|
|
81
|
-
|
110
|
+
context = @local_test_suites_mode ? @context : maybe_remote_context
|
111
|
+
|
112
|
+
test_suite = context.start_test_suite(test_suite_name, service: service, tags: tags)
|
82
113
|
on_test_suite_started(test_suite)
|
83
114
|
test_suite
|
84
115
|
end
|
85
116
|
|
86
117
|
def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
|
87
|
-
test_suite =
|
118
|
+
test_suite = active_test_suite(test_suite_name)
|
88
119
|
tags[Ext::Test::TAG_SUITE] ||= test_suite_name
|
89
120
|
|
90
121
|
if block
|
@@ -123,14 +154,18 @@ module Datadog
|
|
123
154
|
end
|
124
155
|
|
125
156
|
def active_test_session
|
126
|
-
|
157
|
+
maybe_remote_context.active_test_session
|
127
158
|
end
|
128
159
|
|
129
160
|
def active_test_module
|
130
|
-
|
161
|
+
maybe_remote_context.active_test_module
|
131
162
|
end
|
132
163
|
|
133
164
|
def active_test_suite(test_suite_name)
|
165
|
+
# when fetching test_suite to use as test's context, try local context instance first
|
166
|
+
local_test_suite = @context.active_test_suite(test_suite_name)
|
167
|
+
return local_test_suite if local_test_suite
|
168
|
+
|
134
169
|
maybe_remote_context.active_test_suite(test_suite_name)
|
135
170
|
end
|
136
171
|
|
@@ -159,7 +194,8 @@ module Datadog
|
|
159
194
|
test_suite = active_test_suite(test_suite_name)
|
160
195
|
on_test_suite_finished(test_suite) if test_suite
|
161
196
|
|
162
|
-
|
197
|
+
# deactivation always happens on the same process where test suite is located
|
198
|
+
@context.deactivate_test_suite(test_suite_name)
|
163
199
|
end
|
164
200
|
|
165
201
|
def total_tests_count
|
@@ -178,6 +214,10 @@ module Datadog
|
|
178
214
|
# noop, there is no thread owned by test visibility component
|
179
215
|
end
|
180
216
|
|
217
|
+
def client_process?
|
218
|
+
forked? || @is_client_process
|
219
|
+
end
|
220
|
+
|
181
221
|
private
|
182
222
|
|
183
223
|
# DOMAIN EVENTS
|
@@ -188,10 +228,6 @@ module Datadog
|
|
188
228
|
# finds and instruments additional test libraries that we support (ex: selenium-webdriver)
|
189
229
|
Contrib::Instrumentation.instrument_on_session_start
|
190
230
|
|
191
|
-
# sends internal telemetry events
|
192
|
-
Telemetry.test_session_started(test_session)
|
193
|
-
Telemetry.event_created(test_session)
|
194
|
-
|
195
231
|
# sets logical test session name if none provided by the user
|
196
232
|
override_logical_test_session_name!(test_session) if logical_test_session_name.nil?
|
197
233
|
|
@@ -200,21 +236,22 @@ module Datadog
|
|
200
236
|
remote.configure(test_session)
|
201
237
|
end
|
202
238
|
|
239
|
+
# intentionally empty
|
203
240
|
def on_test_module_started(test_module)
|
204
|
-
Telemetry.event_created(test_module)
|
205
241
|
end
|
206
242
|
|
207
243
|
def on_test_suite_started(test_suite)
|
208
244
|
set_codeowners(test_suite)
|
209
|
-
|
210
|
-
Telemetry.event_created(test_suite)
|
211
245
|
end
|
212
246
|
|
213
247
|
def on_test_started(test)
|
214
248
|
maybe_remote_context.incr_total_tests_count
|
215
249
|
|
216
|
-
#
|
217
|
-
#
|
250
|
+
# Sometimes test suite is not being assigned correctly.
|
251
|
+
# Fix it by fetching the one single running test suite from the process context.
|
252
|
+
#
|
253
|
+
# This is a hack to fix some edge cases that come from some minitest plugins,
|
254
|
+
# especially thoughtbot/shoulda-context.
|
218
255
|
fix_test_suite!(test) if test.test_suite_id.nil?
|
219
256
|
validate_test_suite_level_visibility_correctness(test)
|
220
257
|
|
@@ -236,6 +273,8 @@ module Datadog
|
|
236
273
|
TotalCoverage.extract_lines_pct(test_session)
|
237
274
|
|
238
275
|
Telemetry.event_finished(test_session)
|
276
|
+
|
277
|
+
Utils::FileStorage.cleanup
|
239
278
|
end
|
240
279
|
|
241
280
|
def on_test_module_finished(test_module)
|
@@ -399,7 +438,7 @@ module Datadog
|
|
399
438
|
# DISTRIBUTED RUBY CONTEXT
|
400
439
|
def start_drb_service
|
401
440
|
return if @context_service_uri
|
402
|
-
return if
|
441
|
+
return if client_process?
|
403
442
|
|
404
443
|
@context_service = DRb.start_service("drbunix:", @context)
|
405
444
|
@context_service_uri = @context_service.uri
|
@@ -407,15 +446,30 @@ module Datadog
|
|
407
446
|
|
408
447
|
# depending on whether we are in a forked process or not, returns either the global context or its DRbObject
|
409
448
|
def maybe_remote_context
|
410
|
-
return @context unless
|
449
|
+
return @context unless client_process?
|
411
450
|
return @context_client if defined?(@context_client)
|
412
451
|
|
413
|
-
# once per fork we must stop the running DRb server that was copied from the parent process
|
452
|
+
# at least once per fork we must stop the running DRb server that was copied from the parent process
|
414
453
|
# otherwise, client will be confused thinking it's server which leads to terrible bugs
|
415
|
-
@context_service
|
454
|
+
@context_service&.stop_service
|
416
455
|
|
417
456
|
@context_client = DRbObject.new_with_uri(@context_service_uri)
|
418
457
|
end
|
458
|
+
|
459
|
+
# Implementation of Stateful interface
|
460
|
+
def serialize_state
|
461
|
+
{
|
462
|
+
known_tests: @known_tests
|
463
|
+
}
|
464
|
+
end
|
465
|
+
|
466
|
+
def restore_state(state)
|
467
|
+
@known_tests = state[:known_tests]
|
468
|
+
end
|
469
|
+
|
470
|
+
def storage_key
|
471
|
+
FILE_STORAGE_KEY
|
472
|
+
end
|
419
473
|
end
|
420
474
|
end
|
421
475
|
end
|
@@ -4,8 +4,9 @@ require "datadog/tracing"
|
|
4
4
|
require "datadog/tracing/contrib/component"
|
5
5
|
require "datadog/tracing/trace_digest"
|
6
6
|
|
7
|
-
require_relative "store/
|
8
|
-
require_relative "store/
|
7
|
+
require_relative "store/process"
|
8
|
+
require_relative "store/fiber_local"
|
9
|
+
require_relative "telemetry"
|
9
10
|
|
10
11
|
require_relative "../ext/app_types"
|
11
12
|
require_relative "../ext/environment"
|
@@ -29,9 +30,11 @@ module Datadog
|
|
29
30
|
class Context
|
30
31
|
attr_reader :total_tests_count, :tests_skipped_by_tia_count
|
31
32
|
|
32
|
-
def initialize
|
33
|
-
@
|
34
|
-
|
33
|
+
def initialize(test_visibility_component:)
|
34
|
+
@test_visibility_component = test_visibility_component
|
35
|
+
|
36
|
+
@fiber_local_context = Store::FiberLocal.new
|
37
|
+
@process_context = Store::Process.new
|
35
38
|
|
36
39
|
@mutex = Mutex.new
|
37
40
|
|
@@ -40,18 +43,23 @@ module Datadog
|
|
40
43
|
end
|
41
44
|
|
42
45
|
def start_test_session(service: nil, tags: {})
|
43
|
-
@
|
46
|
+
@process_context.fetch_or_activate_test_session do
|
44
47
|
tracer_span = start_datadog_tracer_span(
|
45
48
|
"test.session", build_tracing_span_options(service, Ext::AppTypes::TYPE_TEST_SESSION)
|
46
49
|
)
|
47
50
|
set_session_context(tags, tracer_span)
|
48
51
|
|
49
|
-
build_test_session(tracer_span, tags)
|
52
|
+
test_session = build_test_session(tracer_span, tags)
|
53
|
+
|
54
|
+
Telemetry.test_session_started(test_session)
|
55
|
+
Telemetry.event_created(test_session)
|
56
|
+
|
57
|
+
test_session
|
50
58
|
end
|
51
59
|
end
|
52
60
|
|
53
61
|
def start_test_module(test_module_name, service: nil, tags: {})
|
54
|
-
@
|
62
|
+
@process_context.fetch_or_activate_test_module do
|
55
63
|
set_inherited_globals(tags)
|
56
64
|
set_session_context(tags)
|
57
65
|
|
@@ -60,12 +68,16 @@ module Datadog
|
|
60
68
|
)
|
61
69
|
set_module_context(tags, tracer_span)
|
62
70
|
|
63
|
-
build_test_module(tracer_span, tags)
|
71
|
+
test_module = build_test_module(tracer_span, tags)
|
72
|
+
|
73
|
+
Telemetry.event_created(test_module)
|
74
|
+
|
75
|
+
test_module
|
64
76
|
end
|
65
77
|
end
|
66
78
|
|
67
79
|
def start_test_suite(test_suite_name, service: nil, tags: {})
|
68
|
-
@
|
80
|
+
@process_context.fetch_or_activate_test_suite(test_suite_name) do
|
69
81
|
set_inherited_globals(tags)
|
70
82
|
set_session_context(tags)
|
71
83
|
set_module_context(tags)
|
@@ -75,7 +87,11 @@ module Datadog
|
|
75
87
|
)
|
76
88
|
set_suite_context(tags, test_suite: tracer_span)
|
77
89
|
|
78
|
-
build_test_suite(tracer_span, tags)
|
90
|
+
test_suite = build_test_suite(tracer_span, tags)
|
91
|
+
|
92
|
+
Telemetry.event_created(test_suite)
|
93
|
+
|
94
|
+
test_suite
|
79
95
|
end
|
80
96
|
end
|
81
97
|
|
@@ -100,14 +116,14 @@ module Datadog
|
|
100
116
|
start_datadog_tracer_span(test_name, span_options) do |tracer_span|
|
101
117
|
test = build_test(tracer_span, tags)
|
102
118
|
|
103
|
-
@
|
119
|
+
@fiber_local_context.activate_test(test) do
|
104
120
|
block.call(test)
|
105
121
|
end
|
106
122
|
end
|
107
123
|
else
|
108
124
|
tracer_span = start_datadog_tracer_span(test_name, span_options)
|
109
125
|
test = build_test(tracer_span, tags)
|
110
|
-
@
|
126
|
+
@fiber_local_context.activate_test(test)
|
111
127
|
test
|
112
128
|
end
|
113
129
|
end
|
@@ -136,43 +152,43 @@ module Datadog
|
|
136
152
|
end
|
137
153
|
|
138
154
|
def active_test
|
139
|
-
@
|
155
|
+
@fiber_local_context.active_test
|
140
156
|
end
|
141
157
|
|
142
158
|
def active_test_session
|
143
|
-
@
|
159
|
+
@process_context.active_test_session
|
144
160
|
end
|
145
161
|
|
146
162
|
def active_test_module
|
147
|
-
@
|
163
|
+
@process_context.active_test_module
|
148
164
|
end
|
149
165
|
|
150
166
|
def active_test_suite(test_suite_name)
|
151
|
-
@
|
167
|
+
@process_context.active_test_suite(test_suite_name)
|
152
168
|
end
|
153
169
|
|
154
170
|
def single_active_test_suite
|
155
|
-
@
|
171
|
+
@process_context.fetch_single_test_suite
|
156
172
|
end
|
157
173
|
|
158
174
|
def stop_all_test_suites
|
159
|
-
@
|
175
|
+
@process_context.stop_all_test_suites
|
160
176
|
end
|
161
177
|
|
162
178
|
def deactivate_test
|
163
|
-
@
|
179
|
+
@fiber_local_context.deactivate_test
|
164
180
|
end
|
165
181
|
|
166
182
|
def deactivate_test_session
|
167
|
-
@
|
183
|
+
@process_context.deactivate_test_session!
|
168
184
|
end
|
169
185
|
|
170
186
|
def deactivate_test_module
|
171
|
-
@
|
187
|
+
@process_context.deactivate_test_module!
|
172
188
|
end
|
173
189
|
|
174
190
|
def deactivate_test_suite(test_suite_name)
|
175
|
-
@
|
191
|
+
@process_context.deactivate_test_suite!(test_suite_name)
|
176
192
|
end
|
177
193
|
|
178
194
|
def incr_total_tests_count
|
@@ -231,20 +247,21 @@ module Datadog
|
|
231
247
|
|
232
248
|
# PROPAGATING CONTEXT FROM TOP-LEVEL TO THE LOWER LEVELS
|
233
249
|
def set_inherited_globals(tags)
|
234
|
-
#
|
235
|
-
|
236
|
-
@global_context.inheritable_session_tags.each do |key, value|
|
250
|
+
# Copy inheritable tags from the test session context to the provided tags
|
251
|
+
test_session_context&.inheritable_tags&.each do |key, value|
|
237
252
|
tags[key] = value unless tags.key?(key)
|
238
253
|
end
|
239
254
|
end
|
240
255
|
|
241
256
|
def set_session_context(tags, test_session = nil)
|
242
|
-
|
257
|
+
# we need to call TestVisibility::Component here because active test session might be remote
|
258
|
+
test_session ||= test_session_context
|
243
259
|
tags[Ext::Test::TAG_TEST_SESSION_ID] = test_session.id.to_s if test_session
|
244
260
|
end
|
245
261
|
|
246
262
|
def set_module_context(tags, test_module = nil)
|
247
|
-
|
263
|
+
# we need to call TestVisibility::Component here because active test module might be remote
|
264
|
+
test_module ||= test_module_context
|
248
265
|
if test_module
|
249
266
|
tags[Ext::Test::TAG_TEST_MODULE_ID] = test_module.id.to_s
|
250
267
|
tags[Ext::Test::TAG_MODULE] = test_module.name
|
@@ -281,11 +298,42 @@ module Datadog
|
|
281
298
|
end
|
282
299
|
|
283
300
|
def build_tracing_span_options(service, type, other_options = {})
|
284
|
-
other_options[:service] = service ||
|
301
|
+
other_options[:service] = service || test_session_context&.service
|
285
302
|
other_options[:type] = type
|
286
303
|
|
287
304
|
other_options
|
288
305
|
end
|
306
|
+
|
307
|
+
# one of:
|
308
|
+
# 1. Currrent test session from the Store::Process
|
309
|
+
# 2. Readonly copy of the remote test session (if test session was started by a parent process and local copy was created)
|
310
|
+
# 3. Remote test session as DRb::DRbObject link (in this case also local copy will be created)
|
311
|
+
def test_session_context
|
312
|
+
local_test_session = @process_context.active_test_session
|
313
|
+
return local_test_session if local_test_session
|
314
|
+
|
315
|
+
local_readonly_test_session = @process_context.readonly_test_session
|
316
|
+
return local_readonly_test_session if local_readonly_test_session
|
317
|
+
|
318
|
+
remote_test_session = @test_visibility_component.active_test_session
|
319
|
+
@process_context.set_readonly_test_session(remote_test_session)
|
320
|
+
|
321
|
+
remote_test_session
|
322
|
+
end
|
323
|
+
|
324
|
+
# works similar to test_session_context
|
325
|
+
def test_module_context
|
326
|
+
local_test_module = @process_context.active_test_module
|
327
|
+
return local_test_module if local_test_module
|
328
|
+
|
329
|
+
local_readonly_test_module = @process_context.readonly_test_module
|
330
|
+
return local_readonly_test_module if local_readonly_test_module
|
331
|
+
|
332
|
+
remote_test_module = @test_visibility_component.active_test_module
|
333
|
+
@process_context.set_readonly_test_module(remote_test_module)
|
334
|
+
|
335
|
+
remote_test_module
|
336
|
+
end
|
289
337
|
end
|
290
338
|
end
|
291
339
|
end
|