packages feed

kazura-queue-0.1.0.3: test/Test/KazuraQueue.hs

module Test.KazuraQueue where

import qualified Test.Expectations as T

import qualified Test.Hspec      as HS
import qualified Test.QuickCheck as Q

import qualified Control.Concurrent.KazuraQueue as KQ

import qualified Control.Concurrent       as CC
import qualified Control.Concurrent.Async as AS
import qualified Control.Exception        as E
import qualified Control.Monad            as M

import qualified Data.Foldable as TF

import qualified System.Timeout as ST

timeout :: IO r -> IO r
timeout act = do
    mr <- ST.timeout (10 * 1000000) act
    case mr of
        Just r  -> return r
        Nothing -> T.assertFailure "timeout 10sec"

whenQueueIsEmpty :: (((KQ.Queue x -> IO r) -> IO r) -> HS.Spec) -> HS.Spec
whenQueueIsEmpty f = HS.describe "when Queue is empty" $ f prepare
  where
    prepare :: (KQ.Queue x -> IO r) -> IO r
    prepare iof = do
        q <- KQ.newQueue
        timeout . prependIndefiniteBlock q $ iof q

whenItemsInQueue :: Q.Arbitrary x =>
    (Int, Int) -> ((((KQ.Queue x, [x]) -> IO r) -> IO r) -> HS.Spec) -> HS.Spec
whenItemsInQueue range f = HS.describe "when some items in Queue" $ f prepare
  where
    (minSize, maxSize) = range
    len = maxSize - minSize + 1
    prepare :: Q.Arbitrary x => ((KQ.Queue x, [x]) -> IO r) -> IO r
    prepare iof = do
        num <- (+ minSize) . (`mod` len) . abs <$> Q.generate Q.arbitrary
        vals <- M.replicateM num $ Q.generate Q.arbitrary
        queue <- KQ.newQueue
        TF.for_ vals $ KQ.writeQueue queue
        timeout . prependIndefiniteBlock queue $ iof (queue, vals)

prependIndefiniteBlock :: KQ.Queue x -> IO r -> IO r
prependIndefiniteBlock queue io = do
    async <- AS.async $ do
        CC.threadDelay $ 50 * 1000000 -- 50 sec
        KQ.writeQueue queue $ error "indefinitly blocked"
    io `E.finally` AS.cancel async

--------------- expectations

queueLengthShouldBeIn :: KQ.Queue x -> (Int, Int) -> IO ()
queueLengthShouldBeIn q (minv, maxv) = do
    len <- KQ.lengthQueue q `T.shouldNotBlock` 500000
    len `T.shouldSatisfy` T.and [(>= minv), (<= maxv)]
    alen <- KQ.lengthQueue' q `T.shouldNotBlock` 500000
    alen `T.shouldSatisfy` T.and [(>= max minv 0), (<= max maxv 0)]