From de33d477fdf369b2005dbe0c1c7fc5fc4812f001 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 24 Apr 2024 10:54:33 +0200 Subject: [PATCH 1/3] Test visibility serializer factory and serializers accept options hash that will be used for storing ITR correlation id --- .../ci/test_visibility/serializers/base.rb | 5 +- .../serializers/factories/test_level.rb | 6 +- .../serializers/factories/test_suite_level.rb | 12 ++-- .../ci/test_visibility/serializers/base.rbs | 14 +++-- .../serializers/factories/test_level.rbs | 2 +- .../factories/test_suite_level.rbs | 2 +- .../factories/test_suite_level_spec.rb | 59 +++++++++++-------- 7 files changed, 60 insertions(+), 40 deletions(-) diff --git a/lib/datadog/ci/test_visibility/serializers/base.rb b/lib/datadog/ci/test_visibility/serializers/base.rb index b32ddc26..24fe9777 100644 --- a/lib/datadog/ci/test_visibility/serializers/base.rb +++ b/lib/datadog/ci/test_visibility/serializers/base.rb @@ -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) } diff --git a/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb b/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb index aca2bdb3..30309d78 100644 --- a/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb +++ b/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb @@ -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 diff --git a/lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb b/lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb index f6f4c181..f03f0a1b 100644 --- a/lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb +++ b/lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb @@ -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 diff --git a/sig/datadog/ci/test_visibility/serializers/base.rbs b/sig/datadog/ci/test_visibility/serializers/base.rbs index a6281b0b..d5a76e41 100644 --- a/sig/datadog/ci/test_visibility/serializers/base.rbs +++ b/sig/datadog/ci/test_visibility/serializers/base.rbs @@ -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 diff --git a/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs b/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs index ac7b6c13..4cebc8e4 100644 --- a/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs +++ b/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs @@ -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 diff --git a/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs b/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs index 8ebc424f..af2dbc06 100644 --- a/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs +++ b/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs @@ -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 diff --git a/spec/datadog/ci/test_visibility/serializers/factories/test_suite_level_spec.rb b/spec/datadog/ci/test_visibility/serializers/factories/test_suite_level_spec.rb index c2ab81e9..42d155be 100644 --- a/spec/datadog/ci/test_visibility/serializers/factories/test_suite_level_spec.rb +++ b/spec/datadog/ci/test_visibility/serializers/factories/test_suite_level_spec.rb @@ -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 From 5f01d0fe47a3bf7b0aefc76338f28017d6b8d684 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 24 Apr 2024 11:27:17 +0200 Subject: [PATCH 2/3] Test visibility transport passes ITR correlation ID to serializers --- lib/datadog/ci/test_visibility/transport.rb | 6 +++++- sig/datadog/ci/itr/runner.rbs | 8 ++++++-- sig/datadog/ci/test_visibility/transport.rbs | 2 ++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/datadog/ci/test_visibility/transport.rb b/lib/datadog/ci/test_visibility/transport.rb index 4116d513..ace6870d 100644 --- a/lib/datadog/ci/test_visibility/transport.rb +++ b/lib/datadog/ci/test_visibility/transport.rb @@ -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) @@ -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 diff --git a/sig/datadog/ci/itr/runner.rbs b/sig/datadog/ci/itr/runner.rbs index abc0720e..eaecd27b 100644 --- a/sig/datadog/ci/itr/runner.rbs +++ b/sig/datadog/ci/itr/runner.rbs @@ -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? @@ -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 diff --git a/sig/datadog/ci/test_visibility/transport.rbs b/sig/datadog/ci/test_visibility/transport.rbs index 77ec7a0b..ee7e0f79 100644 --- a/sig/datadog/ci/test_visibility/transport.rbs +++ b/sig/datadog/ci/test_visibility/transport.rbs @@ -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, @@ -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 From f8d1a7cf96ae9bbc5d4795b9e0c253f1f90f9a6c Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 24 Apr 2024 12:44:58 +0200 Subject: [PATCH 3/3] send itr_correlation_id in the content of test event payload --- .../ci/test_visibility/serializers/test_v2.rb | 16 +++++++++++-- .../test_visibility/serializers/test_v2.rbs | 6 +++++ .../serializers/test_v2_spec.rb | 15 +++++++++++- .../ci/test_visibility/transport_spec.rb | 24 +++++++++++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/lib/datadog/ci/test_visibility/serializers/test_v2.rb b/lib/datadog/ci/test_visibility/serializers/test_v2.rb index 4380fb57..ec026964 100644 --- a/lib/datadog/ci/test_visibility/serializers/test_v2.rb +++ b/lib/datadog/ci/test_visibility/serializers/test_v2.rb @@ -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 diff --git a/sig/datadog/ci/test_visibility/serializers/test_v2.rbs b/sig/datadog/ci/test_visibility/serializers/test_v2.rbs index 1ba034be..62712e96 100644 --- a/sig/datadog/ci/test_visibility/serializers/test_v2.rbs +++ b/sig/datadog/ci/test_visibility/serializers/test_v2.rbs @@ -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]] @@ -15,6 +19,8 @@ module Datadog def version: () -> 2 + def itr_correlation_id: () -> String? + private def required_fields: () -> Array[String] diff --git a/spec/datadog/ci/test_visibility/serializers/test_v2_spec.rb b/spec/datadog/ci/test_visibility/serializers/test_v2_spec.rb index f25e1621..1491a250 100644 --- a/spec/datadog/ci/test_visibility/serializers/test_v2_spec.rb +++ b/spec/datadog/ci/test_visibility/serializers/test_v2_spec.rb @@ -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 @@ -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 diff --git a/spec/datadog/ci/test_visibility/transport_spec.rb b/spec/datadog/ci/test_visibility/transport_spec.rb index d30bad37..2ef48da8 100644 --- a/spec/datadog/ci/test_visibility/transport_spec.rb +++ b/spec/datadog/ci/test_visibility/transport_spec.rb @@ -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 }