A few days ago, I was writing some integration tests. The site's workflow was something like this:
POSTto a URL like '/create_a_widget' with some data
- Get a token saying "your widget will be A29G"
GETthe finished widget from a URL like '/widgets/A29G'.
At step 3, either the widget is ready or you have to try again.
Now I know that it shouldn't take more than, say, 3 seconds before the widget is ready. So in my test, I could say "do step 2,
sleep 3 then do step 3 and check the results." But that's slow, and maybe the widget will actually be ready much sooner.
Alternately, I could poll until it's done. That could get results quickly, but would hang if it never finishes.
What I'd really like to do is say "poll for up to 3 seconds. If it finishes sooner, great! If time runs out, give up."
So I wrote a small helper method to do just that. It looks like this:
def with_timeout_of(duration, failure_message = "Time up") start = Time.now finish = start + duration answer = nil while Time.now < finish answer = yield break if answer sleep 0.1 # simple rate limit end answer ? answer : fail(failure_message) end
Here's how I use it:
it "can make and fetch a widget" do # 1. do the post # 2. get the token widget = with_timeout_of(3) do response = get_widget('A29G') # If there's a widget in the response, # return it; we're done. # If not, return false and we'll poll # again if time isn't up. response.fetch("widget", false) end expect(widget).to be_shiny # or whatever end
If you like this, feel free to adapt it for your own needs. Happy coding!