Skip to content

Handle Open3 returning a nil status #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lib/cc/engine/analyzers/command_line_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ def initialize(command, timeout = DEFAULT_TIMEOUT)
def run(input)
Timeout.timeout(timeout) do
out, err, status = Open3.capture3(command, stdin_data: input)

status ||= handle_open3_race_condition(out)

if status.success?
yield out
else
Expand All @@ -26,6 +29,25 @@ def run(input)
private

attr_reader :command, :timeout

# Work around a race condition in JRuby's Open3.capture3 that can lead
# to a nil status returned. We'll consider the process successful if it
# produced output that can be parsed as JSON.
#
# https://github.com/jruby/jruby/blob/master/lib/ruby/stdlib/open3.rb#L200-L201
#
def handle_open3_race_condition(out)
JSON.parse(out)
NullStatus.new(true, 0)
rescue JSON::ParserError
NullStatus.new(false, 1)
end

NullStatus = Struct.new(:success, :exitstatus) do
def success?
success
end
end
end
end
end
Expand Down
52 changes: 52 additions & 0 deletions spec/cc/engine/analyzers/command_line_runner_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require "spec_helper"
require "cc/engine/duplication"

module CC::Engine::Analyzers
RSpec.describe CommandLineRunner do
describe "#run" do
it "runs the command on the input and yields the output" do
runner = CommandLineRunner.new("cat; echo hi")

output = runner.run("oh ") { |o| o }

expect(output).to eq "oh hi\n"
end


it "raises on errors" do
runner = CommandLineRunner.new("echo error output >&2; false")

expect { runner.run("") }.to raise_error(
ParserError, /code 1:\nerror output/
)
end

it "times out commands" do
runner = CommandLineRunner.new("sleep 3", 0.01)

expect { runner.run("") }.to raise_error(Timeout::Error)
end

context "when Open3 returns a nil status" do
it "accepts it if the output parses as JSON" do
runner = CommandLineRunner.new("")

allow(Open3).to receive(:capture3).and_return(["{\"type\":\"issue\"}", "", nil])

output = runner.run("") { |o| o }
expect(output).to eq "{\"type\":\"issue\"}"
end

it "raises if the output was not valid JSON" do
runner = CommandLineRunner.new("")

allow(Open3).to receive(:capture3).and_return(["", "error output", nil])

expect { runner.run("") }.to raise_error(
ParserError, /code 1:\nerror output/
)
end
end
end
end
end