Skip to content

Commit 88419c7

Browse files
committed
Simplify itWithCustomTimeout implementation
with Matthias suggestion.
1 parent 766200b commit 88419c7

File tree

2 files changed

+25
-35
lines changed

2 files changed

+25
-35
lines changed

lib/test-utils/src/Test/Hspec/Extra.hs

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
{-# LANGUAGE LambdaCase #-}
33
{-# LANGUAGE ScopedTypeVariables #-}
44
{-# LANGUAGE TupleSections #-}
5-
{-# LANGUAGE TypeApplications #-}
65

76
-- |
87
-- Copyright: © 2018-2020 IOHK
@@ -22,13 +21,11 @@ import Prelude
2221
import Control.Concurrent
2322
( threadDelay )
2423
import Control.Concurrent.Async
25-
( AsyncCancelled, async, race, race_, wait )
24+
( AsyncCancelled, async, race, wait )
2625
import Control.Concurrent.MVar
2726
( MVar, newEmptyMVar, putMVar, takeMVar )
2827
import Control.Exception
29-
( SomeException, fromException, throwIO, try )
30-
import Data.Maybe
31-
( isJust )
28+
( SomeException, catch, throwIO )
3229
import Test.Hspec
3330
( ActionWith
3431
, HasCallStack
@@ -115,36 +112,29 @@ aroundAll acquire =
115112
it :: HasCallStack => String -> ActionWith ctx -> SpecWith ctx
116113
it = itWithCustomTimeout (10*minute)
117114
where
118-
minute = 60*1000*1000
115+
minute = 60
119116

120117
-- | Like @it@ but with a custom timeout, which makes it realistic to test.
121-
itWithCustomTimeout :: HasCallStack => Int -> String -> ActionWith ctx -> SpecWith ctx
122-
itWithCustomTimeout micro title action = specify title $ \ctx -> do
123-
race_ timeout $ do
124-
res1 <- try $ action ctx
125-
case res1 of
126-
Right r1 -> return r1
127-
Left (e1 :: SomeException)
128-
-- If we time out during the first attempt, then we /should/ time
129-
-- out.
130-
| isAsyncCancelled e1 -> throwIO e1
131-
| otherwise -> do
132-
res2 <- try $ action ctx
133-
case res2 of
134-
-- If the second try fails, return the first error. The
135-
-- second error might not be helpful.
136-
Left (e2 :: SomeException)
137-
| isAsyncCancelled e2 -> throwIO e1
138-
| otherwise -> throwIO e1
139-
Right r2 -> return r2
118+
itWithCustomTimeout
119+
:: HasCallStack
120+
=> Int -- ^ Timeout in seconds.
121+
-> String
122+
-> ActionWith ctx
123+
-> SpecWith ctx
124+
itWithCustomTimeout sec title action = specify title $ \ctx -> timeout sec $ do
125+
action ctx
126+
`catch` (\(_ :: AsyncCancelled) -> return ())
127+
`catch` (\(e :: SomeException) -> action ctx
128+
`catch` (\(_ :: SomeException) -> throwIO e))
140129
where
141-
isAsyncCancelled = isJust . fromException @AsyncCancelled
142-
timeout = do
143-
threadDelay micro
144-
expectationFailure
145-
$ "timed out in "
146-
<> show (micro `div` 1000000)
147-
<> " seconds"
130+
timeout t act =
131+
race (threadDelay (micro t)) act >>= \case
132+
Right () ->
133+
return ()
134+
Left () ->
135+
expectationFailure $ "timed out in " <> show t <> " seconds"
136+
where
137+
micro = (* 1000) . (* 1000)
148138

149139
-- | Some helper to help readability on the thread synchronization above.
150140
await :: MVar () -> IO ()

lib/test-utils/test/Test/Hspec/ExtraSpec.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ spec = do
5656
outcomes <- newIORef [failure, noRetry]
5757
(dynamically outcomes) `shouldMatchHSpecIt` failure
5858
it "can time out" $ do
59-
let s = 1000*1000
59+
let micro = (1000*1000 *)
6060
let timeout = do
61-
threadDelay (10 * s)
61+
threadDelay (micro 10)
6262
expectationFailure "should have timed out"
63-
res <- run (Extra.itWithCustomTimeout $ 2 * s) timeout
63+
res <- run (Extra.itWithCustomTimeout 2) timeout
6464
res `shouldContain` "timed out in 2 seconds"
6565

6666
where

0 commit comments

Comments
 (0)