From d6f1ad20892cd6497384939f4e082428f96fbd53 Mon Sep 17 00:00:00 2001 From: Naoto Ono Date: Thu, 8 Aug 2024 10:50:40 +0900 Subject: [PATCH] Launchable: Capture Timeout error --- tool/lib/test/unit.rb | 42 +++++++++++++++++++++++++++------- tool/lib/test/unit/parallel.rb | 2 +- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/tool/lib/test/unit.rb b/tool/lib/test/unit.rb index 30f30df62e..40ea0762c9 100644 --- a/tool/lib/test/unit.rb +++ b/tool/lib/test/unit.rb @@ -782,11 +782,11 @@ module Test unless rep.empty? rep.each do |r| if r[:error] - puke(*r[:error], Timeout::Error.new) + puke(*r[:error], Timeout::Error.new, r[:file]) next end r[:report]&.each do |f| - puke(*f) if f + puke(*f, r[:file]) if f end end if @options[:retry] @@ -1384,7 +1384,36 @@ module Test end module LaunchableOption - module Nothing + module Runner + def puke(klass, meth, e, file=nil) + if writer = options[:launchable_test_reports] + # # Since `record` method is not called when a timeout occurs while waiting for the worker's response, we need to capture it here. + if file && e.is_a?(Timeout::Error) + status = 'TEST_FAILED' + e = "Timeout:\n#{klass}##{meth}\n" + full_path = File.expand_path(file) + repo_path = File.expand_path("#{__dir__}/../../../") + relative_path = full_path.delete_prefix("#{repo_path}/") + # The test path is a URL-encoded representation. + # https://github.com/launchableinc/cli/blob/v1.81.0/launchable/testpath.py#L18 + test_path = {file: relative_path, class: klass, testcase: meth}.map{|key, val| + "#{encode_test_path_component(key)}=#{encode_test_path_component(val)}" + }.join('#') + writer.write_object( + { + testPath: test_path, + status: status, + duration: options[:worker_timeout], + createdAt: Time.now.to_s, + stderr: e, + stdout: nil + } + ) + end + end + super + end + private def setup_options(opts, options) super @@ -1410,9 +1439,6 @@ module Test when Test::Unit::AssertionFailedError status = 'TEST_FAILED' "Failure:\n#{suite.name}##{method} [#{location error}]:\n#{error.message}\n" - when Timeout::Error - status = 'TEST_FAILED' - "Timeout:\n#{suite.name}##{method}\n" else status = 'TEST_FAILED' bt = Test::filter_backtrace(error.backtrace).join "\n " @@ -1790,7 +1816,7 @@ module Test prepend Test::Unit::ExcludesOption prepend Test::Unit::TimeoutOption prepend Test::Unit::RunCount - prepend Test::Unit::LaunchableOption::Nothing + prepend Test::Unit::LaunchableOption::Runner ## # Begins the full test run. Delegates to +runner+'s #_run method. @@ -1816,7 +1842,7 @@ module Test alias orig_run_suite _run_suite # Overriding of Test::Unit::Runner#puke - def puke klass, meth, e + def puke klass, meth, e, file=nil n = report.size e = case e when Test::Unit::PendedError then diff --git a/tool/lib/test/unit/parallel.rb b/tool/lib/test/unit/parallel.rb index 188a0d1a19..4accf930c1 100644 --- a/tool/lib/test/unit/parallel.rb +++ b/tool/lib/test/unit/parallel.rb @@ -167,7 +167,7 @@ module Test abort("#{e.inspect} in _report(#{res.inspect}, #{args.inspect})\n#{e.backtrace.join("\n")}") end - def puke(klass, meth, e) # :nodoc: + def puke(klass, meth, e, file=nil) # :nodoc: if e.is_a?(Test::Unit::PendedError) new_e = Test::Unit::PendedError.new(e.message) new_e.set_backtrace(e.backtrace)