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

Improve the output matcher to make it thread safe #642

Open
cupakromer opened this issue Aug 29, 2014 · 8 comments
Open

Improve the output matcher to make it thread safe #642

cupakromer opened this issue Aug 29, 2014 · 8 comments

Comments

@cupakromer
Copy link
Member

The current output matcher is not considered thread safe.

Rails had a similar feature capture and silence which were both recently deprecated. This caused issues with the ammeter gem which relied on those methods. The patch applied there was near identical to how the output matcher works. Based on feedback this is not considered thread safe either.

cupakromer referenced this issue in alexrothenberg/ammeter Aug 29, 2014
Thanks @cupakromer for this fix re-implementing `capture` now that Rails 4.2 has made it private.
@mikegee
Copy link

mikegee commented Aug 30, 2014

This seems to work in my initial testing:

def self.capture(&block)
  reader, writer = IO.pipe

  fork do
    reader.close
    $stdout = writer
    block.call
  end
  writer.close

  reader.read
end

Downsides include:

  • decreased portability? (jvm, windows)
  • increased overhead
  • errors raised in the block would not stop the execution of the parent

@JonRowe
Copy link
Member

JonRowe commented Sep 1, 2014

We can't use fork as far as I know because we support JRuby, windows and I don't think RBX supports it either...

@myronmarston
Copy link
Member

fork also has some pretty surprising effects: state mutations in the expect block will not be visible outside of it (as the block will run in a sub process), which is very unexpected behavior. I think fork has too many downsides and gotchas to consider.

@mikegee
Copy link

mikegee commented Sep 2, 2014

Gotcha. No forking allowed.

Is there a thread-safe implementation of the output matcher? Put me down as pessimistic.

Does the output matcher need to go away in favor of a thread-safe Rspec?

@myronmarston
Copy link
Member

Is there a thread-safe implementation of the output matcher? Put me down as pessimistic.

I'm not sure. I haven't looked into this issue at all yet, honestly.

Does the output matcher need to go away in favor of a thread-safe Rspec?

I know minitest has a similar feature, and it has a multithreaded parallel test runner, so it doesn't seem like they are fundamentally incompatible. Also, the matcher is brand new in 3.0...so I don't want to consider removing it. If we simply can't find a way to make it threadsafe, we can (and should) document that this particular matcher isn't threadsafe so users are aware of the issue.

@mikegee
Copy link

mikegee commented Sep 2, 2014

minitest is using the same thread-unsafe (StringIO, global swapping) implementation: https://github.com/seattlerb/minitest/blob/master/lib/minitest/assertions.rb#L399

@bf4
Copy link

bf4 commented Nov 13, 2014

Maybe see rubygems, per my comment rails/rails#13392 (comment)

@soulcutter
Copy link
Member

I feel like a mutex is best way to guarantee threadsafety (possibly combined with the rubytapas-style capturing mentioned by @bf4 in the other comment), however it's probably important to not initialize the mutex with a non-atomic ||= operation, though the risk of a race condition is small.

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

No branches or pull requests

6 participants