packages feed

lazy-cache-0.2.0.0: test/Cheops/Cache/CacheSpec.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NumericUnderscores #-}
module Cheops.Cache.CacheSpec where

import Control.Exception
import Data.IORef
import System.Clock.Seconds
import Data.Hashable
import Test.Hspec
import Test.HUnit.Base               ((@=?))

import qualified System.Cache                  as Cache
import qualified System.Cache.Impl.Ghc         as Ghc
import qualified System.Cache.Impl.MVar        as MVar
import System.Cache.Internal.Interface as Cache

spec :: Spec
spec = do
  describe "GHC"  $ inner (Ghc.new)
  describe "MVar" $ inner (MVar.new)

inner :: (forall a b . (Show a, Hashable a, Ord a) => Cache.Config -> IO (Cache.Handle a b)) -> Spec
inner new = describe "Cache service" $ do
  let configClock = Monotonic
  let configLongestAge = fromNanoSecs (100 * 1_000_000_000)
  it "cache store values" $ do
    ch <- new Cache.Config{..}
    ir <- newIORef True
    let
      f _ = do
        firstTime <- readIORef ir
        if firstTime then writeIORef ir False >> pure 0 else pure 1
    ((0 :: Int) @=?) =<< Cache.requestOr ch () f
    ((0 :: Int) @=?) =<< Cache.requestOr ch () f
  it "honour input" $ do
    ch <- new Cache.Config{..}
    let f x = pure x
    ((3 :: Int) @=?) =<< Cache.requestOr ch 3 f
    ((4 :: Int) @=?) =<< Cache.requestOr ch 4 f
    ((3 :: Int) @=?) =<< Cache.requestOr ch 3 f
  it "drops caches" $ do
    ch <- new Cache.Config{ configLongestAge = fromNanoSecs 0, ..}
    ir <- newIORef True
    let
      f _ = do
        firstTime <- readIORef ir
        if firstTime then writeIORef ir False >> pure 0 else pure 1
    ((0 :: Int) @=?)
      =<< Cache.requestOrInternal ch (fromNanoSecs (0)) () f
    ((1 :: Int) @=?)
      =<< Cache.requestOrInternal ch (fromNanoSecs (2 * 1_000_000_000)) () f
  it "handles exceptions" $ do
    ch <- new Cache.Config{..} :: IO (Cache.Handle Int Int)
    ((Left (ErrorCall "foo")) @=?) =<<
       either (\(ErrorCallWithLocation s _) -> Left (ErrorCall s)) Right
         <$> try (Cache.requestOr ch (3::Int) (\_ -> error "foo"))
    -- second call is still ok
    ((Left (ErrorCall "bar")) @=?) =<<
       either (\(ErrorCallWithLocation s _) -> Left (ErrorCall s)) Right
         <$> try (Cache.requestOr ch (3::Int) (\_ -> error "bar"))
    (Right 4 @=?) =<<
       either (\(ErrorCallWithLocation s _) -> Left (ErrorCall s)) Right
         <$> try (Cache.requestOr ch (3::Int) (\_ -> pure 4))