diff --git a/lib/buildkite/test_collector/cucumber_plugin/trace.rb b/lib/buildkite/test_collector/cucumber_plugin/trace.rb index d3c54eb..a3d13ea 100644 --- a/lib/buildkite/test_collector/cucumber_plugin/trace.rb +++ b/lib/buildkite/test_collector/cucumber_plugin/trace.rb @@ -2,28 +2,33 @@ module Buildkite::TestCollector::CucumberPlugin class Trace < Buildkite::TestCollector::Trace - attr_accessor :scenario, :failure_reason, :failure_expanded + attr_accessor :failure_reason, :failure_expanded attr_reader :history, :tags, :location_prefix FILE_PATH_REGEX = /^(.*?\.(rb|feature))/ def initialize(scenario, history:, failure_reason: nil, failure_expanded: [], tags: nil, location_prefix: nil) - @scenario = scenario @history = history @failure_reason = failure_reason @failure_expanded = failure_expanded @tags = tags @location_prefix = location_prefix + + # Extract all data eagerly to allow GC of the scenario object + @result = if scenario.passed? + 'passed' + elsif scenario.failed? + 'failed' + else + 'skipped' + end + @name = scenario.name + @location = scenario.location&.to_s + @file_name = @location&.to_s[FILE_PATH_REGEX] end def result - if scenario.passed? - 'passed' - elsif scenario.failed? - 'failed' - else - 'skipped' - end + @result end private @@ -41,15 +46,15 @@ def scope end def name - scenario.name + @name end def location - scenario.location&.to_s + @location end def file_name - @file_name ||= location&.to_s[FILE_PATH_REGEX] + @file_name end end end diff --git a/lib/buildkite/test_collector/minitest_plugin/reporter.rb b/lib/buildkite/test_collector/minitest_plugin/reporter.rb index d0f11ad..6abac2c 100644 --- a/lib/buildkite/test_collector/minitest_plugin/reporter.rb +++ b/lib/buildkite/test_collector/minitest_plugin/reporter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Buildkite::TestCollector::MinitestPlugin - class Reporter < Minitest::StatisticsReporter + class Reporter < Minitest::Reporter def initialize(io, options) super @io = io diff --git a/lib/buildkite/test_collector/minitest_plugin/trace.rb b/lib/buildkite/test_collector/minitest_plugin/trace.rb index b895627..0f5d93c 100644 --- a/lib/buildkite/test_collector/minitest_plugin/trace.rb +++ b/lib/buildkite/test_collector/minitest_plugin/trace.rb @@ -2,8 +2,6 @@ module Buildkite::TestCollector::MinitestPlugin class Trace < Buildkite::TestCollector::Trace - attr_accessor :example - attr_writer :failure_reason, :failure_expanded attr_reader :history attr_reader :location_prefix attr_reader :tags @@ -18,28 +16,45 @@ class Trace < Buildkite::TestCollector::Trace FILE_PATH_REGEX = /^(.*?\.(rb|feature))/ def initialize(example, history:, tags: nil, trace: nil, location_prefix: nil) - @example = example @history = history @tags = tags @location_prefix = location_prefix + + # Extract all data eagerly to allow GC of the test object + @source_location = example.method(example.name).source_location + @result = RESULT_CODES[example.result_code] + @scope = example.class.name + @name = example.name + @failure_reason = strip_invalid_utf8_chars(example.failure&.message)&.split("\n")&.first + @failure_expanded = example.failures.map.with_index do |failure, index| + # remove the first line of message from the first failure + # to avoid duplicate line in Test Analytics UI + messages = strip_invalid_utf8_chars(failure.message).split("\n") + messages = messages[1..-1] if index.zero? + + { + expanded: messages, + backtrace: failure.backtrace + } + end end def result - RESULT_CODES[example.result_code] + @result end def source_location - @source_location ||= example.method(example.name).source_location + @source_location end private def scope - example.class.name + @scope end def name - example.name + @name end def location @@ -65,21 +80,11 @@ def project_dir end def failure_reason - @failure_reason ||= strip_invalid_utf8_chars(example.failure&.message)&.split("\n")&.first + @failure_reason end def failure_expanded - @failure_expanded ||= example.failures.map.with_index do |failure, index| - # remove the first line of message from the first failure - # to avoid duplicate line in Test Analytics UI - messages = strip_invalid_utf8_chars(failure.message).split("\n") - messages = messages[1..-1] if index.zero? - - { - expanded: messages, - backtrace: failure.backtrace - } - end + @failure_expanded end end end diff --git a/lib/buildkite/test_collector/rspec_plugin/reporter.rb b/lib/buildkite/test_collector/rspec_plugin/reporter.rb index 609548b..93036e9 100644 --- a/lib/buildkite/test_collector/rspec_plugin/reporter.rb +++ b/lib/buildkite/test_collector/rspec_plugin/reporter.rb @@ -16,7 +16,11 @@ def handle_example(notification) trace = Buildkite::TestCollector.uploader.traces[example.id] if trace - trace.example = example + trace.result = case example.execution_result.status + when :passed; "passed" + when :failed; "failed" + when :pending; "skipped" + end if example.execution_result.status == :failed trace.failure_reason, trace.failure_expanded = failure_info(notification) end diff --git a/lib/buildkite/test_collector/rspec_plugin/trace.rb b/lib/buildkite/test_collector/rspec_plugin/trace.rb index b9853b7..f507a54 100644 --- a/lib/buildkite/test_collector/rspec_plugin/trace.rb +++ b/lib/buildkite/test_collector/rspec_plugin/trace.rb @@ -2,7 +2,8 @@ module Buildkite::TestCollector::RSpecPlugin class Trace < Buildkite::TestCollector::Trace - attr_accessor :example, :failure_reason, :failure_expanded + attr_accessor :failure_reason, :failure_expanded + attr_writer :result attr_reader :history attr_reader :tags attr_reader :location_prefix @@ -10,48 +11,45 @@ class Trace < Buildkite::TestCollector::Trace FILE_PATH_REGEX = /^(.*?\.(rb|feature))/ def initialize(example, history:, failure_reason: nil, failure_expanded: [], tags: nil, location_prefix: nil) - @example = example @history = history @failure_reason = failure_reason @failure_expanded = failure_expanded @tags = tags @location_prefix = location_prefix + + # Extract all data eagerly to allow GC of the test object + @scope = example.example_group.metadata[:full_description] + @name = example.description + @location = example.location + @id = strip_invalid_utf8_chars(example.id) + @shared_group_inclusion_backtrace = example.metadata[:shared_group_inclusion_backtrace] end def result - case example.execution_result.status - when :passed; "passed" - when :failed; "failed" - when :pending; "skipped" - end + @result end private def scope - example.example_group.metadata[:full_description] + @scope end def name - example.description + @name end def location - example.location + @location end def file_name @file_name ||= begin - identifier_file_name = strip_invalid_utf8_chars(example.id)[FILE_PATH_REGEX] - location_file_name = example.location[FILE_PATH_REGEX] + identifier_file_name = @id[FILE_PATH_REGEX] + location_file_name = @location[FILE_PATH_REGEX] if identifier_file_name != location_file_name - # If the identifier and location files are not the same, we assume - # that the test was run as part of a shared example. If this isn't the - # case, then there's something we haven't accounted for if shared_example? - # Taking the last frame in this backtrace will give us the original - # entry point for the shared example shared_example_call_location[FILE_PATH_REGEX] else "Unknown" @@ -63,11 +61,11 @@ def file_name end def shared_example? - !example.metadata[:shared_group_inclusion_backtrace].empty? + !@shared_group_inclusion_backtrace.empty? end def shared_example_call_location - example.metadata[:shared_group_inclusion_backtrace].last.inclusion_location + @shared_group_inclusion_backtrace.last.inclusion_location end end end diff --git a/spec/support/rspec_example_trace_helpers.rb b/spec/support/rspec_example_trace_helpers.rb index 5ec08e2..5e28f31 100644 --- a/spec/support/rspec_example_trace_helpers.rb +++ b/spec/support/rspec_example_trace_helpers.rb @@ -52,9 +52,9 @@ def fake_example(opts = {}) end def fake_trace(a_example) - fake_trace = double("Buildkite::TestCollector::RSpecPlugin::Trace", example: a_example) + fake_trace = double("Buildkite::TestCollector::RSpecPlugin::Trace") allow(fake_trace).to receive(:[]) { fake_trace } - allow(fake_trace).to receive(:example=) + allow(fake_trace).to receive(:result=) allow(fake_trace).to receive(:failure_reason=) allow(fake_trace).to receive(:failure_expanded=) fake_trace diff --git a/spec/test_collector/http_client_spec.rb b/spec/test_collector/http_client_spec.rb index 72c7c5f..1237d0c 100644 --- a/spec/test_collector/http_client_spec.rb +++ b/spec/test_collector/http_client_spec.rb @@ -18,11 +18,16 @@ description: "mince and cheese", id: "12", location: "123 Pie St", - execution_result: execution_result + execution_result: execution_result, + metadata: { shared_group_inclusion_backtrace: [] } ) end - let(:trace) { Buildkite::TestCollector::RSpecPlugin::Trace.new(example, history: "pie lore") } + let(:trace) do + t = Buildkite::TestCollector::RSpecPlugin::Trace.new(example, history: "pie lore") + t.result = "passed" + t + end let(:http_double) { double("Net::HTTP_double") } let(:post_double) { double("Net::HTTP::Post") }