-------------------------------------------------------------------------------
-- network-wait
-- Copyright 2022 Michael B. Gale (github@michael-gale.co.uk)
-------------------------------------------------------------------------------
{-# OPTIONS_GHC -Wno-unused-imports #-}
{-# LANGUAGE TypeApplications #-}
import Control.Concurrent
import Control.Monad.Catch
import Control.Retry
-- Only needed for base < 4.11, redundant otherwise
import Data.Semigroup
import Test.Tasty
import Test.Tasty.HUnit
import Network.Simple.TCP
import Network.Wait
-------------------------------------------------------------------------------
-- | Essentially the same as `retryPolicyDefault`, but here for compatibility
-- with older versions of `retry`.
testRetryPolicy :: Monad m => RetryPolicyM m
testRetryPolicy = constantDelay 50000 <> limitRetries 5
-- | `withServer` @delay action@ runs @action@ while asynchronously setting up
-- a TCP server on @localhost:5999@ with a @delay@ microseconds delay. The TCP
-- server will accept exactly one connection before shutting down.
withServer :: Int -> IO () -> IO ()
withServer delay k = do
let initSocket = do
(sock, _) <- bindSock (Host "localhost") "5999"
listenSock sock 1
pure sock
tid <- forkIO $ do
-- wait before starting the server
threadDelay delay
-- initialise the server, accept one connection, and shut down
bracket initSocket closeSock $ \sock ->
accept sock $ \(client,_) -> closeSock client
-- run the computation that depends on the server
k
-- kill the server thread, if it is still alive
killThread tid
tests :: TestTree
tests = testGroup "network-wait"
[ testCase "Can't connect to service that doesn't exist" $ do
res <- try @IO @SomeException $
waitTcp testRetryPolicy "localhost" "5999"
case res of
Left _ -> pure ()
Right _ -> assertFailure "`waitTcp` did not fail"
, testCase "Can connect to service that does exist" $
withServer 0 $ do
res <- try @IO @SomeException $
waitTcp testRetryPolicy "localhost" "5999"
case res of
Left ex -> assertFailure $
"`waitTcp` caused an exception: " <> show ex
Right _ -> pure ()
, testCase "Can connect to service after delay" $
withServer 500000 $ do
let policy = limitRetries 5 <> exponentialBackoff (60*1000)
res <- try @IO @SomeException $
waitTcp policy "localhost" "5999"
case res of
Left ex -> assertFailure $
"`waitTcp` caused an exception: " <> show ex
Right _ -> pure ()
]
-- | `main` is the entry point to this test suite.
main :: IO ()
main = defaultMain tests
-------------------------------------------------------------------------------