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

module Test.Syd.RabbitMQ
  ( RabbitMQHandle (..),
    rabbitMQSpec,
    rabbitMQServerSetupFunc,
    rabbitMQServerSetupFunc',
    cleanRabbitMQStateBeforeEach,
    cleanRabbitMQState,
  )
where

import Control.Monad
import Data.Aeson as JSON
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic)
import Network.Socket
import Network.Socket.Free
import qualified Network.Socket.Wait as Socket
import Path
import Path.IO
import System.Environment (getEnvironment)
import System.Exit
import System.IO
import System.Process.Typed
import Test.Syd
import Test.Syd.Path
import Test.Syd.Process.Typed

data RabbitMQHandle = RabbitMQHandle
  { RabbitMQHandle -> Process () Handle Handle
rabbitMQHandleProcessHandle :: !(Process () Handle Handle),
    RabbitMQHandle -> PortNumber
rabbitMQHandlePort :: !PortNumber
  }

-- | Run a rabbitmq server around a group of tests.
--
-- Example usage:
--
-- > rabbitMQSpec $ do
-- >   describe "rabbitMQSpec" $
-- >     it "can run the server and clean up nicely" $ do
-- >       pure () :: IO ()
--
-- (You will probably want to use `sydtest-amqp` or `sydtest-amqp-client`
-- instead of directly using this package.)
--
-- This function also cleans up the rabbitmq state before every test.
-- Consequently, it also uses @modifyMaxSuccess (`div` 20)@ to decrease the
-- number of property tests that will be run, because the state cleaning takes
-- a long time.
rabbitMQSpec :: TestDefM (RabbitMQHandle ': outers) inner result -> TestDefM outers inner result
rabbitMQSpec :: TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM outers inner result
rabbitMQSpec =
  SetupFunc RabbitMQHandle
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM outers inner result
forall outer (outers :: [*]) inner result.
SetupFunc outer
-> TestDefM (outer : outers) inner result
-> TestDefM outers inner result
setupAroundAll SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc
    (TestDefM (RabbitMQHandle : outers) inner result
 -> TestDefM outers inner result)
-> (TestDefM (RabbitMQHandle : outers) inner result
    -> TestDefM (RabbitMQHandle : outers) inner result)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM outers inner result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall (a :: [*]) b c. TestDefM a b c -> TestDefM a b c
sequential -- Must run sequentially because state is shared.
    (TestDefM (RabbitMQHandle : outers) inner result
 -> TestDefM (RabbitMQHandle : outers) inner result)
-> (TestDefM (RabbitMQHandle : outers) inner result
    -> TestDefM (RabbitMQHandle : outers) inner result)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall (outers :: [*]) inner result.
TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
cleanRabbitMQStateBeforeEach
    (TestDefM (RabbitMQHandle : outers) inner result
 -> TestDefM (RabbitMQHandle : outers) inner result)
-> (TestDefM (RabbitMQHandle : outers) inner result
    -> TestDefM (RabbitMQHandle : outers) inner result)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Int -> Int)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall (a :: [*]) b c.
(Int -> Int) -> TestDefM a b c -> TestDefM a b c
modifyMaxSuccess (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
20)

-- | Set up a rabbitmq server in a temporary directory.
rabbitMQServerSetupFunc :: SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc :: SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc = do
  Path Abs Dir
td <- String -> SetupFunc (Path Abs Dir)
tempDirSetupFunc String
"sydtest-amqp"
  Path Abs Dir -> SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc' Path Abs Dir
td

-- | Set up a rabbitmq server in the given directory
rabbitMQServerSetupFunc' :: Path Abs Dir -> SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc' :: Path Abs Dir -> SetupFunc RabbitMQHandle
rabbitMQServerSetupFunc' Path Abs Dir
td = do
  Path Abs File
pidFile <- Path Abs Dir -> String -> SetupFunc (Path Abs File)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs File)
resolveFile Path Abs Dir
td String
"rabbitmq.pid"
  Path Abs File
configFile <- Path Abs Dir -> String -> SetupFunc (Path Abs File)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs File)
resolveFile Path Abs Dir
td String
"rabbitmq.conf"
  Path Abs Dir
mnesiaDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"mnesia"
  Path Abs Dir
schemaDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"schema"
  Path Abs Dir
pluginsDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"plugins"
  Path Abs Dir
pluginsExpandDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"plugins-expand"
  Path Abs Dir
generatedConfigDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"generated-config"
  Path Abs Dir
logDir <- Path Abs Dir -> String -> SetupFunc (Path Abs Dir)
forall (m :: * -> *).
MonadIO m =>
Path Abs Dir -> String -> m (Path Abs Dir)
resolveDir Path Abs Dir
td String
"log"
  Path Abs Dir -> SetupFunc ()
forall (m :: * -> *) b. MonadIO m => Path b Dir -> m ()
ensureDir Path Abs Dir
logDir
  let getFreePort_ :: IO Int
getFreePort_ = IO Int -> IO Int
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Int -> IO Int) -> IO Int -> IO Int
forall a b. (a -> b) -> a -> b
$ do
        (Int
portInt, Socket
_socket) <- IO (Int, Socket)
openFreePort
        Socket -> IO ()
close Socket
_socket
        Int -> IO Int
forall (f :: * -> *) a. Applicative f => a -> f a
pure Int
portInt
  Int
portInt <- IO Int -> SetupFunc Int
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Int
getFreePort_
  Int
distPortInt <- IO Int -> SetupFunc Int
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO Int
getFreePort_
  [(String, String)]
oldEnv <- IO [(String, String)] -> SetupFunc [(String, String)]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO [(String, String)]
getEnvironment -- We may not want to leak all of this in?
  let e :: [(String, String)]
e =
        [ (String
"RABBITMQ_BASE", Path Abs Dir -> String
fromAbsDir Path Abs Dir
td),
          (String
"RABBITMQ_PID_FILE", Path Abs File -> String
fromAbsFile Path Abs File
pidFile),
          (String
"RABBITMQ_CONFIG_FILE", Path Abs File -> String
fromAbsFile Path Abs File
configFile),
          (String
"RABBITMQ_MNESIA_DIR", Path Abs Dir -> String
fromAbsDir Path Abs Dir
mnesiaDir),
          (String
"RABBITMQ_MNESIA_BASE", Path Abs Dir -> String
fromAbsDir Path Abs Dir
mnesiaDir), -- Just to be sure
          (String
"RABBITMQ_SCHEMA_DIR", Path Abs Dir -> String
fromAbsDir Path Abs Dir
schemaDir),
          (String
"RABBITMQ_PLUGINS_DIR", Path Abs Dir -> String
fromAbsDir Path Abs Dir
pluginsDir),
          (String
"RABBITMQ_PLUGINS_EXPAND_DIR", Path Abs Dir -> String
fromAbsDir Path Abs Dir
pluginsExpandDir),
          (String
"RABBITMQ_GENERATED_CONFIG_DIR", Path Abs Dir -> String
fromAbsDir Path Abs Dir
generatedConfigDir),
          (String
"RABBITMQ_LOG_BASE", Path Abs Dir -> String
fromAbsDir Path Abs Dir
logDir),
          (String
"RABBITMQ_LOGS", Path Abs Dir -> String
fromAbsDir Path Abs Dir
logDir), -- Just to be sure
          (String
"RABBITMQ_NODE_PORT", Int -> String
forall a. Show a => a -> String
show Int
portInt),
          (String
"RABBITMQ_DIST_PORT", Int -> String
forall a. Show a => a -> String
show Int
distPortInt)
        ]
          [(String, String)] -> [(String, String)] -> [(String, String)]
forall a. [a] -> [a] -> [a]
++ [(String, String)]
oldEnv
  let pc :: ProcessConfig () Handle Handle
pc = String
-> ProcessConfig () Handle Handle -> ProcessConfig () Handle Handle
forall stdin stdout stderr.
String
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setWorkingDir (Path Abs Dir -> String
fromAbsDir Path Abs Dir
td) (ProcessConfig () Handle Handle -> ProcessConfig () Handle Handle)
-> ProcessConfig () Handle Handle -> ProcessConfig () Handle Handle
forall a b. (a -> b) -> a -> b
$ StreamSpec 'STOutput Handle
-> ProcessConfig () () Handle -> ProcessConfig () Handle Handle
forall stdout stdin stdout0 stderr.
StreamSpec 'STOutput stdout
-> ProcessConfig stdin stdout0 stderr
-> ProcessConfig stdin stdout stderr
setStdout StreamSpec 'STOutput Handle
forall (anyStreamType :: StreamType).
StreamSpec anyStreamType Handle
createPipe (ProcessConfig () () Handle -> ProcessConfig () Handle Handle)
-> ProcessConfig () () Handle -> ProcessConfig () Handle Handle
forall a b. (a -> b) -> a -> b
$ StreamSpec 'STOutput Handle
-> ProcessConfig () () () -> ProcessConfig () () Handle
forall stderr stdin stdout stderr0.
StreamSpec 'STOutput stderr
-> ProcessConfig stdin stdout stderr0
-> ProcessConfig stdin stdout stderr
setStderr StreamSpec 'STOutput Handle
forall (anyStreamType :: StreamType).
StreamSpec anyStreamType Handle
createPipe (ProcessConfig () () () -> ProcessConfig () () Handle)
-> ProcessConfig () () () -> ProcessConfig () () Handle
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> ProcessConfig () () () -> ProcessConfig () () ()
forall stdin stdout stderr.
[(String, String)]
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setEnv [(String, String)]
e (ProcessConfig () () () -> ProcessConfig () () ())
-> ProcessConfig () () () -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String -> [String] -> ProcessConfig () () ()
proc String
"rabbitmq-server" []
  Process () Handle Handle
ph <- ProcessConfig () Handle Handle
-> SetupFunc (Process () Handle Handle)
forall stdin stdout stderr.
ProcessConfig stdin stdout stderr
-> SetupFunc (Process stdin stdout stderr)
typedProcessSetupFunc ProcessConfig () Handle Handle
pc
  IO () -> SetupFunc ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> SetupFunc ()) -> IO () -> SetupFunc ()
forall a b. (a -> b) -> a -> b
$ String -> Int -> IO ()
Socket.wait String
"127.0.0.1" Int
portInt
  let pn :: PortNumber
pn = Int -> PortNumber
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
portInt -- (hopefully) safe because it came from 'getFreePort'.
  RabbitMQHandle -> SetupFunc RabbitMQHandle
forall (f :: * -> *) a. Applicative f => a -> f a
pure (RabbitMQHandle -> SetupFunc RabbitMQHandle)
-> RabbitMQHandle -> SetupFunc RabbitMQHandle
forall a b. (a -> b) -> a -> b
$
    RabbitMQHandle :: Process () Handle Handle -> PortNumber -> RabbitMQHandle
RabbitMQHandle
      { rabbitMQHandleProcessHandle :: Process () Handle Handle
rabbitMQHandleProcessHandle = Process () Handle Handle
ph,
        rabbitMQHandlePort :: PortNumber
rabbitMQHandlePort = PortNumber
pn
      }

cleanRabbitMQStateBeforeEach :: TestDefM (RabbitMQHandle ': outers) inner result -> TestDefM (RabbitMQHandle ': outers) inner result
cleanRabbitMQStateBeforeEach :: TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
cleanRabbitMQStateBeforeEach =
  (RabbitMQHandle -> inner -> IO inner)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall (outers :: [*]) outer oldInner newInner result.
HContains outers outer =>
(outer -> oldInner -> IO newInner)
-> TestDefM outers newInner result
-> TestDefM outers oldInner result
beforeWith' ((RabbitMQHandle -> inner -> IO inner)
 -> TestDefM (RabbitMQHandle : outers) inner result
 -> TestDefM (RabbitMQHandle : outers) inner result)
-> (RabbitMQHandle -> inner -> IO inner)
-> TestDefM (RabbitMQHandle : outers) inner result
-> TestDefM (RabbitMQHandle : outers) inner result
forall a b. (a -> b) -> a -> b
$ \RabbitMQHandle
handle inner
inner -> do
    RabbitMQHandle -> IO ()
cleanRabbitMQState RabbitMQHandle
handle
    inner -> IO inner
forall (f :: * -> *) a. Applicative f => a -> f a
pure inner
inner

-- FIXME: I'd prefer if there was a less-external way to do this, but oh well :s
cleanRabbitMQState :: RabbitMQHandle -> IO ()
cleanRabbitMQState :: RabbitMQHandle -> IO ()
cleanRabbitMQState RabbitMQHandle {PortNumber
Process () Handle Handle
rabbitMQHandlePort :: PortNumber
rabbitMQHandleProcessHandle :: Process () Handle Handle
rabbitMQHandlePort :: RabbitMQHandle -> PortNumber
rabbitMQHandleProcessHandle :: RabbitMQHandle -> Process () Handle Handle
..} = do
  [(String, String)]
oldEnv <- IO [(String, String)] -> IO [(String, String)]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO [(String, String)]
getEnvironment -- We may not want to leak all of this in?
  let e :: [(String, String)]
e =
        (String
"RABBITMQ_NODE_PORT", Int -> String
forall a. Show a => a -> String
show (PortNumber -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral PortNumber
rabbitMQHandlePort :: Int)) (String, String) -> [(String, String)] -> [(String, String)]
forall a. a -> [a] -> [a]
:
        [(String, String)]
oldEnv

  (ExitCode
_ec, ByteString
_output) <- ProcessConfig () () () -> IO (ExitCode, ByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (ExitCode, ByteString)
readProcessInterleaved (ProcessConfig () () () -> IO (ExitCode, ByteString))
-> ProcessConfig () () () -> IO (ExitCode, ByteString)
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> ProcessConfig () () () -> ProcessConfig () () ()
forall stdin stdout stderr.
[(String, String)]
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setEnv [(String, String)]
e (ProcessConfig () () () -> ProcessConfig () () ())
-> ProcessConfig () () () -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String -> ProcessConfig () () ()
shell String
"rabbitmqctl close_all_connections cleanup"
  case ExitCode
_ec of
    ExitFailure Int
i -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [String
"Something went wrong while trying to close connections", String
"exit code: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
i, ByteString -> String
forall a. Show a => a -> String
show ByteString
_output]
    ExitCode
ExitSuccess -> () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  ByteString
lb <- ProcessConfig () () () -> IO ByteString
forall (m :: * -> *) stdin stdoutIgnored stderr.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderr -> m ByteString
readProcessStdout_ (ProcessConfig () () () -> IO ByteString)
-> ProcessConfig () () () -> IO ByteString
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> ProcessConfig () () () -> ProcessConfig () () ()
forall stdin stdout stderr.
[(String, String)]
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setEnv [(String, String)]
e (ProcessConfig () () () -> ProcessConfig () () ())
-> ProcessConfig () () () -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String -> ProcessConfig () () ()
shell String
"rabbitmqctl list_queues --formatter json"
  case ByteString -> Either String ListQueuesOutput
forall a. FromJSON a => ByteString -> Either String a
JSON.eitherDecode ByteString
lb of
    Left String
err -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
err
    Right (ListQueuesOutput [QueueOutput]
queues) -> [QueueOutput] -> (QueueOutput -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [QueueOutput]
queues ((QueueOutput -> IO ()) -> IO ())
-> (QueueOutput -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \QueueOutput
queue -> do
      let queueName :: String
queueName = Text -> String
T.unpack (QueueOutput -> Text
queueOutputName QueueOutput
queue)
      (ExitCode
_ec, ByteString
_output) <- ProcessConfig () () () -> IO (ExitCode, ByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (ExitCode, ByteString)
readProcessInterleaved (ProcessConfig () () () -> IO (ExitCode, ByteString))
-> ProcessConfig () () () -> IO (ExitCode, ByteString)
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> ProcessConfig () () () -> ProcessConfig () () ()
forall stdin stdout stderr.
[(String, String)]
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setEnv [(String, String)]
e (ProcessConfig () () () -> ProcessConfig () () ())
-> ProcessConfig () () () -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String -> ProcessConfig () () ()
shell (String -> ProcessConfig () () ())
-> String -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String
"rabbitmqctl purge_queue " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
queueName
      case ExitCode
_ec of
        ExitFailure Int
i -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [String
"Something went wrong while trying to purge queue " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
queueName, String
"exit code: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
i, ByteString -> String
forall a. Show a => a -> String
show ByteString
_output]
        ExitCode
ExitSuccess -> () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      (ExitCode
_ec, ByteString
_output) <- ProcessConfig () () () -> IO (ExitCode, ByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (ExitCode, ByteString)
readProcessInterleaved (ProcessConfig () () () -> IO (ExitCode, ByteString))
-> ProcessConfig () () () -> IO (ExitCode, ByteString)
forall a b. (a -> b) -> a -> b
$ [(String, String)]
-> ProcessConfig () () () -> ProcessConfig () () ()
forall stdin stdout stderr.
[(String, String)]
-> ProcessConfig stdin stdout stderr
-> ProcessConfig stdin stdout stderr
setEnv [(String, String)]
e (ProcessConfig () () () -> ProcessConfig () () ())
-> ProcessConfig () () () -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String -> ProcessConfig () () ()
shell (String -> ProcessConfig () () ())
-> String -> ProcessConfig () () ()
forall a b. (a -> b) -> a -> b
$ String
"rabbitmqctl delete_queue " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
queueName
      case ExitCode
_ec of
        ExitFailure Int
i -> String -> IO ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines [String
"Something went wrong while trying to delete queue " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
queueName, String
"exit code: " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> Int -> String
forall a. Show a => a -> String
show Int
i, ByteString -> String
forall a. Show a => a -> String
show ByteString
_output]
        ExitCode
ExitSuccess -> () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

newtype ListQueuesOutput = ListQueuesOutput [QueueOutput]
  deriving (Int -> ListQueuesOutput -> String -> String
[ListQueuesOutput] -> String -> String
ListQueuesOutput -> String
(Int -> ListQueuesOutput -> String -> String)
-> (ListQueuesOutput -> String)
-> ([ListQueuesOutput] -> String -> String)
-> Show ListQueuesOutput
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [ListQueuesOutput] -> String -> String
$cshowList :: [ListQueuesOutput] -> String -> String
show :: ListQueuesOutput -> String
$cshow :: ListQueuesOutput -> String
showsPrec :: Int -> ListQueuesOutput -> String -> String
$cshowsPrec :: Int -> ListQueuesOutput -> String -> String
Show, ListQueuesOutput -> ListQueuesOutput -> Bool
(ListQueuesOutput -> ListQueuesOutput -> Bool)
-> (ListQueuesOutput -> ListQueuesOutput -> Bool)
-> Eq ListQueuesOutput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ListQueuesOutput -> ListQueuesOutput -> Bool
$c/= :: ListQueuesOutput -> ListQueuesOutput -> Bool
== :: ListQueuesOutput -> ListQueuesOutput -> Bool
$c== :: ListQueuesOutput -> ListQueuesOutput -> Bool
Eq, (forall x. ListQueuesOutput -> Rep ListQueuesOutput x)
-> (forall x. Rep ListQueuesOutput x -> ListQueuesOutput)
-> Generic ListQueuesOutput
forall x. Rep ListQueuesOutput x -> ListQueuesOutput
forall x. ListQueuesOutput -> Rep ListQueuesOutput x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ListQueuesOutput x -> ListQueuesOutput
$cfrom :: forall x. ListQueuesOutput -> Rep ListQueuesOutput x
Generic)

instance FromJSON ListQueuesOutput where
  parseJSON :: Value -> Parser ListQueuesOutput
parseJSON Value
v = [QueueOutput] -> ListQueuesOutput
ListQueuesOutput ([QueueOutput] -> ListQueuesOutput)
-> Parser [QueueOutput] -> Parser ListQueuesOutput
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> Parser [QueueOutput]
forall a. FromJSON a => Value -> Parser a
parseJSON Value
v

data QueueOutput = QueueOutput
  { QueueOutput -> Text
queueOutputName :: Text,
    QueueOutput -> Int
queueOutputMessages :: Int
  }
  deriving (Int -> QueueOutput -> String -> String
[QueueOutput] -> String -> String
QueueOutput -> String
(Int -> QueueOutput -> String -> String)
-> (QueueOutput -> String)
-> ([QueueOutput] -> String -> String)
-> Show QueueOutput
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [QueueOutput] -> String -> String
$cshowList :: [QueueOutput] -> String -> String
show :: QueueOutput -> String
$cshow :: QueueOutput -> String
showsPrec :: Int -> QueueOutput -> String -> String
$cshowsPrec :: Int -> QueueOutput -> String -> String
Show, QueueOutput -> QueueOutput -> Bool
(QueueOutput -> QueueOutput -> Bool)
-> (QueueOutput -> QueueOutput -> Bool) -> Eq QueueOutput
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: QueueOutput -> QueueOutput -> Bool
$c/= :: QueueOutput -> QueueOutput -> Bool
== :: QueueOutput -> QueueOutput -> Bool
$c== :: QueueOutput -> QueueOutput -> Bool
Eq, (forall x. QueueOutput -> Rep QueueOutput x)
-> (forall x. Rep QueueOutput x -> QueueOutput)
-> Generic QueueOutput
forall x. Rep QueueOutput x -> QueueOutput
forall x. QueueOutput -> Rep QueueOutput x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep QueueOutput x -> QueueOutput
$cfrom :: forall x. QueueOutput -> Rep QueueOutput x
Generic)

instance FromJSON QueueOutput where
  parseJSON :: Value -> Parser QueueOutput
parseJSON = String
-> (Object -> Parser QueueOutput) -> Value -> Parser QueueOutput
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"QueueOutput" ((Object -> Parser QueueOutput) -> Value -> Parser QueueOutput)
-> (Object -> Parser QueueOutput) -> Value -> Parser QueueOutput
forall a b. (a -> b) -> a -> b
$ \Object
o -> Text -> Int -> QueueOutput
QueueOutput (Text -> Int -> QueueOutput)
-> Parser Text -> Parser (Int -> QueueOutput)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
o Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"name" Parser (Int -> QueueOutput) -> Parser Int -> Parser QueueOutput
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
o Object -> Text -> Parser Int
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"messages"