Class: Datadog::CI::TestVisibility::Component

Inherits:
Object
  • Object
show all
Includes:
Core::Utils::Forking, Utils::Stateful
Defined in:
lib/datadog/ci/test_visibility/component.rb

Overview

Core functionality of the library: tracing tests’ execution

Constant Summary collapse

FILE_STORAGE_KEY =
"test_visibility_component_state"

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils::Stateful

#load_component_state, #store_component_state

Constructor Details

#initialize(known_tests_client:, test_suite_level_visibility_enabled: false, codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse, logical_test_session_name: nil, context_service_uri: nil) ⇒ Component

Returns a new instance of Component.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/datadog/ci/test_visibility/component.rb', line 34

def initialize(
  known_tests_client:,
  test_suite_level_visibility_enabled: false,
  codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse,
  logical_test_session_name: nil,
  context_service_uri: nil
)
  @test_suite_level_visibility_enabled = test_suite_level_visibility_enabled

  @context = Context.new(test_visibility_component: self)

  @codeowners = codeowners
  @logical_test_session_name = logical_test_session_name

  # "Known tests" feature fetches a list of all tests known to Datadog for this repository
  # and uses this list to determine if a test is new or not. New tests are marked with "test.is_new" tag.
  @known_tests_enabled = false
  @known_tests_client = known_tests_client
  @known_tests = Set.new

  # this is used for parallel test runners such as parallel_tests
  if context_service_uri
    @context_service_uri = context_service_uri
    @is_client_process = true
  end

  # This is used for parallel test runners such as parallel_tests.
  # If true, then test suites are created in the worker process, not the parent.
  #
  # The only test runner that requires creating test suites in the remote process is rails test runner because
  # it splits workload by test, not by test suite.
  #
  # Another test runner that splits workload by test is knapsack_pro, but we lack distributed test sessions/test suties
  # support for that one (as of 2025-03).
  @local_test_suites_mode = true
end

Instance Attribute Details

#context_service_uriObject (readonly)

Returns the value of attribute context_service_uri.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def context_service_uri
  @context_service_uri
end

#known_testsObject (readonly)

Returns the value of attribute known_tests.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def known_tests
  @known_tests
end

#known_tests_enabledObject (readonly)

Returns the value of attribute known_tests_enabled.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def known_tests_enabled
  @known_tests_enabled
end

#local_test_suites_modeObject (readonly)

Returns the value of attribute local_test_suites_mode.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def local_test_suites_mode
  @local_test_suites_mode
end

#logical_test_session_nameObject (readonly)

Returns the value of attribute logical_test_session_name.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def logical_test_session_name
  @logical_test_session_name
end

#test_suite_level_visibility_enabledObject (readonly)

Returns the value of attribute test_suite_level_visibility_enabled.



31
32
33
# File 'lib/datadog/ci/test_visibility/component.rb', line 31

def test_suite_level_visibility_enabled
  @test_suite_level_visibility_enabled
end

Instance Method Details

#active_spanObject



148
149
150
# File 'lib/datadog/ci/test_visibility/component.rb', line 148

def active_span
  @context.active_span
end

#active_testObject



152
153
154
# File 'lib/datadog/ci/test_visibility/component.rb', line 152

def active_test
  @context.active_test
end

#active_test_moduleObject



160
161
162
# File 'lib/datadog/ci/test_visibility/component.rb', line 160

def active_test_module
  maybe_remote_context.active_test_module
end

#active_test_sessionObject



156
157
158
# File 'lib/datadog/ci/test_visibility/component.rb', line 156

def active_test_session
  maybe_remote_context.active_test_session
end

#active_test_suite(test_suite_name) ⇒ Object



164
165
166
167
168
169
170
# File 'lib/datadog/ci/test_visibility/component.rb', line 164

def active_test_suite(test_suite_name)
  # when fetching test_suite to use as test's context, try local context instance first
  local_test_suite = @context.active_test_suite(test_suite_name)
  return local_test_suite if local_test_suite

  maybe_remote_context.active_test_suite(test_suite_name)
end

#client_process?Boolean

Returns:

  • (Boolean)


217
218
219
# File 'lib/datadog/ci/test_visibility/component.rb', line 217

def client_process?
  forked? || @is_client_process
end

#configure(library_configuration, test_session) ⇒ Object



71
72
73
74
75
76
77
78
79
80
# File 'lib/datadog/ci/test_visibility/component.rb', line 71

def configure(library_configuration, test_session)
  return unless test_suite_level_visibility_enabled
  return unless library_configuration.known_tests_enabled?

  @known_tests_enabled = true
  return if load_component_state

  fetch_known_tests(test_session)
  store_component_state if test_session.distributed
end

#deactivate_testObject



172
173
174
175
176
177
# File 'lib/datadog/ci/test_visibility/component.rb', line 172

def deactivate_test
  test = active_test
  on_test_finished(test) if test

  @context.deactivate_test
end

#deactivate_test_moduleObject



186
187
188
189
190
191
# File 'lib/datadog/ci/test_visibility/component.rb', line 186

def deactivate_test_module
  test_module = active_test_module
  on_test_module_finished(test_module) if test_module

  @context.deactivate_test_module
end

#deactivate_test_sessionObject



179
180
181
182
183
184
# File 'lib/datadog/ci/test_visibility/component.rb', line 179

def deactivate_test_session
  test_session = active_test_session
  on_test_session_finished(test_session) if test_session

  @context.deactivate_test_session
end

#deactivate_test_suite(test_suite_name) ⇒ Object



193
194
195
196
197
198
199
# File 'lib/datadog/ci/test_visibility/component.rb', line 193

def deactivate_test_suite(test_suite_name)
  test_suite = active_test_suite(test_suite_name)
  on_test_suite_finished(test_suite) if test_suite

  # deactivation always happens on the same process where test suite is located
  @context.deactivate_test_suite(test_suite_name)
end

#itr_enabled?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/datadog/ci/test_visibility/component.rb', line 209

def itr_enabled?
  test_optimisation.enabled?
end

#shutdown!Object



213
214
215
# File 'lib/datadog/ci/test_visibility/component.rb', line 213

def shutdown!
  # noop, there is no thread owned by test visibility component
end

#start_test_module(test_module_name, service: nil, tags: {}) ⇒ Object



98
99
100
101
102
103
104
105
# File 'lib/datadog/ci/test_visibility/component.rb', line 98

def start_test_module(test_module_name, service: nil, tags: {})
  return skip_tracing unless test_suite_level_visibility_enabled

  test_module = maybe_remote_context.start_test_module(test_module_name, service: service, tags: tags)
  on_test_module_started(test_module)

  test_module
end

#start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0, distributed: false, local_test_suites_mode: true) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/datadog/ci/test_visibility/component.rb', line 82

def start_test_session(service: nil, tags: {}, estimated_total_tests_count: 0, distributed: false, local_test_suites_mode: true)
  return skip_tracing unless test_suite_level_visibility_enabled

  @local_test_suites_mode = local_test_suites_mode

  start_drb_service

  test_session = maybe_remote_context.start_test_session(service: service, tags: tags)
  test_session.estimated_total_tests_count = estimated_total_tests_count
  test_session.distributed = distributed

  on_test_session_started(test_session)

  test_session
end

#start_test_suite(test_suite_name, service: nil, tags: {}) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/datadog/ci/test_visibility/component.rb', line 107

def start_test_suite(test_suite_name, service: nil, tags: {})
  return skip_tracing unless test_suite_level_visibility_enabled

  context = @local_test_suites_mode ? @context : maybe_remote_context

  test_suite = context.start_test_suite(test_suite_name, service: service, tags: tags)
  on_test_suite_started(test_suite)
  test_suite
end

#tests_skipped_by_tia_countObject



205
206
207
# File 'lib/datadog/ci/test_visibility/component.rb', line 205

def tests_skipped_by_tia_count
  maybe_remote_context.tests_skipped_by_tia_count
end

#total_tests_countObject



201
202
203
# File 'lib/datadog/ci/test_visibility/component.rb', line 201

def total_tests_count
  maybe_remote_context.total_tests_count
end

#trace(span_name, type: "span", tags: {}, &block) ⇒ Object



138
139
140
141
142
143
144
145
146
# File 'lib/datadog/ci/test_visibility/component.rb', line 138

def trace(span_name, type: "span", tags: {}, &block)
  if block
    @context.trace(span_name, type: type, tags: tags) do |span|
      block.call(span)
    end
  else
    @context.trace(span_name, type: type, tags: tags)
  end
end

#trace_test(test_name, test_suite_name, service: nil, tags: {}, &block) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/datadog/ci/test_visibility/component.rb', line 117

def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
  test_suite = active_test_suite(test_suite_name)
  tags[Ext::Test::TAG_SUITE] ||= test_suite_name

  if block
    @context.trace_test(test_name, test_suite, service: service, tags: tags) do |test|
      subscribe_to_after_stop_event(test.tracer_span)

      on_test_started(test)
      res = block.call(test)
      on_test_finished(test)
      res
    end
  else
    test = @context.trace_test(test_name, test_suite, service: service, tags: tags)
    subscribe_to_after_stop_event(test.tracer_span)
    on_test_started(test)
    test
  end
end