packages feed

interprocess-0.2.1.0: test/StoredMVar.hs

{-# LANGUAGE TupleSections #-}
module Main (main) where

import Control.Concurrent                    (threadDelay)
import Control.Concurrent.Async
import Control.Concurrent.Process.StoredMVar
import Tools.Runner
import Tools.TestResult

data BasicRole = Master | Slave
  deriving (Eq, Ord, Show, Read)

data ThreeWayRole = Reader | Taker | Putter
  deriving (Eq, Ord, Show, Read)

simpleTakePut :: TestSpec
simpleTakePut = Repeat 100 $ TestSpec "SimpleTakePut"
  [ (Master, run)
  , (Slave, run)
  ]
  where
    run :: BasicRole -> StoredMVar Double -> IO TestResult
    run Master mVar = do
      putMVar mVar 42
      putMVar mVar 17
      return Success
    run Slave mVar = do
      a <- takeMVar mVar
      b <- takeMVar mVar
      return $
        if (a + b) == (42 + 17)
          then Success
          else Failure $ show (a + b) ++ " /= 42 + 17"


readersTakers :: TestSpec
readersTakers = Repeat 100 $ TestSpec "ReadersTakers" $
    (, run) <$> (replicate 20 Reader <> [Taker, Putter])
  where
    run :: ThreeWayRole -> StoredMVar Int -> IO TestResult
    run Putter mVar = do
      let putLoud x = do
            putStrLn $ "Putting " ++ show x ++ "..."
            putMVar mVar x
      putLoud 177
      putLoud 178
      putLoud 179
      putLoud 777
      return Success
    run Taker mVar = do
      a <- takeMVar mVar
      b <- takeMVar mVar
      c <- takeMVar mVar
      putStrLn $ "Taking: " ++ show (a, b, c)
      return $
        if a < b && b < c
          then Success
          else Failure "Three taken numbers must go ordered!"
    run Reader mVar = do
      a <- readMVar mVar
      b <- readMVar mVar
      c <- readMVar mVar
      putStrLn $ "Reading: " ++ show (a, b, c)
      return $
        if a <= b && b <= c
          then Success
          else Failure "Three taken numbers must go ordered!"


asyncException :: TestSpec
asyncException = Repeat 10 $ WithTimeLimit 2000 $ TestSpec "AsyncException" [((), run)]
  where
    run :: () -> StoredMVar Int -> IO TestResult
    run _ mvar = do
      let timeMs = 50 :: Int
      locked <- async $ takeMVar mvar
      threadDelay $ timeMs * 1000
      killed <- async $ cancel locked
      let pollStatus t = do
            let t1 = t + timeMs
            threadDelay $ timeMs * 1000
            r <- poll killed
            case r of
              Nothing -> pollStatus t1
              Just _  -> return t1
      -- NB: the whole thread is gonna be killed by the test runner
      --     if pollStatus does not finish within the time defined in SpecParams.
      elapsed <- pollStatus 0
      putStrLn $ "Cancelled a thread within " ++ show elapsed ++ " ms"
      return Success

main :: IO ()
main = runTests [simpleTakePut, readersTakers, asyncException]