haskell-bee-tests-0.1.0.0: tests/Test/Integration/Broker.hs
{-|
Generic Broker tests. All brokers should satisfy them.
-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Test.Integration.Broker
( Message(..)
, brokerTests )
where
import Async.Worker.Broker.Types qualified as BT
import Control.Exception (bracket)
import Data.Aeson (ToJSON(..), FromJSON(..), withText)
import Data.Maybe (isJust)
import Data.Text qualified as T
import Test.Hspec
import Test.Integration.Utils (randomQueueName, waitUntil)
import Test.RandomStrings (randomASCII, randomString, onlyAlphaNum)
data TestEnv b =
TestEnv { broker :: BT.Broker b Message
, queue :: BT.Queue }
testQueuePrefix :: BT.Queue
testQueuePrefix = "test_broker"
data Message =
Message { text :: String }
deriving (Show, Eq)
instance ToJSON Message where
toJSON (Message { text }) = toJSON text
instance FromJSON Message where
parseJSON = withText "Message" $ \text -> do
pure $ Message { text = T.unpack text }
withBroker :: (BT.MessageBroker b Message)
=> BT.BrokerInitParams b Message
-> (TestEnv b -> IO ())
-> IO ()
withBroker bInitParams = bracket (setUpBroker bInitParams) tearDownBroker
where
-- NOTE I need to pass 'b' again, otherwise GHC can't infer the
-- type of 'b' (even with 'ScopedTypeVariables' turned on)
setUpBroker :: (BT.MessageBroker b Message)
=> BT.BrokerInitParams b Message -> IO (TestEnv b)
setUpBroker bInit = do
b <- BT.initBroker bInit
queue <- randomQueueName testQueuePrefix
BT.dropQueue b queue
BT.createQueue b queue
return $ TestEnv { broker = b
, queue }
tearDownBroker (TestEnv { broker, queue }) = do
BT.dropQueue broker queue
BT.deinitBroker broker
brokerTests :: (BT.MessageBroker b Message)
=> BT.BrokerInitParams b Message -> Spec
brokerTests bInitParams =
parallel $ around (withBroker bInitParams) $ describe "Broker tests" $ do
it "can send and receive a message" $ \(TestEnv { broker, queue }) -> do
let msg = Message { text = "test" }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
msg2 <- BT.readMessageWaiting broker queue
-- putStrLn $ "[messageId] " <> show (BT.messageId msg2)
msg `shouldBe` BT.toA (BT.getMessage msg2)
msgId `shouldBe` BT.messageId msg2
it "can send, archive and read message from archive" $ \(TestEnv { broker, queue }) -> do
let msg = Message { text = "test" }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
msg2 <- BT.readMessageWaiting broker queue
msgId `shouldBe` BT.messageId msg2
BT.archiveMessage broker queue msgId
-- It might take some time to archive a message so we wait a bit
waitUntil (isJust <$> BT.getArchivedMessage broker queue msgId) 200
msgArchive <- BT.getArchivedMessage broker queue msgId
let msgIdArchive = BT.messageId <$> msgArchive
msgIdArchive `shouldBe` Just msgId
it "returns correct message id when sending message to broker" $ \(TestEnv { broker, queue }) -> do
let iter = [1..20] :: [Int] -- number of steps
mapM_ (\_i -> do
-- Generate random strings and make sure that the
-- message ids we get from sendMessage match our data
text <- randomString (onlyAlphaNum randomASCII) 20
let msg = Message { text }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
bMsg <- BT.readMessageWaiting broker queue
msg `shouldBe` BT.toA (BT.getMessage bMsg)
msgId `shouldBe` BT.messageId bMsg
BT.deleteMessage broker queue msgId
) iter
it "preserves msgId when archiving a message" $ \(TestEnv { broker, queue }) -> do
let iter = [1..20] :: [Int] -- number of steps
mapM_ (\_i -> do
-- Generate random strings and make sure that the
-- message ids we get from sendMessage match our data
text <- randomString (onlyAlphaNum randomASCII) 20
let msg = Message { text }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
BT.archiveMessage broker queue msgId
msgArchive <- BT.getArchivedMessage broker queue msgId
Just msg `shouldBe` (BT.toA . BT.getMessage <$> msgArchive)
) iter
it "returns the same size of pending messages as 'getQueueSize'" $ \(TestEnv { broker, queue }) -> do
let numSteps = 20 :: Int
let iter = [1..numSteps] :: [Int] -- number of steps
mapM_ (\i -> do
-- Generate random strings and make sure that the
-- message ids we get from sendMessage match our data
text <- randomString (onlyAlphaNum randomASCII) 20
let msg = Message { text }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
qs <- BT.getQueueSize broker queue
qs `shouldBe` i
msgIds <- BT.listPendingMessageIds broker queue
length msgIds `shouldBe` qs
msgIds `shouldSatisfy` (elem msgId)
) iter
msgIds <- BT.listPendingMessageIds broker queue
let timeoutS = 10 -- some large enough value
-- after message timeout is set, it shouldn't be counted
mapM_ (\msgId -> do
BT.setMessageTimeout broker queue msgId timeoutS
msgIds' <- BT.listPendingMessageIds broker queue
msgIds' `shouldSatisfy` (not . elem msgId)
) msgIds
-- queue should be "empty" since all messages are timed out
qs <- BT.getQueueSize broker queue
qs `shouldBe` 0
it "can get message by it's id (from queue)" $ \(TestEnv { broker, queue }) -> do
text <- randomString (onlyAlphaNum randomASCII) 20
let msg = Message { text }
msgId <- BT.sendMessage broker queue (BT.toMessage msg)
mMsg <- BT.getMessageById broker queue msgId
(BT.toA . BT.getMessage <$> mMsg) `shouldBe` (Just msg)