Skip to content

Commit

Permalink
Merge pull request #108 from DataDog/anmarchenko/trace_remove_type_param
Browse files Browse the repository at this point in the history
[CIVIS-8333] improvements for manual tracing API
  • Loading branch information
anmarchenko authored Jan 18, 2024
2 parents d8274b0 + c89c711 commit a21b953
Show file tree
Hide file tree
Showing 36 changed files with 245 additions and 532 deletions.
90 changes: 37 additions & 53 deletions lib/datadog/ci.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

require_relative "ci/version"
require_relative "ci/utils/configuration"
require_relative "ci/ext/app_types"

require "datadog/core"

Expand All @@ -9,6 +11,8 @@ module Datadog
#
# @public_api
module CI
class ReservedTypeError < StandardError; end

class << self
# Starts a {Datadog::CI::TestSession ci_test_session} that represents the whole test session run.
#
Expand All @@ -30,13 +34,11 @@ class << self
#
# Remember that calling {Datadog::CI::TestSession#finish} is mandatory.
#
# @param [String] service the service name for this session (optional, defaults to DD_SERVICE)
# @param [String] service the service name for this session (optional, defaults to DD_SERVICE or repository name)
# @param [Hash<String,String>] tags extra tags which should be added to the test session.
# @return [Datadog::CI::TestSession] returns the active, running {Datadog::CI::TestSession}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
# detected and test suite level visibility cannot be supported.
def start_test_session(service: nil, tags: {})
service ||= Datadog.configuration.service
# @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)
end

Expand Down Expand Up @@ -88,9 +90,8 @@ def active_test_session
# @param [String] test_module_name the name for this module
# @param [String] service the service name for this session (optional, inherited from test session if not provided)
# @param [Hash<String,String>] tags extra tags which should be added to the test module (optional, some tags are inherited from test session).
# @return [Datadog::CI::TestModule] returns the active, running {Datadog::CI::TestModule}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
# detected and test suite level visibility cannot be supported.
# @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)
end
Expand Down Expand Up @@ -141,9 +142,8 @@ def active_test_module
# @param [String] test_suite_name the name of the test suite
# @param [String] service the service name for this test suite (optional, inherited from test session if not provided)
# @param [Hash<String,String>] tags extra tags which should be added to the test module (optional, some tags are inherited from test session)
# @return [Datadog::CI::TestSuite] returns the active, running {Datadog::CI::TestSuite}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
# detected and test suite level visibility cannot be supported.
# @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)
end
Expand Down Expand Up @@ -217,10 +217,10 @@ def active_test_suite(test_suite_name)
# @return [Object] If a block is provided, returns the result of the block execution.
# @return [Datadog::CI::Test] If no block is provided, returns the active,
# unfinished {Datadog::CI::Test}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
# @return [nil] if no block is provided and CI mode is disabled.
# @yield Optional block where newly created {Datadog::CI::Test} captures the execution.
# @yieldparam [Datadog::CI::Test] ci_test the newly created and active [Datadog::CI::Test]
# @yieldparam [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
# @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)
end
Expand All @@ -245,8 +245,8 @@ def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
# @param [String] test_suite_name name of test suite this test belongs to (example: "CalculatorTest").
# @param [String] service the service name for this span (optional, inherited from test session if not provided)
# @param [Hash<String,String>] tags extra tags which should be added to the test.
# @return [Datadog::CI::Test] Returns the active, unfinished {Datadog::CI::Test}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
# @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)
end
Expand All @@ -260,8 +260,8 @@ def start_test(test_name, test_suite_name, service: nil, tags: {})
#
# ```
# Datadog::CI.trace(
# "step",
# "Given I have 42 cucumbers",
# type: "step",
# tags: {}
# ) do
# run_operation
Expand All @@ -271,31 +271,40 @@ def start_test(test_name, test_suite_name, service: nil, tags: {})
# The {.trace} method can also be used without a block in this way:
# ```
# ci_span = Datadog::CI.trace(
# "step",
# "Given I have 42 cucumbers",
# type: "step",
# tags: {}
# )
# # ... run test here ...
# ci_span.finish
# ```
# Remember that in this case, calling {Datadog::CI::Span#finish} is mandatory.
#
# @param [String] type custom, user-defined span type (for example "step" or "query").
# @param [String] span_name the resource this span refers, or `test` if it's missing
# @param [String] type custom, user-defined span type (for example "step" or "query").
# @param [Hash<String,String>] tags extra tags which should be added to the span.
# @return [Object] If a block is provided, returns the result of the block execution.
# @return [Datadog::CI::Span] If no block is provided, returns the active,
# unfinished {Datadog::CI::Span}.
# @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
# @return [nil] if CI visibility is disabled
# @raise [ReservedTypeError] if provided type is reserved for Datadog CI visibility
# @yield Optional block where newly created {Datadog::CI::Span} captures the execution.
# @yieldparam [Datadog::CI::Span] ci_span the newly created and active [Datadog::CI::Span]
# @yieldparam [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
def trace(type, span_name, tags: {}, &block)
recorder.trace(type, span_name, tags: tags, &block)
# @yieldparam [nil] ci_span if CI visibility is disabled
def trace(span_name, type: "span", tags: {}, &block)
if Ext::AppTypes::CI_SPAN_TYPES.include?(type)
raise(
ReservedTypeError,
"Span type #{type} is reserved for Datadog CI visibility. " \
"Reserved types are: #{Ext::AppTypes::CI_SPAN_TYPES}"
)
end

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

# The active, unfinished custom span if it matches given type.
# If no span is active, or if the active span is not a custom span with given type, returns nil.
# The active, unfinished custom (i.e. not test/suite/module/session) span.
# If no span is active, or if the active span is not a custom span, returns nil.
#
# The active span belongs to an {.active_test}.
#
Expand All @@ -314,12 +323,11 @@ def trace(type, span_name, tags: {}, &block)
# step_span.finish()
# ```
#
# @param [String] type type of the span to retrieve (for example "step" or "query") that was provided to {.trace}
# @return [Datadog::CI::Span] the active span
# @return [nil] if no span is active, or if the active span is not a custom span with given type
def active_span(type)
# @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 if span && span.type == type
span if span && !Ext::AppTypes::CI_SPAN_TYPES.include?(span.type)
end

# The active, unfinished test span.
Expand Down Expand Up @@ -347,30 +355,6 @@ def active_test
recorder.active_test
end

# Internal only, to finish a test use {Datadog::CI::Test#finish}
# @private
def deactivate_test(test)
recorder.deactivate_test(test)
end

# Internal only, to finish a test session use {Datadog::CI::TestSession#finish}
# @private
def deactivate_test_session
recorder.deactivate_test_session
end

# Internal only, to finish a test module use {Datadog::CI::TestModule#finish}
# @private
def deactivate_test_module
recorder.deactivate_test_module
end

# Internal only, to finish a test suite use {Datadog::CI::TestSuite#finish}
# @private
def deactivate_test_suite(test_suite_name)
recorder.deactivate_test_suite(test_suite_name)
end

private

def components
Expand Down
10 changes: 5 additions & 5 deletions lib/datadog/ci/contrib/cucumber/formatter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def on_test_run_started(event)
},
service: configuration[:service_name]
)
CI.start_test_module(test_session.name)
CI.start_test_module(test_session.name) if test_session
end

def on_test_run_finished(event)
Expand Down Expand Up @@ -71,7 +71,7 @@ def on_test_case_started(event)
service: configuration[:service_name]
)

if (parameters = extract_parameters_hash(event.test_case))
if test_span && (parameters = extract_parameters_hash(event.test_case))
test_span.set_parameters(parameters)
end
end
Expand All @@ -94,11 +94,11 @@ def on_test_case_finished(event)
end

def on_test_step_started(event)
CI.trace(Ext::STEP_SPAN_TYPE, event.test_step.to_s)
CI.trace(event.test_step.to_s, type: Ext::STEP_SPAN_TYPE)
end

def on_test_step_finished(event)
current_step_span = CI.active_span(Ext::STEP_SPAN_TYPE)
current_step_span = CI.active_span
return if current_step_span.nil?

finish_test(current_step_span, event.result)
Expand Down Expand Up @@ -157,7 +157,7 @@ def start_test_suite(test_suite_name)

test_suite = CI.start_test_suite(test_suite_name)
# will be overridden if any test fails
test_suite.passed!
test_suite.passed! if test_suite

@current_test_suite = test_suite
end
Expand Down
2 changes: 1 addition & 1 deletion lib/datadog/ci/contrib/minitest/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def plugin_datadog_ci_init(*)
},
service: datadog_configuration[:service_name]
)
CI.start_test_module(test_session.name)
CI.start_test_module(test_session.name) if test_session

reporter.reporters << DatadogReporter.new(reporter)
end
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/ci/contrib/minitest/runnable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ def run(*)
test_suite_name = Helpers.test_suite_name(self, method)

test_suite = Datadog::CI.start_test_suite(test_suite_name)
test_suite.passed! # will be overridden if any test fails
test_suite.passed! if test_suite # will be overridden if any test fails

results = super
return results unless test_suite

test_suite.finish

Expand Down
20 changes: 11 additions & 9 deletions lib/datadog/ci/contrib/rspec/example.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,19 @@ def run(*)
},
service: datadog_configuration[:service_name]
) do |test_span|
test_span.set_parameters({}, {"scoped_id" => metadata[:scoped_id]})

result = super

case execution_result.status
when :passed
test_span.passed!
when :failed
test_span.failed!(exception: execution_result.exception)
else
test_span.skipped!(exception: execution_result.exception) if execution_result.example_skipped?
if test_span
test_span.set_parameters({}, {"scoped_id" => metadata[:scoped_id]})

case execution_result.status
when :passed
test_span.passed!
when :failed
test_span.failed!(exception: execution_result.exception)
else
test_span.skipped!(exception: execution_result.exception) if execution_result.example_skipped?
end
end

result
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/ci/contrib/rspec/example_group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def run(*)
test_suite = Datadog::CI.start_test_suite(suite_name)

result = super
return result unless test_suite

if result
test_suite.passed!
Expand Down
3 changes: 2 additions & 1 deletion lib/datadog/ci/contrib/rspec/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ def run_specs(*)
service: datadog_configuration[:service_name]
)

test_module = CI.start_test_module(test_session.name)
test_module = CI.start_test_module(test_session.name) if test_session

result = super
return result unless test_module && test_session

if result != 0
# TODO: repeating this twice feels clunky, we need to remove test_module API before GA
Expand Down
2 changes: 2 additions & 0 deletions lib/datadog/ci/ext/app_types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Datadog
module CI
module Ext
# Defines span types for CI visibility
# @public_api
module AppTypes
TYPE_TEST = "test"
TYPE_TEST_SESSION = "test_session_end"
Expand Down
66 changes: 0 additions & 66 deletions lib/datadog/ci/null_span.rb

This file was deleted.

Loading

0 comments on commit a21b953

Please sign in to comment.