Skip to content

Commit

Permalink
Merge pull request #235 from DataDog/anmarchenko/logical_names_for_te…
Browse files Browse the repository at this point in the history
…st_sessions

[SDTEST-786] support logical names for test sessions
  • Loading branch information
anmarchenko authored Sep 20, 2024
2 parents 0fc0203 + 96c32c7 commit b8f49d9
Show file tree
Hide file tree
Showing 20 changed files with 204 additions and 13 deletions.
3 changes: 2 additions & 1 deletion lib/datadog/ci/configuration/components.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ def activate_ci!(settings)
# @type ivar @test_optimisation: Datadog::CI::TestOptimisation::Component
@test_optimisation = build_test_optimisation(settings, test_visibility_api)
@test_visibility = TestVisibility::Component.new(
test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility
test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
logical_test_session_name: settings.ci.test_session_name
)
end

Expand Down
5 changes: 5 additions & 0 deletions lib/datadog/ci/configuration/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ def self.add_settings!(base)
o.default false
end

option :test_session_name do |o|
o.type :string, nilable: true
o.env CI::Ext::Settings::ENV_TEST_SESSION_NAME
end

option :agentless_mode_enabled do |o|
o.type :bool
o.env CI::Ext::Settings::ENV_AGENTLESS_MODE_ENABLED
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/ci/ext/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Settings
ENV_RETRY_FAILED_TESTS_MAX_ATTEMPTS = "DD_CIVISIBILITY_FLAKY_RETRY_COUNT"
ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT = "DD_CIVISIBILITY_TOTAL_FLAKY_RETRY_COUNT"
ENV_RETRY_NEW_TESTS_ENABLED = "DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED"
ENV_TEST_SESSION_NAME = "DD_TEST_SESSION_NAME"

# Source: https://docs.datadoghq.com/getting_started/site/
DD_SITE_ALLOWLIST = %w[
Expand Down
3 changes: 3 additions & 0 deletions lib/datadog/ci/ext/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ module Test
TAG_SPAN_KIND = "span.kind"
SPAN_KIND_TEST = "test"

# common tags that are serialized directly in msgpack header in metadata field
METADATA_TAG_TEST_SESSION_NAME = "test_session.name"

# tags that are common for the whole session and can be inherited from the test session
INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze

Expand Down
18 changes: 18 additions & 0 deletions lib/datadog/ci/test_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ def name
get_tag(Ext::Test::TAG_COMMAND)
end

# Return the test session's command used to run the tests
# @return [String] the command for this test session.
def test_command
get_tag(Ext::Test::TAG_COMMAND)
end

# Return the test session's CI provider name (e.g. "travis", "circleci", etc.)
# @return [String] the provider name for this test session.
def ci_provider
get_tag(Ext::Environment::TAG_PROVIDER_NAME)
end

# Return the test session's CI job name (e.g. "build", "test", etc.)
# @return [String] the job name for this test session.
def ci_job_name
get_tag(Ext::Environment::TAG_JOB_NAME)
end

def skipping_tests?
get_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED) == "true"
end
Expand Down
17 changes: 15 additions & 2 deletions lib/datadog/ci/test_visibility/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ module CI
module TestVisibility
# Common behavior for CI tests
class Component
attr_reader :test_suite_level_visibility_enabled
attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name

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

def start_test_session(service: nil, tags: {}, total_tests_count: 0)
Expand Down Expand Up @@ -152,6 +154,9 @@ def on_test_session_started(test_session)
Telemetry.test_session_started(test_session)
Telemetry.event_created(test_session)

# sets logical test session name if none provided by the user
override_logical_test_session_name!(test_session) if logical_test_session_name.nil?

# signal Remote::Component to configure the library
remote.configure(test_session)
end
Expand Down Expand Up @@ -269,6 +274,14 @@ def validate_test_suite_level_visibility_correctness(test)
end
end

def override_logical_test_session_name!(test_session)
@logical_test_session_name = test_session.test_command
ci_job_name = test_session.ci_job_name
if ci_job_name
@logical_test_session_name = "#{ci_job_name}-#{@logical_test_session_name}"
end
end

def test_optimisation
Datadog.send(:components).test_optimisation
end
Expand Down
7 changes: 7 additions & 0 deletions lib/datadog/ci/test_visibility/null_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ def set_test_finished_callback(_)
def remove_test_finished_callback
end

def test_suite_level_visibility_enabled
false
end

def logical_test_session_name
end

private

def skip_tracing(block = nil)
Expand Down
4 changes: 1 addition & 3 deletions lib/datadog/ci/test_visibility/telemetry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ def self.test_session_started(test_session)
1,
{
Ext::Telemetry::TAG_AUTO_INJECTED => "false", # ruby doesn't support auto injection yet
Ext::Telemetry::TAG_PROVIDER =>
test_session.get_tag(Ext::Environment::TAG_PROVIDER_NAME) ||
Ext::Telemetry::Provider::UNSUPPORTED
Ext::Telemetry::TAG_PROVIDER => test_session.ci_provider || Ext::Telemetry::Provider::UNSUPPORTED
}
)
end
Expand Down
24 changes: 21 additions & 3 deletions lib/datadog/ci/test_visibility/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require "datadog/core/environment/identity"

require_relative "serializers/factories/test_level"
require_relative "../ext/app_types"
require_relative "../ext/telemetry"
require_relative "../ext/transport"
require_relative "../transport/event_platform_transport"
Expand Down Expand Up @@ -51,7 +52,12 @@ def encode_events(traces)
end

def encode_span(trace, span)
serializer = serializers_factory.serializer(trace, span, options: {itr_correlation_id: itr&.correlation_id})
serializer = serializers_factory.serializer(
trace,
span,
options: {itr_correlation_id: test_optimisation&.correlation_id}
)

if serializer.valid?
encoded = encoder.encode(serializer)
return nil if event_too_large?(span, encoded)
Expand All @@ -75,7 +81,7 @@ def write_payload_header(packer)
packer.write(1)

packer.write("metadata")
packer.write_map_header(1)
packer.write_map_header(1 + Ext::AppTypes::CI_SPAN_TYPES.size)

packer.write("*")
metadata_fields_count = dd_env ? 4 : 3
Expand All @@ -95,12 +101,24 @@ def write_payload_header(packer)
packer.write("library_version")
packer.write(Datadog::CI::VERSION::STRING)

Ext::AppTypes::CI_SPAN_TYPES.each do |ci_span_type|
packer.write(ci_span_type)
packer.write_map_header(1)

packer.write(Ext::Test::METADATA_TAG_TEST_SESSION_NAME)
packer.write(test_visibility&.logical_test_session_name)
end

packer.write("events")
end

def itr
def test_optimisation
@test_optimisation ||= Datadog::CI.send(:test_optimisation)
end

def test_visibility
@test_visibility ||= Datadog::CI.send(:test_visibility)
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions sig/datadog/ci/ext/settings.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ module Datadog
ENV_RETRY_FAILED_TESTS_MAX_ATTEMPTS: String
ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT: String
ENV_RETRY_NEW_TESTS_ENABLED: String
ENV_TEST_SESSION_NAME: String

DD_SITE_ALLOWLIST: Array[String]
end
Expand Down
2 changes: 2 additions & 0 deletions sig/datadog/ci/ext/test.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ module Datadog

EARLY_FLAKE_FAULTY: "faulty"

METADATA_TAG_TEST_SESSION_NAME: "test_session.name"

module Status
PASS: "pass"

Expand Down
6 changes: 6 additions & 0 deletions sig/datadog/ci/test_session.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ module Datadog
@inheritable_tags: Hash[untyped, untyped]

def inheritable_tags: () -> Hash[untyped, untyped]

def test_command: () -> String?

def ci_provider: () -> String?

def ci_job_name: () -> String?
end
end
end
6 changes: 5 additions & 1 deletion sig/datadog/ci/test_visibility/component.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ module Datadog

attr_reader test_suite_level_visibility_enabled: bool

def initialize: (?test_suite_level_visibility_enabled: bool, ?codeowners: Datadog::CI::Codeowners::Matcher) -> void
attr_reader logical_test_session_name: String?

def initialize: (?test_suite_level_visibility_enabled: bool, ?codeowners: Datadog::CI::Codeowners::Matcher, ?logical_test_session_name: String?) -> void

def trace_test: (String span_name, String test_suite_name, ?service: String?, ?tags: Hash[untyped, untyped]) ?{ (Datadog::CI::Test span) -> untyped } -> untyped

Expand Down Expand Up @@ -77,6 +79,8 @@ module Datadog

def subscribe_to_after_stop_event: (Datadog::Tracing::SpanOperation span) -> void

def override_logical_test_session_name!: (Datadog::CI::TestSession test_session) -> void

def test_optimisation: () -> Datadog::CI::TestOptimisation::Component

def test_retries: () -> Datadog::CI::TestRetries::Component
Expand Down
5 changes: 4 additions & 1 deletion sig/datadog/ci/test_visibility/transport.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ module Datadog

@dd_env: String?
@serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel) | singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestSuiteLevel)

@test_optimisation: Datadog::CI::TestOptimisation::Component?
@test_visibility: Datadog::CI::TestVisibility::Component?

def initialize: (
api: Datadog::CI::Transport::Api::Base,
Expand All @@ -21,7 +23,8 @@ module Datadog
def send_payload: (String encoded_payload) -> Datadog::CI::Transport::Adapters::Net::Response
def encode_events: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[String]
def encode_span: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> String?
def itr: () -> Datadog::CI::TestOptimisation::Component?
def test_optimisation: () -> Datadog::CI::TestOptimisation::Component?
def test_visibility: () -> Datadog::CI::TestVisibility::Component?
end
end
end
Expand Down
37 changes: 36 additions & 1 deletion spec/datadog/ci/configuration/settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,41 @@ def patcher
end
end

describe "#test_session_name" do
subject(:test_session_name) { settings.ci.test_session_name }

it { is_expected.to be nil }

context "when #{Datadog::CI::Ext::Settings::ENV_TEST_SESSION_NAME}" do
around do |example|
ClimateControl.modify(Datadog::CI::Ext::Settings::ENV_TEST_SESSION_NAME => test_session_name) do
example.run
end
end

context "is not defined" do
let(:test_session_name) { nil }

it { is_expected.to be nil }
end

context "is set to some value" do
let(:test_session_name) { "knapsack-pro-circle-ci-runner-1" }

it { is_expected.to eq test_session_name }
end
end
end

describe "#test_session_name=" do
it "updates the #test_session_name setting" do
expect { settings.ci.test_session_name = "rspec" }
.to change { settings.ci.test_session_name }
.from(nil)
.to("rspec")
end
end

describe "#agentless_mode_enabled" do
subject(:agentless_mode_enabled) { settings.ci.agentless_mode_enabled }

Expand Down Expand Up @@ -166,7 +201,7 @@ def patcher
end

describe "#agentless_url=" do
it "updates the #enabled setting" do
it "updates the #agentless_url setting" do
expect { settings.ci.agentless_url = "example.com" }
.to change { settings.ci.agentless_url }
.from(nil)
Expand Down
30 changes: 30 additions & 0 deletions spec/datadog/ci/test_session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,36 @@
it { is_expected.to eq("test command") }
end

describe "#test_command" do
subject(:test_command) { ci_test_session.test_command }

before do
tracer_span.set_tag(Datadog::CI::Ext::Test::TAG_COMMAND, "test command")
end

it { is_expected.to eq("test command") }
end

describe "#ci_provider" do
subject(:ci_provider) { ci_test_session.ci_provider }

before do
tracer_span.set_tag(Datadog::CI::Ext::Environment::TAG_PROVIDER_NAME, "ci provider")
end

it { is_expected.to eq("ci provider") }
end

describe "#ci_job_name" do
subject(:ci_job_name) { ci_test_session.ci_job_name }

before do
tracer_span.set_tag(Datadog::CI::Ext::Environment::TAG_JOB_NAME, "ci job name")
end

it { is_expected.to eq("ci job name") }
end

describe "#skipping_tests?" do
subject(:skipping_tests?) { ci_test_session.skipping_tests? }

Expand Down
36 changes: 36 additions & 0 deletions spec/datadog/ci/test_visibility/component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,42 @@
end
end

context "with logical test session name set" do
let(:logical_test_session_name) { "my-logical-test-session" }

it "sets the logical test session name" do
subject

expect(test_visibility.logical_test_session_name).to eq(logical_test_session_name)
end
end

context "without logical test session name set" do
before do
allow_any_instance_of(Datadog::CI::TestSession).to receive(:ci_job_name).and_return(ci_job_name)
end

context "without CI job name available" do
let(:ci_job_name) { nil }

it "uses the test command" do
subject

expect(test_visibility.logical_test_session_name).to eq(test_command)
end
end

context "with CI job name available" do
let(:ci_job_name) { "my-ci-job" }

it "uses the CI job name and test command" do
subject

expect(test_visibility.logical_test_session_name).to eq("#{ci_job_name}-#{test_command}")
end
end
end

it_behaves_like "span with environment tags"
it_behaves_like "span with default tags"
it_behaves_like "span with runtime tags"
Expand Down
Loading

0 comments on commit b8f49d9

Please sign in to comment.