Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDTEST-172] Refactor configs and components #196

Merged
merged 4 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ext/datadog_cov/datadog_cov.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,8 @@ void Init_datadog_cov(void)
{
VALUE mDatadog = rb_define_module("Datadog");
VALUE mCI = rb_define_module_under(mDatadog, "CI");
VALUE mITR = rb_define_module_under(mCI, "ITR");
VALUE mCoverage = rb_define_module_under(mITR, "Coverage");
VALUE mTestOptimisation = rb_define_module_under(mCI, "TestOptimisation");
VALUE mCoverage = rb_define_module_under(mTestOptimisation, "Coverage");
VALUE cDatadogCov = rb_define_class_under(mCoverage, "DDCov", rb_cObject);

rb_define_alloc_func(cDatadogCov, dd_cov_allocate);
Expand Down
30 changes: 15 additions & 15 deletions lib/datadog/ci.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class << self
# @return [Datadog::CI::TestSession] the active, running {Datadog::CI::TestSession}.
# @return [nil] if test suite level visibility is disabled or CI mode is disabled.
def start_test_session(service: Utils::Configuration.fetch_service_name("test"), tags: {})
recorder.start_test_session(service: service, tags: tags)
test_visibility.start_test_session(service: service, tags: tags)
end

# The active, unfinished test session.
Expand All @@ -61,7 +61,7 @@ def start_test_session(service: Utils::Configuration.fetch_service_name("test"),
# @return [Datadog::CI::TestSession] the active test session
# @return [nil] if no test session is active
def active_test_session
recorder.active_test_session
test_visibility.active_test_session
end

# Starts a {Datadog::CI::TestModule ci_test_module} that represents a single test module (for most Ruby test frameworks
Expand Down Expand Up @@ -93,7 +93,7 @@ def active_test_session
# @return [Datadog::CI::TestModule] the active, running {Datadog::CI::TestModule}.
# @return [nil] if test suite level visibility is disabled or CI mode is disabled.
def start_test_module(test_module_name, service: nil, tags: {})
recorder.start_test_module(test_module_name, service: service, tags: tags)
test_visibility.start_test_module(test_module_name, service: service, tags: tags)
end

# The active, unfinished test module.
Expand All @@ -116,7 +116,7 @@ def start_test_module(test_module_name, service: nil, tags: {})
# @return [Datadog::CI::TestModule] the active test module
# @return [nil] if no test module is active
def active_test_module
recorder.active_test_module
test_visibility.active_test_module
end

# Starts a {Datadog::CI::TestSuite ci_test_suite} that represents a single test suite.
Expand Down Expand Up @@ -145,7 +145,7 @@ def active_test_module
# @return [Datadog::CI::TestSuite] the active, running {Datadog::CI::TestSuite}.
# @return [nil] if test suite level visibility is disabled or CI mode is disabled.
def start_test_suite(test_suite_name, service: nil, tags: {})
recorder.start_test_suite(test_suite_name, service: service, tags: tags)
test_visibility.start_test_suite(test_suite_name, service: service, tags: tags)
end

# The active, unfinished test suite.
Expand All @@ -168,7 +168,7 @@ def start_test_suite(test_suite_name, service: nil, tags: {})
# @return [Datadog::CI::TestSuite] the active test suite
# @return [nil] if no test suite with given name is active
def active_test_suite(test_suite_name)
recorder.active_test_suite(test_suite_name)
test_visibility.active_test_suite(test_suite_name)
end

# Return a {Datadog::CI::Test ci_test} that will trace a test called `test_name`.
Expand Down Expand Up @@ -222,7 +222,7 @@ def active_test_suite(test_suite_name)
# @yieldparam [Datadog::CI::Test] ci_test the newly created and active [Datadog::CI::Test]
# @yieldparam [nil] if CI mode is disabled
def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
recorder.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
test_visibility.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
end

# Same as {.trace_test} but it does not accept a block.
Expand All @@ -248,7 +248,7 @@ def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
# @return [Datadog::CI::Test] the active, unfinished {Datadog::CI::Test}.
# @return [nil] if CI mode is disabled.
def start_test(test_name, test_suite_name, service: nil, tags: {})
recorder.trace_test(test_name, test_suite_name, service: service, tags: tags)
test_visibility.trace_test(test_name, test_suite_name, service: service, tags: tags)
end

# Trace any custom span inside a test. For example, you could trace:
Expand Down Expand Up @@ -300,7 +300,7 @@ def trace(span_name, type: "span", tags: {}, &block)
)
end

recorder.trace(span_name, type: type, tags: tags, &block)
test_visibility.trace(span_name, type: type, tags: tags, &block)
end

# The active, unfinished custom (i.e. not test/suite/module/session) span.
Expand All @@ -326,7 +326,7 @@ def trace(span_name, type: "span", tags: {}, &block)
# @return [Datadog::CI::Span] the active span
# @return [nil] if no span is active, or if the active span is not a custom span
def active_span
span = recorder.active_span
span = test_visibility.active_span
span if span && !Ext::AppTypes::CI_SPAN_TYPES.include?(span.type)
end

Expand All @@ -352,7 +352,7 @@ def active_span
# @return [Datadog::CI::Test] the active test
# @return [nil] if no test is active
def active_test
recorder.active_test
test_visibility.active_test
end

private
Expand All @@ -361,12 +361,12 @@ def components
Datadog.send(:components)
end

def recorder
components.ci_recorder
def test_visibility
components.test_visibility
end

def itr_runner
components.itr
def test_optimisation
components.test_optimisation
end
end
end
Expand Down
170 changes: 92 additions & 78 deletions lib/datadog/ci/configuration/components.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

require_relative "../ext/settings"
require_relative "../git/tree_uploader"
require_relative "../itr/runner"
require_relative "../itr/coverage/transport"
require_relative "../itr/coverage/writer"
require_relative "../test_optimisation/component"
require_relative "../test_optimisation/coverage/transport"
require_relative "../test_optimisation/coverage/writer"
require_relative "../test_visibility/component"
require_relative "../test_visibility/flush"
require_relative "../test_visibility/recorder"
require_relative "../test_visibility/null_recorder"
require_relative "../test_visibility/null_component"
require_relative "../test_visibility/serializers/factories/test_level"
require_relative "../test_visibility/serializers/factories/test_suite_level"
require_relative "../test_visibility/transport"
Expand All @@ -21,15 +21,15 @@ module CI
module Configuration
# Adds CI behavior to Datadog trace components
module Components
attr_reader :ci_recorder, :itr
attr_reader :test_visibility, :test_optimisation

def initialize(settings)
@test_optimisation = nil
@test_visibility = TestVisibility::NullComponent.new

# Activate CI mode if enabled
if settings.ci.enabled
activate_ci!(settings)
else
@itr = nil
@ci_recorder = TestVisibility::NullRecorder.new
end

super
Expand All @@ -38,8 +38,8 @@ def initialize(settings)
def shutdown!(replacement = nil)
super

@ci_recorder&.shutdown!
@itr&.shutdown!
@test_visibility&.shutdown!
@test_optimisation&.shutdown!
end

def activate_ci!(settings)
Expand All @@ -53,22 +53,21 @@ def activate_ci!(settings)
return
end

# Configure ddtrace library for CI visibility mode
# Builds test visibility API layer in agentless or EvP proxy mode
test_visibility_api = build_test_visibility_api(settings)
# bail out early if api is misconfigured
return unless settings.ci.enabled

# Configure datadog gem for test visibility mode

# Deactivate telemetry
settings.telemetry.enabled = false

# Deactivate remote configuration
# Test visibility uses its own remote settings
settings.remote.enabled = false

# do not use 128-bit trace ids for CI visibility
# they are used for OTEL compatibility in Datadog tracer
settings.tracing.trace_id_128_bit_generation_enabled = false

# Activate underlying tracing test mode
settings.tracing.test_mode.enabled = true

# Choose user defined TraceFlush or default to CI TraceFlush
settings.tracing.test_mode.trace_flush = settings.ci.trace_flush || CI::TestVisibility::Flush::Partial.new
# startup logs are useless for test visibility and create noise
settings.diagnostics.startup_logs.enabled = false

# When timecop is present, Time.now is mocked and .now_without_mock_time is added on Time to
# get the current time without the mock.
Expand All @@ -81,76 +80,42 @@ def activate_ci!(settings)
end
end

# startup logs are useless for CI visibility and create noise
settings.diagnostics.startup_logs.enabled = false

# transport creation
writer_options = settings.ci.writer_options
coverage_writer = nil
test_visibility_api = build_test_visibility_api(settings)
# Configure Datadog::Tracing module

if test_visibility_api
# setup writer for code coverage payloads
coverage_writer = ITR::Coverage::Writer.new(
transport: ITR::Coverage::Transport.new(api: test_visibility_api)
)

# configure tracing writer to send traces to CI visibility backend
writer_options[:transport] = TestVisibility::Transport.new(
api: test_visibility_api,
serializers_factory: serializers_factory(settings),
dd_env: settings.env
)
writer_options[:shutdown_timeout] = 60
writer_options[:buffer_size] = 10_000

settings.tracing.test_mode.async = true
else
# only legacy APM protocol is supported, so no test suite level visibility
settings.ci.force_test_level_visibility = true

# ITR is not supported with APM protocol
settings.ci.itr_enabled = false
end
# No need not use 128-bit trace ids for test visibility,
# they are used for OTEL compatibility in Datadog tracer
settings.tracing.trace_id_128_bit_generation_enabled = false

settings.tracing.test_mode.writer_options = writer_options
# Activate underlying tracing test mode with async worker
settings.tracing.test_mode.enabled = true
settings.tracing.test_mode.async = true
settings.tracing.test_mode.trace_flush = settings.ci.trace_flush || CI::TestVisibility::Flush::Partial.new

custom_configuration_tags = Utils::TestRun.custom_configuration(settings.tags)
trace_writer_options = settings.ci.writer_options
trace_writer_options[:shutdown_timeout] = 60
trace_writer_options[:buffer_size] = 10_000
tracing_transport = build_tracing_transport(settings, test_visibility_api)
trace_writer_options[:transport] = tracing_transport if tracing_transport

remote_settings_api = Transport::RemoteSettingsApi.new(
api: test_visibility_api,
dd_env: settings.env,
config_tags: custom_configuration_tags
)
settings.tracing.test_mode.writer_options = trace_writer_options

itr = ITR::Runner.new(
# @type ivar @test_optimisation: Datadog::CI::TestOptimisation::Component
@test_optimisation = TestOptimisation::Component.new(
api: test_visibility_api,
dd_env: settings.env,
config_tags: custom_configuration_tags,
coverage_writer: coverage_writer,
config_tags: custom_configuration(settings),
coverage_writer: build_coverage_writer(settings, test_visibility_api),
enabled: settings.ci.enabled && settings.ci.itr_enabled,
bundle_location: settings.ci.itr_code_coverage_excluded_bundle_path,
use_single_threaded_coverage: settings.ci.itr_code_coverage_use_single_threaded_mode
)

git_tree_uploader = Git::TreeUploader.new(api: test_visibility_api)
git_tree_upload_worker = if settings.ci.git_metadata_upload_enabled
Worker.new do |repository_url|
git_tree_uploader.call(repository_url)
end
else
DummyWorker.new
end

# CI visibility recorder global instance
@ci_recorder = TestVisibility::Recorder.new(
@test_visibility = TestVisibility::Component.new(
test_optimisation: @test_optimisation,
test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
itr: itr,
remote_settings_api: remote_settings_api,
git_tree_upload_worker: git_tree_upload_worker
remote_settings_api: build_remote_settings_client(settings, test_visibility_api),
git_tree_upload_worker: build_git_upload_worker(settings, test_visibility_api)
)

@itr = itr
end

def build_test_visibility_api(settings)
Expand Down Expand Up @@ -179,12 +144,61 @@ def build_test_visibility_api(settings)
Datadog.logger.debug(
"Old agent version detected, no evp_proxy support. Forcing test level visibility mode"
)

# only legacy APM protocol is supported, so no test suite level visibility
settings.ci.force_test_level_visibility = true

# ITR is not supported with APM protocol
settings.ci.itr_enabled = false
end
end

api
end

def build_tracing_transport(settings, api)
return nil if api.nil?

TestVisibility::Transport.new(
api: api,
serializers_factory: serializers_factory(settings),
dd_env: settings.env
)
end

def build_coverage_writer(settings, api)
return nil if api.nil?

TestOptimisation::Coverage::Writer.new(
transport: TestOptimisation::Coverage::Transport.new(api: api)
)
end

def build_git_upload_worker(settings, api)
if settings.ci.git_metadata_upload_enabled
git_tree_uploader = Git::TreeUploader.new(api: api)
Worker.new do |repository_url|
git_tree_uploader.call(repository_url)
end
else
DummyWorker.new
end
end

def build_remote_settings_client(settings, api)
Transport::RemoteSettingsApi.new(
api: api,
dd_env: settings.env,
config_tags: custom_configuration(settings)
)
end

# fetch custom tags provided by the user in DD_TAGS env var
# with prefix test.configuration.
def custom_configuration(settings)
@custom_configuration ||= Utils::TestRun.custom_configuration(settings.tags)
end

def serializers_factory(settings)
if settings.ci.force_test_level_visibility
TestVisibility::Serializers::Factories::TestLevel
Expand Down
6 changes: 3 additions & 3 deletions lib/datadog/ci/span.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ def to_s

private

# provides access to global CI recorder for CI models to deactivate themselves
def recorder
Datadog.send(:components).ci_recorder
# provides access to the test visibility component for CI models to deactivate themselves
def test_visibility
Datadog.send(:components).test_visibility
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/datadog/ci/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def name
# Finishes the current test.
# @return [void]
def finish
recorder.deactivate_test
test_visibility.deactivate_test

super
end
Expand Down
Loading
Loading