glue-core-0.8.0.0: test/Glue/TimeoutSpec.hs
{-# LANGUAGE ScopedTypeVariables #-}
module Glue.TimeoutSpec (spec) where
import Control.Concurrent.Async (async, wait)
import Glue.Clock
import Glue.Clock.Virtual
import Glue.Timeout
import Test.Hspec
import Test.QuickCheck
spec :: Spec
spec = do
describe "addTimeout" $ do
it "Services taking too long should fail with a timeout" $
property $ \(request :: Int) -> do
vc <- newVirtualClock
let clock = virtualClock vc :: Clock IO
options = (defaultTimeoutOptions :: TimeoutOptions IO) { timeoutLimitMs = 10, timeoutClock = clock }
service req = (if req > 0 then pure () else clockSleep clock (50 * 1000)) >> pure (req + 100)
timeoutService = addTimeout options service
if request > 0
then timeoutService request `shouldReturn` (request + 100)
else do
call <- async (timeoutService request)
waitForSleepers vc 2
advanceClock vc (10 * 1000)
wait call `shouldThrow` (== TimeoutException (timeoutDescription options))
it "Does not time out a call that finishes just inside the limit" $ do
vc <- newVirtualClock
let clock = virtualClock vc :: Clock IO
options = (defaultTimeoutOptions :: TimeoutOptions IO) { timeoutLimitMs = 10, timeoutClock = clock }
call <- async (addTimeout options (\(x :: Int) -> clockSleep clock 9999 >> pure x) 7)
waitForSleepers vc 2
advanceClock vc 9999
wait call `shouldReturn` 7
describe "addTimeoutEither" $
it "Returns the timeout failure as a value" $ do
vc <- newVirtualClock
let clock = virtualClock vc :: Clock IO
options = (defaultTimeoutOptions :: TimeoutOptions IO) { timeoutLimitMs = 10, timeoutClock = clock }
service (_ :: Int) = clockSleep clock 50000 >> pure (Right (1 :: Int))
call <- async (addTimeoutEither options "timed out" service 1)
waitForSleepers vc 2
advanceClock vc 10000
wait call `shouldReturn` (Left ("timed out" :: String))