Skip to content

Commit

Permalink
Merge pull request #180 from DataDog/anmarchenko/knapsack_pro_integra…
Browse files Browse the repository at this point in the history
…tion

[CIVIS-10061] Fix Knapsack Pro integration
  • Loading branch information
anmarchenko authored May 22, 2024
2 parents 80e7b13 + 85152a2 commit 1d12868
Show file tree
Hide file tree
Showing 17 changed files with 189 additions and 12 deletions.
8 changes: 6 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ TEST_METADATA = {
"minitest-5-shoulda-context-2-shoulda-matchers-6" => "❌ 2.7 / ❌ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby"
},
"knapsack_rspec" => {
"knapsack_pro-7-rspec-3" => "✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ✅ jruby"
"knapsack_pro-7-rspec-3" => "✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ❌ jruby"
},
"knapsack_rspec_go" => {
"knapsack_pro-7-rspec-3" => "✅ 2.7 / ✅ 3.0 / ✅ 3.1 / ✅ 3.2 / ✅ 3.3 / ❌ jruby"
}
}

Expand Down Expand Up @@ -132,7 +135,8 @@ namespace :spec do
:activesupport,
:ci_queue_minitest,
:ci_queue_rspec,
:knapsack_rspec
:knapsack_rspec,
:knapsack_rspec_go
].each do |contrib|
desc "" # "Explicitly hiding from `rake -T`"
RSpec::Core::RakeTask.new(contrib) do |t, args|
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/ci/contrib/rspec/example.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def self.included(base)

module InstanceMethods
def run(*)
return super if ::RSpec.configuration.dry_run?
return super unless datadog_configuration[:enabled]

test_name = full_description.strip
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 @@ -16,6 +16,7 @@ def self.included(base)
# Instance methods for configuration
module ClassMethods
def run(reporter = ::RSpec::Core::NullReporter)
return super if ::RSpec.configuration.dry_run?
return super unless datadog_configuration[:enabled]
return super unless top_level?

Expand Down
1 change: 0 additions & 1 deletion lib/datadog/ci/contrib/rspec/knapsack_pro/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ module Datadog
module CI
module Contrib
module RSpec
# Instrument RSpec::Core::Example
module KnapsackPro
module Extension
def self.included(base)
Expand Down
26 changes: 26 additions & 0 deletions lib/datadog/ci/contrib/rspec/knapsack_pro/patcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module Datadog
module CI
module Contrib
module RSpec
module KnapsackPro
module Patcher
def self.patch
if defined?(::KnapsackPro::Extensions::RSpecExtension::Runner) &&
::RSpec::Core::Runner.ancestors.include?(::KnapsackPro::Extensions::RSpecExtension::Runner)
# knapsack already patched rspec runner
require_relative "runner"
::RSpec::Core::Runner.include(KnapsackPro::Runner)
else
# knapsack didn't patch rspec runner yet
require_relative "extension"
::KnapsackPro::Extensions::RSpecExtension.include(KnapsackPro::Extension)
end
end
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/datadog/ci/contrib/rspec/knapsack_pro/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def self.included(base)

module InstanceMethods
def knapsack__run_specs(*)
return super if ::RSpec.configuration.dry_run?
return super unless datadog_configuration[:enabled]

test_session = CI.start_test_session(
Expand Down
10 changes: 6 additions & 4 deletions lib/datadog/ci/contrib/rspec/patcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ def patch
::RSpec::Queue::Runner.include(Runner)
end

# Knapsack Pro test runner instrumentation
# https://github.com/KnapsackPro/knapsack_pro-ruby
if knapsack_pro?
require_relative "knapsack_pro/extension"
::KnapsackPro::Extensions::RSpecExtension.include(KnapsackPro::Extension)
# Knapsack Pro test runner instrumentation
# https://github.com/KnapsackPro/knapsack_pro-ruby
require_relative "knapsack_pro/patcher"
Datadog::CI::Contrib::RSpec::KnapsackPro::Patcher.patch
end

# default rspec test runner instrumentation
::RSpec::Core::Runner.include(Runner)

::RSpec::Core::Example.include(Example)
::RSpec::Core::ExampleGroup.include(ExampleGroup)
end
Expand Down
1 change: 1 addition & 0 deletions lib/datadog/ci/contrib/rspec/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def self.included(base)

module InstanceMethods
def run_specs(*)
return super if ::RSpec.configuration.dry_run?
return super unless datadog_configuration[:enabled]

test_session = CI.start_test_session(
Expand Down
13 changes: 13 additions & 0 deletions sig/datadog/ci/contrib/rspec/knapsack_pro/patcher.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Datadog
module CI
module Contrib
module RSpec
module KnapsackPro
module Patcher
def self.patch: () -> void
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
require "fileutils"

RSpec.describe "RSpec instrumentation with Knapsack Pro runner in queue mode" do
before { skip("jruby fails on file with emojis in name") if PlatformHelpers.jruby? }

include_context "CI mode activated" do
let(:integration_name) { :rspec }
end
Expand Down
79 changes: 79 additions & 0 deletions spec/datadog/ci/contrib/knapsack_rspec_go/instrumentation_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require "knapsack_pro"
require "fileutils"

RSpec.describe "Knapsack Pro runner when Datadog::CI is configured during the knapsack run like in rspec_go rake task" do
# Yields to a block in a new RSpec global context. All RSpec
# test configuration and execution should be wrapped in this method.
def with_new_rspec_environment
old_configuration = ::RSpec.configuration
old_world = ::RSpec.world
::RSpec.configuration = ::RSpec::Core::Configuration.new
::RSpec.world = ::RSpec::Core::World.new

yield
ensure
::RSpec.configuration = old_configuration
::RSpec.world = old_world
end

def devnull
File.new("/dev/null", "w")
end

before do
allow_any_instance_of(Datadog::Core::Remote::Negotiation).to(
receive(:endpoint?).with("/evp_proxy/v4/").and_return(true)
)

allow(Datadog::CI::Utils::TestRun).to receive(:command).and_return("knapsack:queue:rspec")

allow_any_instance_of(KnapsackPro::Runners::Queue::RSpecRunner).to receive(:test_file_paths).and_return(
["./spec/datadog/ci/contrib/knapsack_rspec_go/suite_under_test/some_test_rspec.rb"],
[]
)
end

it "instruments this rspec session" do
with_new_rspec_environment do
ClimateControl.modify(
"KNAPSACK_PRO_CI_NODE_BUILD_ID" => "144",
"KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC" => "example_token",
"KNAPSACK_PRO_FIXED_QUEUE_SPLIT" => "true",
"KNAPSACK_PRO_QUEUE_ID" => nil
) do
KnapsackPro::Adapters::RSpecAdapter.bind
KnapsackPro::Runners::Queue::RSpecRunner.run("--require knapsack_helper", devnull, devnull)
rescue ArgumentError
# suppress invalid API key error
end
end

# test session and module traced
expect(test_session_span).not_to be_nil
expect(test_module_span).not_to be_nil

# test session and module are failed
expect([test_session_span, test_module_span]).to all have_fail_status

# single test suite span
expect(test_suite_spans).to have(1).item
expect(test_suite_spans.first).to have_test_tag(:status, Datadog::CI::Ext::Test::Status::FAIL)
expect(test_suite_spans.first).to have_test_tag(
:suite,
"SomeTest at ./spec/datadog/ci/contrib/knapsack_rspec_go/suite_under_test/some_test_rspec.rb"
)

# there is test span for every test case
expect(test_spans).to have(2).items
# test spans belong to a single test suite
expect(test_spans).to have_unique_tag_values_count(:test_suite_id, 1)
expect(test_spans).to have_tag_values_no_order(
:status,
[Datadog::CI::Ext::Test::Status::FAIL, Datadog::CI::Ext::Test::Status::PASS]
)

# every test span is connected to test module and test session
expect(test_spans).to all have_test_tag(:test_module_id)
expect(test_spans).to all have_test_tag(:test_session_id)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
require "rspec"

RSpec.describe "SomeTest" do
context "nested" do
it "foo" do
# DO NOTHING
end

it "fails" do
expect(1).to eq(2)
end
end
end
25 changes: 22 additions & 3 deletions spec/datadog/ci/contrib/rspec/instrumentation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def rspec_session_run(
test: false,
context: false,
suite: false
}
},
dry_run: false
)
test_meta = unskippable[:test] ? {Datadog::CI::Ext::Test::ITR_UNSKIPPABLE_OPTION => true} : {}
context_meta = unskippable[:context] ? {Datadog::CI::Ext::Test::ITR_UNSKIPPABLE_OPTION => true} : {}
Expand Down Expand Up @@ -58,7 +59,11 @@ def rspec_session_run(
end
end

options = ::RSpec::Core::ConfigurationOptions.new(%w[--pattern none])
options_array = %w[--pattern none]
if dry_run
options_array << "--dry-run"
end
options = ::RSpec::Core::ConfigurationOptions.new(options_array)
::RSpec::Core::Runner.new(options).run(devnull, devnull)

spec
Expand Down Expand Up @@ -104,7 +109,7 @@ def rspec_session_run(
:source_file,
"spec/datadog/ci/contrib/rspec/instrumentation_spec.rb"
)
expect(first_test_span).to have_test_tag(:source_start, "77")
expect(first_test_span).to have_test_tag(:source_start, "82")
expect(first_test_span).to have_test_tag(
:codeowners,
"[\"@DataDog/ruby-guild\", \"@DataDog/ci-app-libraries\"]"
Expand Down Expand Up @@ -773,4 +778,18 @@ def rspec_skipped_session_run
end
end
end

context "with dry run" do
include_context "CI mode activated" do
let(:integration_name) { :rspec }
let(:integration_options) { {service_name: "lspec"} }
end

it "does not instrument test session" do
rspec_session_run(dry_run: true)

expect(test_session_span).to be_nil
expect(test_spans).to be_empty
end
end
end
8 changes: 8 additions & 0 deletions spec/knapsack_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# this file is required for knapsack unit tests

Datadog.configure do |c|
c.service = "knapsack_rspec_example"
c.ci.enabled = true
c.ci.git_metadata_upload_enabled = false
c.ci.instrument :rspec
end
4 changes: 4 additions & 0 deletions spec/support/contexts/ci_mode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,9 @@

Datadog::CI.send(:itr_runner)&.shutdown!
Datadog::CI.send(:recorder)&.shutdown!

Datadog.configure do |c|
c.ci.enabled = false
end
end
end
3 changes: 3 additions & 0 deletions vendor/rbs/knapsack_pro/0/knapsack_pro.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ module KnapsackPro
module Extensions
module RSpecExtension
def setup!: () -> void

module Runner
end
end
end
end
5 changes: 5 additions & 0 deletions vendor/rbs/rspec/0/rspec.rbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module RSpec
def self.configuration: () -> RSpec::Core::Configuration
end

module RSpec::Core
Expand Down Expand Up @@ -36,3 +37,7 @@ end

class RSpec::Core::NullReporter
end

class RSpec::Core::Configuration
def dry_run?: () -> bool
end

0 comments on commit 1d12868

Please sign in to comment.