-
Notifications
You must be signed in to change notification settings - Fork 54
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
Build tidiness #233
Build tidiness #233
Conversation
* Use Timeout.timeout, not Object#timeout
* http://git.io/vJf3J * This appears consistently to fix the red Reel tests
Oh my word, github, you really are in a mood tonight. |
* Avoids NoMethodError: undefined method `spec' for nil:NilClass * Similar approach used in thoughtbot/factory_bot@3c0547f
cab9deb
to
0899628
Compare
In order to 'reserve' a free TCP Server port, we create a TCPServer, take a note of its port number, and then immediately close it. We'd then ask our adapter to use the port we just finished with via that adapter's configuration. While this isn't a particularly safe way of 'reserving' a port, it's the best we can do with heterogeneous adapters that have a one-way config method. However, this would cause intermittent test failures when our 'canary' socket did not get out of the way in time for an adapter to bind its server. Socket#close does not actually block until the socket is closed at OS level, it just frees the Ruby handle to it. Actually waiting for the socket to become free or garbage-collecting it to force the issue is counterproductive – we'd need to poll the port or run a full GC, which would take more time than a simple sleep. Additionally, the sleep needs to be tuned so that tests are not unduly slowed by it – too quick and we'll see failures, too slow and our builds will reflect it.
Using let-style RSpec and lazily creating our servers before every test is good from a test purity point of view but increases greatly the risk of port collisions when we attempt to find a free port to run our adapter in adapter_lint (bearing in mind that Socket#close only releases the Ruby resources, and the socket persists in a TIME_WAIT state for an indeterminate period of time at OS level). Revert to before(:all) and create only one server that will be used for the duration of all tests in adapter_lint. We still need to sleep to ensure our 'free' ports are available, but we reduce the risk of servers being unavailable. This also has the happy side effect of making the tests somewhat faster.
This looks good to me. Is there a reason not to have Ruby 2.2 in the build? |
No good reason, no. Really I was just avoiding it to try and make the build time more tolerable while still acknowledging latest stable. |
For reasons we can't currently fathom, Rubinius has a tendency to fail the build. Rather than let this continue to be the case, until such time as someone has time to figure out precisely why, unblock other PRs by letting builds pass with MRI Rubies for now.
Should we wait for this to be merged into master before merging into other PRs (like #235), or would it be fine to pull in to them now to get tests passing? |
I am going to run this a couple times on travis now. |
builds all the time, merge merge. |
Next step would be to extract all adapters except those shipped by ruby itself to be moved to different gems. Could there be a way to load them automatically when needed? @seancribbs @rgarner |
Object#timeout
deprecation warnings when building with 2.3.0Socket#close
does not actually block on closing the socket. Ruby thinks it's closed, but the OS has it in a briefTIME_WAIT
state. There's seemingly no good way of detecting this, so we combinesleep
ing after close with reverting tobefore(:all)
for adapter lint tests and having each adapter's server live for the duration of alladapter_lint
tests instead of restarting on every test.NoMethodError: undefined method
spec' for nil:NilClass` which occurred in various of Travis's rubies due to old bundler versions by updating bundler before build