travisjeffery / timecop

A gem providing "time travel", "time freezing", and "time acceleration" capabilities, making it simple to test time-dependent code. It provides a unified method to mock Time.now, Date.today, and DateTime.now in a single call.
MIT License
3.36k stars 223 forks source link

Mocking `Process.clock_gettime` causes `Concurrent::IVar` with timeout to wait indefinitely #425

Closed olly closed 2 months ago

olly commented 3 months ago

Updating Timecop to v0.9.9 caused some of our system integration tests which utilise frozen time to wait indefinitely. I managed to narrow it down to the change introduced in 3a0b567bc951bb16e45b95a8c350d7683bbeedcd.

We initially noticed it in a system integration test which used capybara & cuprite to drive a browser. However on further investigation I believe the root cause it down to ferrum's use of a Concurrent::IVar.

I've created a minimal test case which can reproduce the issue.

It appears the concurrent-ruby uses monotonic time to determine whether a timeout has been passed, and therefore by stubbing the monotonic clock it never causes a timeout.


I'm not sure what the exact resolution of this should be. I can see the value in being able to stub the monotonic clock, but perhaps it's too low level to stub by default? I imagine if this impacts a number of concurrent-ruby data structures then it might cause Timecop to be unusable in a large number of testing scenarios.


Thanks for all your hard-work on this gem. ❤️

nerdrew commented 3 months ago

Can we make stubbing Process.clock_gettime a configurable option when freeze-ing or travel-ing?

joshuacronemeyer commented 2 months ago

@alexcwatt any chance you can look at this? I think @nerdrew's suggestion is one viable option. Should we make this option disabled by default? Interested in opinions on this.

joshuacronemeyer commented 2 months ago

thanks @olly for raising this issue. i'm hopeful we can have a solution and get a 0.9.10 release out quickly

alexcwatt commented 2 months ago

@joshuacronemeyer 👀 will take a look

alexcwatt commented 2 months ago

@olly Thanks again for flagging. I cloned your gist, changed Ruby version to 3.2.1 (that's what I have on this MacBook), and was able to repro the issue. Then I upgraded timecop to 0.9.10 and validated the fix - the test doesn't hang.

@joshuacronemeyer I can't close this but based on validation it seems safe to close, and let @olly reopen if there is something we've missed here.