{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}

module Test.Syd.AMQP
  ( amqpSpec,
    amqpConnectionSetupFunc,
  )
where

import Network.AMQP as AMQP
import Test.Syd
import Test.Syd.RabbitMQ

-- | Run a rabbitmq server around a group of test, and provide a clean connection to each individual test
--
-- Example usage
--
-- > spec :: Spec
-- > spec =
-- >   describe "amqpSpec" $ do
-- >     it "can write and read a message" $ \conn -> do
-- >       chan <- openChannel conn
-- >
-- >       -- declare a queue, exchange and binding
-- >       _ <- declareQueue chan newQueue {queueName = "myQueue"}
-- >       declareExchange chan newExchange {exchangeName = "myExchange", exchangeType = "direct"}
-- >       bindQueue chan "myQueue" "myExchange" "myKey"
-- >
-- >       -- publish a message to our new exchange
-- >       let body = "hello world"
-- >       _ <-
-- >         publishMsg
-- >           chan
-- >           "myExchange"
-- >           "myKey"
-- >           newMsg
-- >             { msgBody = body,
-- >               msgDeliveryMode = Just Persistent
-- >             }
-- >
-- >       mMesg <- getMsg chan Ack "myQueue"
-- >       case mMesg of
-- >         Nothing -> expectationFailure "Should have received a message"
-- >         Just (m, e) -> do
-- >           msgBody m `shouldBe` body
-- >           ackEnv e
amqpSpec :: TestDefM (RabbitMQHandle ': outers) AMQP.Connection result -> TestDefM outers inner result
amqpSpec :: TestDefM (RabbitMQHandle : outers) Connection result
-> TestDefM outers inner result
amqpSpec = TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM outers inner result
forall (outers :: [*]) inner result.
TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM outers inner result
rabbitMQSpec (TestDefM (RabbitMQHandle : outers) inner result
 -> TestDefM outers inner result)
-> (TestDefM (RabbitMQHandle : outers) Connection result
    -> TestDefM (RabbitMQHandle : outers) inner result)
-> TestDefM (RabbitMQHandle : outers) Connection result
-> TestDefM outers inner result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (RabbitMQHandle -> inner -> SetupFunc Connection)
-> TestDefM (RabbitMQHandle : outers) Connection result
-> TestDefM (RabbitMQHandle : outers) inner result
forall (outers :: [*]) outer oldInner newInner result.
HContains outers outer =>
(outer -> oldInner -> SetupFunc newInner)
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
setupAroundWith' (\RabbitMQHandle
serverHandle inner
_ -> RabbitMQHandle -> SetupFunc Connection
amqpConnectionSetupFunc RabbitMQHandle
serverHandle)

-- | Setup function for a connection to a given rabbitmq server
amqpConnectionSetupFunc :: RabbitMQHandle -> SetupFunc Connection
amqpConnectionSetupFunc :: RabbitMQHandle -> SetupFunc Connection
amqpConnectionSetupFunc RabbitMQHandle
h = do
  let opts :: ConnectionOpts
opts = ConnectionOpts
defaultConnectionOpts {coServers :: [(String, PortNumber)]
coServers = [(String
"localhost", RabbitMQHandle -> PortNumber
rabbitMQHandlePort RabbitMQHandle
h)]}
  let acquire :: IO Connection
acquire = ConnectionOpts -> IO Connection
openConnection'' ConnectionOpts
opts
  let release :: Connection -> IO ()
release = Connection -> IO ()
closeConnection
  IO Connection -> (Connection -> IO ()) -> SetupFunc Connection
forall resource r.
IO resource -> (resource -> IO r) -> SetupFunc resource
bracketSetupFunc IO Connection
acquire Connection -> IO ()
release