hasql-queue-1.2.0.0: test/Hasql/Queue/High/AtLeastOnceSpec.hs
module Hasql.Queue.High.AtLeastOnceSpec where
import Hasql.Queue.High.AtLeastOnce
import qualified Hasql.Encoders as E
import qualified Hasql.Decoders as D
import Test.Hspec (Spec, describe, parallel, it)
import Test.Hspec.Expectations.Lifted
import Test.Hspec.Core.Spec (sequential)
import Hasql.Queue.TestUtils
import qualified Hasql.Queue.Internal as I
import Control.Exception as E
import Hasql.Connection
import Data.Typeable
import Data.IORef
import Control.Monad
data FailedwithDequeue = FailedwithDequeue
deriving (Show, Eq, Typeable)
instance Exception FailedwithDequeue
getPayload :: Connection -> D.Value a -> I.PayloadId -> IO (Maybe (I.Payload a))
getPayload conn decoder payloadId = I.runThrow (I.getPayload decoder payloadId) conn
spec :: Spec
spec = describe "Hasql.Queue.High.AtLeastOnce" $ parallel $ do
sequential $ aroundAll withSetup $ describe "enqueue/dequeue" $ do
it "enqueue nothing gives nothing" $ withConnection $ \conn -> do
enqueue conn E.int4 []
withDequeue conn D.int4 1 1 pure `shouldReturn` Nothing
it "enqueue 1 gives 1" $ withConnection $ \conn -> do
enqueue conn E.int4 [1]
withDequeue conn D.int4 1 1 pure `shouldReturn` Just [1]
it "dequeue give nothing after enqueueing everything" $ withConnection $ \conn -> do
withDequeue conn D.int4 1 1 pure `shouldReturn` Nothing
it "dequeueing is in FIFO order" $ withConnection $ \conn -> do
enqueue conn E.int4 [1]
enqueue conn E.int4 [2]
withDequeue conn D.int4 1 1 pure `shouldReturn` Just [1]
withDequeue conn D.int4 1 1 pure `shouldReturn` Just [2]
it "dequeueing a batch of elements works" $ withConnection $ \conn -> do
enqueue conn E.int4 [1, 2, 3]
withDequeue conn D.int4 1 2 pure `shouldReturn` Just [1, 2]
withDequeue conn D.int4 1 2 pure `shouldReturn` Just [3]
it "withDequeue fails if a non IOError is thrown" $ withConnection $ \conn -> do
enqueue conn E.int4 [1]
handle (\FailedwithDequeue -> pure Nothing) $
withDequeue conn D.int4 2 1 $ \_ -> throwIO FailedwithDequeue
failures conn D.int4 Nothing 1 `shouldReturn` []
withDequeue conn D.int4 0 1 pure `shouldReturn` Just [1]
it "withDequeue fails if throws occur and retry is zero" $ withConnection $ \conn -> do
enqueue conn E.int4 [1]
handle (\(_ :: IOError) -> pure Nothing) $
withDequeue conn D.int4 0 1 $ \_ -> throwIO $ userError "hey"
[(pId, x)] <- failures conn D.int4 Nothing 1
x `shouldBe` 1
delete conn [pId]
it "withDequeue succeeds even if the first attempt fails" $ withConnection $ \conn -> do
enqueue conn E.int4 [1]
ref <- newIORef (0 :: Int)
withDequeue conn D.int4 1 1 (\_ -> do
count <- readIORef ref
writeIORef ref $ count + 1
when (count < 1) $ throwIO $ userError "hey"
pure '!') `shouldReturn` Just '!'
withDequeue conn D.int4 1 1 pure `shouldReturn` Nothing
readIORef ref `shouldReturn` 2
it "failures paging works" $ withConnection $ \conn -> do
enqueue conn E.int4 [2]
enqueue conn E.int4 [3]
handle (\(_ :: IOError) -> pure Nothing) $
withDequeue conn D.int4 0 1 $ \_ -> throwIO $ userError "fds"
handle (\(_ :: IOError) -> pure Nothing) $
withDequeue conn D.int4 0 1 $ \_ -> throwIO $ userError "fds"
[(next, x)] <- failures conn D.int4 Nothing 1
x `shouldBe` 2
fmap (fmap snd) (failures conn D.int4 (Just next) 2) `shouldReturn` [3]