kazura-queue-0.1.0.0: test/WVarConcurrentSpec.hs
{-# LANGUAGE ScopedTypeVariables #-}
module WVarConcurrentSpec where
import qualified Test.Concurrent as T
import qualified Test.Expectations as T
import qualified Test.Util as T
import qualified Test.WVar as T
import qualified Test.Hspec as HS
import qualified Test.Hspec.QuickCheck as HS
import qualified Control.Concurrent.WVar as WV
import qualified Control.Monad as M
import qualified Data.List as L
takeWVarSeqSpec :: HS.Spec
takeWVarSeqSpec = HS.describe "takeWVar" $ do
T.whenWVarIsFresh $ \ prepare -> do
HS.prop "takes the value before or after putWVar" $ do
(val1, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.takeWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` val1
, ret `T.shouldBe` val2
]
HS.prop "take different value" $ do
(val1, wv) <- prepare
[val2, val3, val4] <- T.genSatisfy 3 (/= val1)
ret <- T.mapConcurrently
[ WV.takeWVar wv <* WV.putWVar wv val2
, WV.takeWVar wv <* WV.putWVar wv val3
, WV.takeWVar wv <* WV.putWVar wv val4
]
T.oneOf
[ ret `T.shouldBe` [val1,val2,val3]
, ret `T.shouldBe` [val1,val4,val2]
, ret `T.shouldBe` [val3,val1,val2]
, ret `T.shouldBe` [val4,val1,val3]
, ret `T.shouldBe` [val3,val4,val1]
, ret `T.shouldBe` [val4,val2,val1]
]
T.whenWVarIsUpdating $ \ prepare -> do
HS.prop "takes the value after putWVar" $ do
(val1, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.takeWVar wv
ret `T.shouldBe` val2
HS.prop "take different value" $ do
(val1 :: Int, wv) <- prepare
[val2, val3, val4, val5] <- T.genSatisfy 4 (/= val1)
ret <- T.mapConcurrently
[ WV.putWVar wv val2 >> return val2
, WV.takeWVar wv <* WV.putWVar wv val3
, WV.takeWVar wv <* WV.putWVar wv val4
, WV.takeWVar wv <* WV.putWVar wv val5
]
T.oneOf
[ ret `T.shouldBe` [val2,val2,val3,val4]
, ret `T.shouldBe` [val2,val2,val5,val3]
, ret `T.shouldBe` [val2,val4,val2,val3]
, ret `T.shouldBe` [val2,val5,val2,val4]
, ret `T.shouldBe` [val2,val4,val5,val2]
, ret `T.shouldBe` [val2,val5,val3,val2]
]
tryTakeWVarSeqSpec :: HS.Spec
tryTakeWVarSeqSpec = HS.describe "tryTakeWVar" $ do
T.whenWVarIsFresh $ \ prepare -> do
HS.prop "takes the value before or after putWVar" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.tryTakeWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` (True, val1)
, ret `T.shouldBe` (True, val2)
]
HS.prop "all read same value but only one succeeded" $ do
(val :: Int, wv) <- prepare
ret <- T.mapConcurrently
[ WV.tryTakeWVar wv
, WV.tryTakeWVar wv
, WV.tryTakeWVar wv
]
T.oneOf
[ ret `T.shouldBe` [(True,val),(False,val),(False,val)]
, ret `T.shouldBe` [(False,val),(True,val),(False,val)]
, ret `T.shouldBe` [(False,val),(False,val),(True,val)]
]
T.whenWVarIsUpdating $ \ prepare -> do
HS.prop "takes the value before(failure) or after(success) putWVar" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.tryTakeWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` (False, val1)
, ret `T.shouldBe` (True, val2)
]
HS.prop "all read same value and fail" $ do
(val :: Int, wv) <- prepare
ret <- T.mapConcurrently
[ WV.tryTakeWVar wv
, WV.tryTakeWVar wv
, WV.tryTakeWVar wv
]
ret `T.shouldBe` [(False,val),(False,val),(False,val)]
readFreshWVarSeqSpec :: HS.Spec
readFreshWVarSeqSpec = HS.describe "readFreshWVar" $ do
T.whenWVarIsFresh $ \ prepare -> do
HS.prop "reads the value before or after putWVar" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.readFreshWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` val1
, ret `T.shouldBe` val2
]
HS.prop "read same value" $ do
(val :: Int, wv) <- prepare
ret <- T.mapConcurrently
[ WV.readFreshWVar wv
, WV.readFreshWVar wv
, WV.readFreshWVar wv
]
ret `T.shouldBe` [val,val,val]
T.whenWVarIsUpdating $ \ prepare -> do
HS.prop "reads the value after putWVar" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.readFreshWVar wv
ret `T.shouldBe` val2
HS.prop "read same value" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
ret <- T.mapConcurrently
[ WV.putWVar wv val2 >> return val2
, WV.readFreshWVar wv
, WV.readFreshWVar wv
, WV.readFreshWVar wv
]
ret `T.shouldBe` [val2,val2,val2,val2]
tryReadFreshWVarSeqSpec :: HS.Spec
tryReadFreshWVarSeqSpec = HS.describe "tryReadWVar" $ do
T.whenWVarIsFresh $ \ prepare -> do
HS.prop "reads the old value" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.tryReadFreshWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` (True, val1)
, ret `T.shouldBe` (True, val2)
]
HS.prop "all read same value and succeed" $ do
(val :: Int, wv) <- prepare
ret <- T.mapConcurrently
[ WV.tryReadFreshWVar wv
, WV.tryReadFreshWVar wv
, WV.tryReadFreshWVar wv
]
ret `T.shouldBe` [(True,val),(True,val),(True,val)]
T.whenWVarIsUpdating $ \ prepare -> do
HS.prop "reads the value before(failure) or after(success) putWVar" $ do
(val1 :: Int, wv) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWVar wv val2 `T.concurrently` do
ret <- WV.tryReadFreshWVar wv `T.shouldNotBlock` 500000
T.oneOf
[ ret `T.shouldBe` (False, val1)
, ret `T.shouldBe` (True, val2)
]
HS.prop "all read same value and fail" $ do
(val :: Int, wv) <- prepare
ret <- T.mapConcurrently
[ WV.tryReadFreshWVar wv
, WV.tryReadFreshWVar wv
, WV.tryReadFreshWVar wv
]
ret `T.shouldBe` [(False,val),(False,val),(False,val)]
takeWCachedSeqSpec :: HS.Spec
takeWCachedSeqSpec = HS.describe "takeWCached" $ do
T.whenWVarIsFresh . T.withLatestCache $ \ prepare -> do
HS.prop "takes the value before or after putWCached" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
wt <- WV.takeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ WV.readWTicket wt `T.shouldBe` val1
, WV.readWTicket wt `T.shouldBe` val2
]
HS.prop "take different value" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2, val3, val4] <- T.genSatisfy 3 (/= val1)
ret <- fmap WV.readWTicket <$> T.mapConcurrently
[ WV.takeWCached wc <* WV.putWCached wc val2
, WV.takeWCached wc <* WV.putWCached wc val3
, WV.takeWCached wc <* WV.putWCached wc val4
]
T.oneOf
[ ret `T.shouldBe` [val1,val2,val3]
, ret `T.shouldBe` [val1,val4,val2]
, ret `T.shouldBe` [val3,val1,val2]
, ret `T.shouldBe` [val4,val1,val3]
, ret `T.shouldBe` [val3,val4,val1]
, ret `T.shouldBe` [val4,val2,val1]
]
T.whenWVarIsUpdating . T.withLatestCache $ \ prepare -> do
HS.prop "takes the value after putWCached" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.takeWCached wc
WV.readWTicket ret `T.shouldBe` val2
HS.prop "take different value" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2, val3, val4, val5] <- T.genSatisfy 4 (/= val1)
ret <- T.mapConcurrently
[ WV.putWCached wc val2 >> return val2
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val3
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val4
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val5
]
T.oneOf
[ ret `T.shouldBe` [val2,val2,val3,val4]
, ret `T.shouldBe` [val2,val2,val5,val3]
, ret `T.shouldBe` [val2,val4,val2,val3]
, ret `T.shouldBe` [val2,val5,val2,val4]
, ret `T.shouldBe` [val2,val4,val5,val2]
, ret `T.shouldBe` [val2,val5,val3,val2]
]
T.whenWVarIsFreshButCacheStaled $ \ prepare -> do
HS.prop "takes the value before or after putWCached" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
wt <- WV.takeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ WV.readWTicket wt `T.shouldBe` val1
, WV.readWTicket wt `T.shouldBe` val2
]
HS.prop "take different value" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2, val3, val4] <- T.genSatisfy 3 (/= val1)
ret <- fmap WV.readWTicket <$> T.mapConcurrently
[ WV.takeWCached wc <* WV.putWCached wc val2
, WV.takeWCached wc <* WV.putWCached wc val3
, WV.takeWCached wc <* WV.putWCached wc val4
]
T.oneOf
[ ret `T.shouldBe` [val1,val2,val3]
, ret `T.shouldBe` [val1,val4,val2]
, ret `T.shouldBe` [val3,val1,val2]
, ret `T.shouldBe` [val4,val1,val3]
, ret `T.shouldBe` [val3,val4,val1]
, ret `T.shouldBe` [val4,val2,val1]
]
T.whenWVarIsUpdatingAndCacheStaled $ \ prepare -> do
HS.prop "takes the value after putWCached" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.takeWCached wc
WV.readWTicket ret `T.shouldBe` val2
HS.prop "take different value" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2, val3, val4, val5] <- T.genSatisfy 4 (/= val1)
ret <- T.mapConcurrently
[ WV.putWCached wc val2 >> return val2
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val3
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val4
, WV.readWTicket <$> WV.takeWCached wc <* WV.putWCached wc val5
]
T.oneOf
[ ret `T.shouldBe` [val2,val2,val3,val4]
, ret `T.shouldBe` [val2,val2,val5,val3]
, ret `T.shouldBe` [val2,val4,val2,val3]
, ret `T.shouldBe` [val2,val5,val2,val4]
, ret `T.shouldBe` [val2,val4,val5,val2]
, ret `T.shouldBe` [val2,val5,val3,val2]
]
tryTakeWCachedSeqSpec :: HS.Spec
tryTakeWCachedSeqSpec = HS.describe "tryTakeWCached" $ do
T.whenWVarIsFresh . T.withLatestCache $ \ prepare -> do
HS.prop "takes the value before(failure)/after(success) putWCached" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
(ret, wt) <- WV.tryTakeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ (ret, WV.readWTicket wt) `T.shouldBe` (True, val1)
, (ret, WV.readWTicket wt) `T.shouldBe` (False, val2)
]
HS.prop "all read same value but only one succeeded" $ do
(_, val1 :: Int, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryTakeWCached wc
, WV.tryTakeWCached wc
, WV.tryTakeWCached wc
]
T.oneOf
[ ret `T.shouldBe` [(True,val1),(False,val1),(False,val1)]
, ret `T.shouldBe` [(False,val1),(True,val1),(False,val1)]
, ret `T.shouldBe` [(False,val1),(False,val1),(True,val1)]
]
T.whenWVarIsUpdating . T.withLatestCache $ \ prepare -> do
HS.prop "takes the value before or after putWCached with failure" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
(ret, wt) <- WV.tryTakeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ (ret, WV.readWTicket wt) `T.shouldBe` (False, val1)
, (ret, WV.readWTicket wt) `T.shouldBe` (False, val2)
]
HS.prop "all read same value and fail" $ do
(_, val1 :: Int, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryTakeWCached wc
, WV.tryTakeWCached wc
, WV.tryTakeWCached wc
]
ret `T.shouldBe` [(False,val1),(False,val1),(False,val1)]
T.whenWVarIsFreshButCacheStaled $ \ prepare -> do
HS.prop "takes the value before or after putWCached with failure" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
(ret, wt) <- WV.tryTakeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ (ret, WV.readWTicket wt) `T.shouldBe` (False, val1)
, (ret, WV.readWTicket wt) `T.shouldBe` (False, val2)
]
HS.prop "all read same value and fail" $ do
(_, val1 :: Int, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryTakeWCached wc
, WV.tryTakeWCached wc
, WV.tryTakeWCached wc
]
ret `T.shouldBe` [(False,val1),(False,val1),(False,val1)]
T.whenWVarIsUpdatingAndCacheStaled $ \ prepare -> do
HS.prop "takes the value before or after putWCached with failure" $ do
(_, val1 :: Int, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
(ret, wt) <- WV.tryTakeWCached wc `T.shouldNotBlock` 500000
T.oneOf
[ (ret, WV.readWTicket wt) `T.shouldBe` (False, val1)
, (ret, WV.readWTicket wt) `T.shouldBe` (False, val2)
]
HS.prop "all read same value and fail" $ do
(_, val1 :: Int, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryTakeWCached wc
, WV.tryTakeWCached wc
, WV.tryTakeWCached wc
]
ret `T.shouldBe` [(False,val1),(False,val1),(False,val1)]
readFreshWCachedSeqSpec :: HS.Spec
readFreshWCachedSeqSpec = HS.describe "readFreshWCached" $ do
T.whenWVarIsFresh . T.withLatestCache $ \ prepare -> do
HS.prop "reads the value before or after putWCached" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
wt <- WV.readFreshWCached wc `T.shouldNotBlock` 500000
WV.readWTicket wt `T.shouldBe` val1
HS.prop "read same value" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap WV.readWTicket <$> T.mapConcurrently
[ WV.readFreshWCached wc
, WV.readFreshWCached wc
, WV.readFreshWCached wc
]
ret `T.shouldBe` [val1,val1,val1]
T.whenWVarIsUpdating . T.withLatestCache $ \ prepare -> do
HS.prop "reads the value after putWCached" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
wt <- WV.readFreshWCached wc
WV.readWTicket wt `T.shouldBe` val2
HS.prop "read same value" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
ret <- T.mapConcurrently
[ WV.putWCached wc val2 >> return val2
, WV.readWTicket <$> WV.readFreshWCached wc
, WV.readWTicket <$> WV.readFreshWCached wc
, WV.readWTicket <$> WV.readFreshWCached wc
]
ret `T.shouldBe` [val2,val2,val2,val2]
T.whenWVarIsFreshButCacheStaled $ \ prepare -> do
HS.prop "reads the value before or after putWCached" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
wt <- WV.readFreshWCached wc `T.shouldNotBlock` 500000
WV.readWTicket wt `T.shouldBe` val1
HS.prop "read same value" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap WV.readWTicket <$> T.mapConcurrently
[ WV.readFreshWCached wc
, WV.readFreshWCached wc
, WV.readFreshWCached wc
]
ret `T.shouldBe` [val1,val1,val1]
T.whenWVarIsUpdatingAndCacheStaled $ \ prepare -> do
HS.prop "reads the value after putWCached" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.readWTicket <$> WV.readFreshWCached wc
ret `T.shouldBe` val1
HS.prop "read same value" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
ret <- T.mapConcurrently
[ WV.putWCached wc val2 >> return val2
, WV.readWTicket <$> WV.readFreshWCached wc
, WV.readWTicket <$> WV.readFreshWCached wc
, WV.readWTicket <$> WV.readFreshWCached wc
]
ret `T.shouldBe` [val2,val1,val1,val1]
tryReadFreshWCachedSeqSpec :: HS.Spec
tryReadFreshWCachedSeqSpec = HS.describe "tryReadWCached" $ do
T.whenWVarIsFresh . T.withLatestCache $ \ prepare -> do
HS.prop "reads the old value and succeed" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.tryReadFreshWCached wc `T.shouldNotBlock` 500000
fmap WV.readWTicket ret `T.shouldBe` (True, val1)
HS.prop "all read same value and succeed" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
]
ret `T.shouldBe` [(True,val1),(True,val1),(True,val1)]
T.whenWVarIsUpdating . T.withLatestCache $ \ prepare -> do
HS.prop "reads the old value and fail" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.tryReadFreshWCached wc `T.shouldNotBlock` 500000
fmap WV.readWTicket ret `T.shouldBe` (False, val1)
HS.prop "all read same value and fail" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
]
ret `T.shouldBe` [(False,val1),(False,val1),(False,val1)]
T.whenWVarIsFreshButCacheStaled $ \ prepare -> do
HS.prop "reads the old value and succeed" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.tryReadFreshWCached wc `T.shouldNotBlock` 500000
fmap WV.readWTicket ret `T.shouldBe` (True, val1)
HS.prop "all read same value and succeed" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
]
ret `T.shouldBe` [(True,val1),(True,val1),(True,val1)]
T.whenWVarIsUpdating . T.withLatestCache $ \ prepare -> do
HS.prop "reads the old value and fail" $ do
(val1 :: Int, _, _, wc) <- prepare
[val2] <- T.genSatisfy 1 (/= val1)
M.void $ WV.putWCached wc val2 `T.concurrently` do
ret <- WV.tryReadFreshWCached wc `T.shouldNotBlock` 500000
fmap WV.readWTicket ret `T.shouldBe` (False, val1)
HS.prop "all read same value and fail" $ do
(val1 :: Int, _, _, wc) <- prepare
ret <- fmap (fmap WV.readWTicket) <$> T.mapConcurrently
[ WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
, WV.tryReadFreshWCached wc
]
ret `T.shouldBe` [(False,val1),(False,val1),(False,val1)]
tryTakeAndPutCachedSeqSpec :: HS.Spec
tryTakeAndPutCachedSeqSpec =
HS.prop "tryTakeWCached and putWCached perform atomic modification" $ do
wv <- WV.newWVar (0 :: Int)
wc <- WV.cacheWVar wv
ret <- L.sort . L.concat <$> T.mapConcurrently (countConc10 wc)
ret `T.shouldBe` [1..1000]
where
countConc10 wc = L.replicate 10 $ count100 wc
count100 wc = M.replicateM 100 $ countOne wc
countOne wc = do
(suc, wt1) <- WV.tryTakeWCached wc
let val = WV.readWTicket wt1
if suc
then do
wt2 <- WV.putWCached wc $ val + 1
return $ WV.readWTicket wt2
else do
wt2 <- WV.readFreshWCached wc { WV.cachedTicket = wt1 }
countOne wc { WV.cachedTicket = wt2 }
wvarSpec :: HS.Spec
wvarSpec = do
takeWVarSeqSpec
tryTakeWVarSeqSpec
readFreshWVarSeqSpec
tryReadFreshWVarSeqSpec
wcachedSpec :: HS.Spec
wcachedSpec = do
takeWCachedSeqSpec
tryTakeWCachedSeqSpec
readFreshWCachedSeqSpec
tryReadFreshWCachedSeqSpec
spec :: HS.Spec
spec = HS.describe "WVar concurrent specs" $ do
HS.describe "WVar" wvarSpec
HS.describe "WCached" wcachedSpec
HS.describe "combination" tryTakeAndPutCachedSeqSpec