Skip to content

Commit

Permalink
Merge pull request #165 from DataDog/anmarchenko/itr_correlation_id
Browse files Browse the repository at this point in the history
[CIVIS-9014] implement "why this test was skipped" feature by adding ITR correlation to test events
  • Loading branch information
anmarchenko authored Apr 24, 2024
2 parents d0cfdc9 + f8d1a7c commit f0592d1
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 46 deletions.
5 changes: 3 additions & 2 deletions lib/datadog/ci/test_visibility/serializers/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ class Base
"duration"
].freeze

attr_reader :trace, :span, :meta
attr_reader :trace, :span, :meta, :options

def initialize(trace, span)
def initialize(trace, span, options: {})
@trace = trace
@span = span
@options = options

@meta = @span.meta.reject { |key, _| Ext::Test::TRANSIENT_TAGS.include?(key) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ module Factories
module TestLevel
module_function

def serializer(trace, span)
def serializer(trace, span, options: {})
case span.type
when Datadog::CI::Ext::AppTypes::TYPE_TEST
Serializers::TestV1.new(trace, span)
Serializers::TestV1.new(trace, span, options: options)
else
Serializers::Span.new(trace, span)
Serializers::Span.new(trace, span, options: options)
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ module Factories
module TestSuiteLevel
module_function

def serializer(trace, span)
def serializer(trace, span, options: {})
case span.type
when Datadog::CI::Ext::AppTypes::TYPE_TEST
Serializers::TestV2.new(trace, span)
Serializers::TestV2.new(trace, span, options: options)
when Datadog::CI::Ext::AppTypes::TYPE_TEST_SESSION
Serializers::TestSession.new(trace, span)
Serializers::TestSession.new(trace, span, options: options)
when Datadog::CI::Ext::AppTypes::TYPE_TEST_MODULE
Serializers::TestModule.new(trace, span)
Serializers::TestModule.new(trace, span, options: options)
when Datadog::CI::Ext::AppTypes::TYPE_TEST_SUITE
Serializers::TestSuite.new(trace, span)
Serializers::TestSuite.new(trace, span, options: options)
else
Serializers::Span.new(trace, span)
Serializers::Span.new(trace, span, options: options)
end
end
end
Expand Down
16 changes: 14 additions & 2 deletions lib/datadog/ci/test_visibility/serializers/test_v2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,34 @@ module Serializers
class TestV2 < TestV1
CONTENT_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + TestV1::CONTENT_FIELDS).freeze

CONTENT_FIELDS_WITH_ITR_CORRELATION_ID = (CONTENT_FIELDS + ["itr_correlation_id"]).freeze

CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)

CONTENT_MAP_SIZE_WITH_ITR_CORRELATION_ID = calculate_content_map_size(CONTENT_FIELDS_WITH_ITR_CORRELATION_ID)

REQUIRED_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + TestV1::REQUIRED_FIELDS).freeze

def content_fields
CONTENT_FIELDS
return CONTENT_FIELDS if itr_correlation_id.nil?

CONTENT_FIELDS_WITH_ITR_CORRELATION_ID
end

def content_map_size
CONTENT_MAP_SIZE
return CONTENT_MAP_SIZE if itr_correlation_id.nil?

CONTENT_MAP_SIZE_WITH_ITR_CORRELATION_ID
end

def version
2
end

def itr_correlation_id
options[:itr_correlation_id]
end

private

def required_fields
Expand Down
6 changes: 5 additions & 1 deletion lib/datadog/ci/test_visibility/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def encode_events(traces)
end

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

if serializer.valid?
encoded = encoder.encode(serializer)
Expand Down Expand Up @@ -98,6 +98,10 @@ def write_payload_header(packer)

packer.write("events")
end

def itr
@itr ||= Datadog::CI.send(:itr_runner)
end
end
end
end
Expand Down
8 changes: 6 additions & 2 deletions sig/datadog/ci/itr/runner.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module Datadog
@enabled: bool
@test_skipping_enabled: bool
@code_coverage_enabled: bool
@correlation_id: String
@skippable_tests: Array[String]
@correlation_id: String?
@skippable_tests: Set[String]
@coverage_writer: Datadog::CI::ITR::Coverage::Writer?

@api: Datadog::CI::Transport::Api::Base?
Expand All @@ -17,6 +17,10 @@ module Datadog
@skipped_tests_count: Integer
@mutex: Thread::Mutex

attr_reader skippable_tests: Set[String]
attr_reader skipped_tests_count: Integer
attr_reader correlation_id: String?

def initialize: (dd_env: String?, ?enabled: bool, coverage_writer: Datadog::CI::ITR::Coverage::Writer?, api: Datadog::CI::Transport::Api::Base?) -> void

def configure: (Hash[String, untyped] remote_configuration, test_session: Datadog::CI::TestSession, git_tree_upload_worker: Datadog::CI::Worker) -> void
Expand Down
14 changes: 10 additions & 4 deletions sig/datadog/ci/test_visibility/serializers/base.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,24 @@ module Datadog
CONTENT_FIELDS: Array[String | Hash[String, String]]
REQUIRED_FIELDS: Array[String]

@content_fields_count: Integer
@start: Integer
@duration: Integer
@trace: Datadog::Tracing::TraceSegment
@span: Datadog::Tracing::Span
@options: Hash[Symbol, untyped]

@meta: Hash[untyped, untyped]
@errors: Hash[String, Set[String]]
@validated: bool

@content_fields_count: Integer
@start: Integer
@duration: Integer

attr_reader trace: Datadog::Tracing::TraceSegment
attr_reader span: Datadog::Tracing::Span
attr_reader meta: Hash[untyped, untyped]
attr_reader options: Hash[Symbol, untyped]

def initialize: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> void
def initialize: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span, ?options: Hash[Symbol, untyped]) -> void

def to_msgpack: (?untyped? packer) -> untyped

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Datadog
module Serializers
module Factories
module TestLevel
def self?.serializer: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> Datadog::CI::TestVisibility::Serializers::Base
def self?.serializer: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span, ?options: Hash[Symbol, untyped]) -> Datadog::CI::TestVisibility::Serializers::Base
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Datadog
module Serializers
module Factories
module TestSuiteLevel
def self?.serializer: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> Datadog::CI::TestVisibility::Serializers::Base
def self?.serializer: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span, ?options: Hash[Symbol, untyped]) -> Datadog::CI::TestVisibility::Serializers::Base
end
end
end
Expand Down
6 changes: 6 additions & 0 deletions sig/datadog/ci/test_visibility/serializers/test_v2.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ module Datadog
class TestV2 < TestV1
CONTENT_FIELDS: ::Array[String | ::Hash[::String, String]]

CONTENT_FIELDS_WITH_ITR_CORRELATION_ID: ::Array[String | ::Hash[::String, String]]

CONTENT_MAP_SIZE: Integer

CONTENT_MAP_SIZE_WITH_ITR_CORRELATION_ID: Integer

REQUIRED_FIELDS: ::Array[String]

def content_fields: () -> ::Array[String | ::Hash[::String, String]]
Expand All @@ -15,6 +19,8 @@ module Datadog

def version: () -> 2

def itr_correlation_id: () -> String?

private

def required_fields: () -> Array[String]
Expand Down
2 changes: 2 additions & 0 deletions sig/datadog/ci/test_visibility/transport.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Datadog

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

def initialize: (
api: Datadog::CI::Transport::Api::Base,
Expand All @@ -20,6 +21,7 @@ module Datadog
def send_payload: (String encoded_payload) -> Datadog::CI::Transport::HTTP::ResponseDecorator
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::ITR::Runner?
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,45 @@
produce_test_session_trace(with_http_span: true)
end

subject { described_class.serializer(trace_for_span(ci_span), ci_span) }

describe ".convert_trace_to_serializable_events" do
context "with a session span" do
let(:ci_span) { test_session_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestSession) }
end

context "with a module span" do
let(:ci_span) { test_module_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestModule) }
end

context "with a suite span" do
let(:ci_span) { first_test_suite_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestSuite) }
context "without options" do
subject { described_class.serializer(trace_for_span(ci_span), ci_span) }

describe ".convert_trace_to_serializable_events" do
context "with a session span" do
let(:ci_span) { test_session_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestSession) }
end

context "with a module span" do
let(:ci_span) { test_module_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestModule) }
end

context "with a suite span" do
let(:ci_span) { first_test_suite_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestSuite) }
end

context "with a test span" do
let(:ci_span) { first_test_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestV2) }
end

context "with a http request span" do
let(:ci_span) { first_custom_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::Span) }
end
end
end

context "with a test span" do
let(:ci_span) { first_test_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::TestV2) }
end
context "with options" do
let(:ci_span) { first_test_span }
subject { described_class.serializer(trace_for_span(ci_span), ci_span, options: {custom: "option"}) }

context "with a http request span" do
let(:ci_span) { first_custom_span }
it { is_expected.to be_kind_of(Datadog::CI::TestVisibility::Serializers::Span) }
describe ".serializer" do
it "passes options to the serializer" do
expect(subject.options).to eq({custom: "option"})
end
end
end
end
15 changes: 14 additions & 1 deletion spec/datadog/ci/test_visibility/serializers/test_v2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
let(:integration_name) { :rspec }
end

let(:options) { {} }
include_context "msgpack serializer" do
subject { described_class.new(trace_for_span(first_test_span), first_test_span) }
subject { described_class.new(trace_for_span(first_test_span), first_test_span, options: options) }
end

describe "#to_msgpack" do
Expand Down Expand Up @@ -110,6 +111,18 @@
})
end
end

context "with itr correlation id" do
let(:options) { {itr_correlation_id: "itr-correlation-id"} }

before do
produce_test_session_trace
end

it "correctly serializes itr correlation id" do
expect(content).to include("itr_correlation_id" => "itr-correlation-id")
end
end
end

describe "#valid?" do
Expand Down
24 changes: 24 additions & 0 deletions spec/datadog/ci/test_visibility/transport_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,30 @@
end
end

context "with itr correlation id" do
let(:serializers_factory) { Datadog::CI::TestVisibility::Serializers::Factories::TestSuiteLevel }

before do
allow_any_instance_of(Datadog::CI::ITR::Runner).to receive(:correlation_id).and_return("correlation-id")

produce_test_session_trace
end

it "passes itr correlation id to serializer" do
subject.send_events([trace_for_span(first_test_span)])

expect(api).to have_received(:citestcycle_request) do |args|
payload = MessagePack.unpack(args[:payload])
expect(payload["version"]).to eq(1)

events = payload["events"]
expect(events.count).to eq(1)
expect(events.first["content"]["resource"]).to include("calculator_tests")
expect(events.first["content"]["itr_correlation_id"]).to eq("correlation-id")
end
end
end

context "multiple traces with 2 spans each" do
let(:traces_count) { 2 }
let(:expected_events_count) { 4 }
Expand Down

0 comments on commit f0592d1

Please sign in to comment.