Skip to content
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

Fix broken exception handler #357

Merged
merged 2 commits into from
Apr 6, 2016

Conversation

e2
Copy link
Contributor

@e2 e2 commented Mar 31, 2016

Summary

An old, undefined variable (cmd) was left over after refactoring. It was replaced with the right one (commandline).

Also, a spec was added to force the code to fail on Unix.

Details

This caused failures on AppVeyor, because the exception handler crashed.

This failed only on Windows because the PATH traversing didn't throw an error earlier.

Still, the error could've occurred on Unix if the program was in the PATH (so no exception there), and yet there was an error accessing a program's file (like if the file wasn't readable).

Motivation and Context

Fixes failure on AppVeyor.

How Has This Been Tested?

Locally, RSpec.

This probably can be simulated in Cucumber scenarios by having an unreadable binary file (e.g. using chmod -r)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist:

  • My code follows the code style of this project.

@@ -56,5 +56,35 @@

it { expect {process.start}.to raise_error Aruba::LaunchError }
end

context "with a childprocess launch error" do
let(:child) { instance_double(ChildProcess::AbstractProcess) }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmhh... I think we should not fully mock "Classes" we not own. Just make it an double, to an instance one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ChildProcess is from the child_process gem, that's why I mocked it out. (https://github.com/jarib/childprocess).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's made a double, we miss out on RSpec's "method check" feature.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know, but don't fiddle with someone else's classes. Why not using this instead: https://relishapp.com/rspec/rspec-mocks/docs/verifying-doubles/using-a-class-double

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that won't work. Or I don't see how.

A class double would help if I was only mocking out ChildProcess.build. And since Aruba::Processes::SpawnProcess breaks the Law Of Demeter here (the result of .build should be wrapped by another Aruba class), I can't use a const_double for it.

I mean, I can used const_double for .build because technically it "fits" (as a method on a constant), but that's not what I'm testing. If I did, I'd be forced to use :transfer_nested_constants because everything in the tests is namespaced with ChildProcess. And that wouldn't make sense, because ChildProcess is the ONLY case here of using a class method.

As for "fiddling with someone else's classes" - that's the point of using instance_double in the first place - to make the implementation based on the interface (of the 3rd party class) while being independent from the behavior. Thus, "mocking".

It may seem debatable whether using ChildProcess::AbstractProcess is a good idea, but I think it's the best option anyway. Even if I used ChildProcess::Windows::Process instead (if it was available without requiring implicitly), it would still be the exact same interface (due to inheritance). And because of inheritance, ChildProcess::AbstractProcess is the public API of childprocess anyway, so that won't change without a major bump.

All I really wanted to do is mock out the :start method, but due to the way the class is setup (and not wrapped by another Aruba class), the way the mocks are done here just exposes a design problem already in codebase (not wrapping the 3rd party class with something easier to mock out).

I can't use object_double on the child, because then the test would depend on the signature of ChildProcess::AbstractProcess#initialize (which is a private API - the only method of the class!).

So it's either terrible mocking here, or changing the Aruba API to wrap the ChildProcess.build result.

I can use a double, but that's not any less verbose ... and ... it's would just be way of completely ignoring the API altogether.

I can't think of a better alternative here than adding a new wrapper class in Aruba.

@e2 e2 force-pushed the e2-fix_broken_exception_handler branch from e34e26e to 097db5e Compare March 31, 2016 17:39
@e2
Copy link
Contributor Author

e2 commented Mar 31, 2016

I've reworked it and added specs.

@@ -115,16 +115,13 @@ def before_run; end
def after_run; end

def inspect
out = stdout(:wait_for_io => 0) + stderr(:wait_for_io => 0)
out = truncate("#{stdout(:wait_for_io => 0).inspect}", 35)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beautiful. I like that implementation much better!

@ghost
Copy link

ghost commented Apr 1, 2016

Please address my comments / fix ruby 1.8.7 - sorry for that - and we're good to go.

e2 added 2 commits April 2, 2016 08:49
Previously, "cmd" was passed to a different method.

The reason this never came up earlier is because on Unix, if a file is
not in the PATH, a Aruba::LaunchError is raised much earlier.

One way this could've been triggered is: if the program file existed,
but wasn't accessible (e.g. EACCES error). That way it wouldn't fail the
`which` test, but would fail once it was attempted to be executed.
@e2 e2 force-pushed the e2-fix_broken_exception_handler branch from 097db5e to fb8fc4c Compare April 2, 2016 06:51
@e2
Copy link
Contributor Author

e2 commented Apr 2, 2016

Fixed, rebased and squashed.

@e2
Copy link
Contributor Author

e2 commented Apr 5, 2016

Can this be merged? Or is there anything else here needed?

@maxmeyer maxmeyer merged commit 7113616 into cucumber:master Apr 6, 2016
@maxmeyer
Copy link
Member

maxmeyer commented Apr 6, 2016

Well done! No. I'm going to merge this now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants