-
Notifications
You must be signed in to change notification settings - Fork 107
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
Add shrink timeout #488
base: master
Are you sure you want to change the base?
Add shrink timeout #488
Conversation
58a6512
to
620ca5f
Compare
Not a maintainer myself, but I think this is neat! More name bikeshedding: I'd suggest adding "micros" (e.g.
Given a known shrink tree, you could have a test deliberately hang on a given input, e.g. a timeout of 100 microseconds and hang for 200 after five shrinks. |
My two cents: I like the naming format |
1393063
to
8419e26
Compare
Thanks for the idea! I added such a test here. I made the timeout longer (1 second) as lower values would often cause at least one ci job to fail (usually MacOS on an older GHC), due to the test timing out before it reached the generated values I specifically wanted it to get stuck on. I also had a "sanity-check" style test that verified the timeout indeed cancels shrinking in the expected wall-clock time. -- Time limit of 2 seconds. Verifies that withShrinkTime indeed cancels
-- shrinking within the time limit we want.
prop_ShrinkTimeLimitClock :: Property
prop_ShrinkTimeLimitClock =
property $ do
startTime <- liftIO $ Clock.getMonotonicTime
annotateShow startTime
_ <- checkModPropGen delay30s (withShrinkTime 2000000)
endTime <- liftIO $ Clock.getMonotonicTime
annotateShow endTime
let timeElapsed = endTime - startTime
annotateShow timeElapsed
-- should be around 2
diff timeElapsed (>=) 1.5
diff timeElapsed (<=) 2.5
where
delay30s x = when (x == 13) (liftIO $ CC.threadDelay 30000000) Unfortunately this relies on As far as the name goes, I agree adding the units is a good idea. Yet |
Also it is probably a good idea to mention -- | Set the timeout -- in microseconds -- after which the test runner gives up
-- on shrinking and prints the best counterexample. Note that shrinking can be
-- cancelled before the timeout if the 'ShrinkLimit' is reached
-- (defaults to 1,000). See 'withShrinks'.
--
withShrinkTime :: ShrinkTimeLimit -> Property -> Property |
c74f125
to
c247881
Compare
I went ahead and made those changes:
|
29b2b1a
to
ab42332
Compare
Add withShrinkTimeoutMicros to allow configuring shrink behavior in terms of a timeout.
Resolves #476.
There are some design decisions to make, so this is intended more to jumpstart the conversation than it is to present a finished implementation. Some notes:
ShrinkTimeLimit :: Int
independent of the currentShrinkLimit :: Int
. This way is backwards compatible, and it allows one to specify both a total number of shrinks and a time limit. That said, it is arguable that combining these choices into a single option makes for a friendlier interface as e.g. someone might specify a time limit of30s
only to be unexpectedly thwarted by the defaultShrinkLimit
of 1,000.ShrinkTimeLimit
could also be namedShrinkTimeout
.Int
microseconds to make interop withtimeout
simpler, though I could imagine choosing something less implementation-derived, say, seconds (and maybe a different type e.g.Natural
).IORef
iffShrinkTimeLimit
is set. IfShrinkTimeLimit
is not set then the "update" logic isconst (pure ())
. I mention this in case it can affect performance, as an alternative would be to have two totally different loops, at the cost of code reuse.Thanks!