diff --git a/mismi-core/src/Mismi/Control.hs b/mismi-core/src/Mismi/Control.hs index 8328919..47f77f6 100644 --- a/mismi-core/src/Mismi/Control.hs +++ b/mismi-core/src/Mismi/Control.hs @@ -31,6 +31,7 @@ module Mismi.Control ( , setRetry , configureRetries , handleServiceError + , handle400Error , withRetries , withRetriesOf , throwOrRetry @@ -359,6 +360,21 @@ handleServiceError f pass action = throwM e +handle400Error :: ErrorCode -> AWS a -> AWS (Maybe a) +handle400Error code action = + let + check :: ServiceError -> Bool + check er = + let + httpStatus = _serviceStatus er == HTTP.status400 + codeCheck = _serviceCode er == code + in + httpStatus && codeCheck + in + handleServiceError check (const Nothing) (Just <$> action) + + + timeoutAWS :: Int -> AWS a -> AWS (Maybe a) timeoutAWS i r = do e <- ask diff --git a/mismi-secretsmanager/src/Mismi/SecretsManager/Commands.hs b/mismi-secretsmanager/src/Mismi/SecretsManager/Commands.hs index ffd9b41..d7e39db 100644 --- a/mismi-secretsmanager/src/Mismi/SecretsManager/Commands.hs +++ b/mismi-secretsmanager/src/Mismi/SecretsManager/Commands.hs @@ -66,21 +66,8 @@ writeString path token string = do handleExists :: AWS a -> AWS (Maybe a) handleExists = - handleError "ResourceExists" + handle400Error "ResourceExists" handleMissing :: AWS a -> AWS (Maybe a) handleMissing = - handleError "ResourceNotFound" - -handleError :: ErrorCode -> AWS a -> AWS (Maybe a) -handleError code action = - let - check :: ServiceError -> Bool - check er = - let - httpStatus = _serviceStatus er == HTTP.status400 - codeCheck = _serviceCode er == code - in - httpStatus && codeCheck - in - handleServiceError check (const Nothing) (Just <$> action) + handle400Error "ResourceNotFound" diff --git a/mismi-sqs/.ghci b/mismi-sqs/.ghci new file mode 120000 index 0000000..f76421a --- /dev/null +++ b/mismi-sqs/.ghci @@ -0,0 +1 @@ +../framework/ghci \ No newline at end of file diff --git a/mismi-sqs/CHANGELOG.md b/mismi-sqs/CHANGELOG.md new file mode 120000 index 0000000..04c99a5 --- /dev/null +++ b/mismi-sqs/CHANGELOG.md @@ -0,0 +1 @@ +../CHANGELOG.md \ No newline at end of file diff --git a/mismi-sqs/LICENSE b/mismi-sqs/LICENSE new file mode 120000 index 0000000..ea5b606 --- /dev/null +++ b/mismi-sqs/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/mismi-sqs/README.md b/mismi-sqs/README.md new file mode 100644 index 0000000..62780fb --- /dev/null +++ b/mismi-sqs/README.md @@ -0,0 +1,2 @@ +sqs +--- diff --git a/mismi-sqs/mismi-sqs.cabal b/mismi-sqs/mismi-sqs.cabal new file mode 100644 index 0000000..0548dc7 --- /dev/null +++ b/mismi-sqs/mismi-sqs.cabal @@ -0,0 +1,97 @@ +version: 0.0.3 + +name: + mismi-sqs +author: + Nick Hibberd +maintainer: + Nick Hibberd +homepage: + https://github.com/nhibberd/mismi +bug-reports: + https://github.com/nhibberd/mismi/issues +synopsis: + AWS Library +description: + mismi-sqs is a library that provides a set of common and useful + operations on top of AWS SQS. +category: + AWS +license: + BSD3 +license-file: + LICENSE +cabal-version: + >= 1.8 +build-type: + Simple +tested-with: + GHC == 8.2.2 + , GHC == 8.4.3 + , GHC == 8.6.3 +extra-source-files: + CHANGELOG.md + +library + build-depends: + base >= 3 && < 5 + , mismi-core == 0.0.3.* + , mismi-kernel == 0.0.3.* + , mismi-p == 0.0.3.* + , template-haskell + , amazonka >= 1.5 && < 1.7 + , amazonka-core >= 1.5 && < 1.7 + , amazonka-sqs >= 1.5 && < 1.7 + , exceptions >= 0.7 && < 0.11 + , text == 1.2.* + , transformers >= 0.3.1 && < 0.6 + , transformers-bifunctors >= 0.1 && < 1 + , lens >= 4.8 && < 4.18 + , unordered-containers >= 0.2.5 && < 0.3 + + ghc-options: + -Wall + + hs-source-dirs: + src + + exposed-modules: + Mismi.SQS.Amazonka + Mismi.SQS.Commands + Mismi.SQS.Data + Mismi.SQS.Error + +test-suite test-io + type: + exitcode-stdio-1.0 + + main-is: + test-io.hs + + ghc-options: + -Wall -threaded -O2 + + hs-source-dirs: + test + + other-modules: + Test.Mismi.SQS.Gen + Test.IO.Mismi.SQS.Commands + Test.IO.Mismi.SQS.Util + + build-depends: + base + , mismi-kernel == 0.0.3.* + , mismi-core == 0.0.3.* + , mismi-core-test == 0.0.3.* + , mismi-sqs + , mismi-p == 0.0.3.* + , mmorph >= 1.0 && < 1.2 + , exceptions >= 0.7 && < 0.11 + , hedgehog + , lens >= 4.8 && < 4.18 + , mtl >= 2.1 && < 2.3 + , resourcet >= 1.1 && < 1.3 + , text == 1.2.* + , time >= 1.4 && < 1.10 + , transformers >= 0.3.1 && < 0.6 diff --git a/mismi-sqs/src/Mismi/SQS/Amazonka.hs b/mismi-sqs/src/Mismi/SQS/Amazonka.hs new file mode 100644 index 0000000..5922721 --- /dev/null +++ b/mismi-sqs/src/Mismi/SQS/Amazonka.hs @@ -0,0 +1,8 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module Mismi.SQS.Amazonka ( + module AWS + ) where + +import Mismi.Amazonka as AWS hiding (Document) + +import Network.AWS.SQS as AWS diff --git a/mismi-sqs/src/Mismi/SQS/Commands.hs b/mismi-sqs/src/Mismi/SQS/Commands.hs new file mode 100644 index 0000000..4d0ef39 --- /dev/null +++ b/mismi-sqs/src/Mismi/SQS/Commands.hs @@ -0,0 +1,119 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Mismi.SQS.Commands ( + onQueue + , createQueue + , createQueueRaw + , deleteQueue + , readMessages + , readMessagesWithAttributes + , writeMessage + , deleteMessage + ) where + +import Control.Lens ((^.), (.~)) +import Control.Exception.Lens (handling) +import Control.Monad.Catch (throwM) + +import qualified Data.List as List +import qualified Data.Text as T +import qualified Data.HashMap.Strict as M + +import Mismi (AWS, fromMismiRegion) +import Mismi.Control (handle400Error) +import Mismi.SQS.Amazonka as A hiding (createQueue, deleteQueue, deleteMessage) +import qualified Mismi.SQS.Amazonka as A +import Mismi.SQS.Data +import Mismi.SQS.Error (SQSError (..)) + +import P + + +readMessages :: QueueUrl -> Maybe MessageCount -> Maybe WaitTime -> AWS [A.Message] +readMessages q c w = do + res <- A.send $ A.receiveMessage (renderQueueUrl q) + & A.rmMaxNumberOfMessages .~ fmap messageCount c + & A.rmWaitTimeSeconds .~ fmap waitTime w + pure $ res ^. rmrsMessages + +readMessagesWithAttributes :: QueueUrl -> Maybe MessageCount -> Maybe WaitTime -> [Text] -> AWS [A.Message] +readMessagesWithAttributes q c w keys = do + res <- A.send $ A.receiveMessage (renderQueueUrl q) + & A.rmMaxNumberOfMessages .~ fmap messageCount c + & A.rmWaitTimeSeconds .~ fmap waitTime w + & A.rmMessageAttributeNames .~ keys + pure $ res ^. rmrsMessages + +-- | Create a queue, which may be in a different region than our global/current one (which will be ignored) +onQueue :: Queue -> Maybe Visibility -> (QueueUrl -> AWS a) -> AWS a +onQueue (Queue q r) v action = + within (fromMismiRegion r) (action =<< createQueue q v) + +createQueueRaw :: QueueName -> Maybe Visibility -> AWS QueueUrl +createQueueRaw q vis = do + let + visbility v = + (A.QANVisibilityTimeout, T.pack . show $ visibility v) + + res <- handleExists q . A.send $ A.createQueue (renderQueueName q) + & A.cqAttributes .~ (M.fromList . maybeToList $ fmap visbility vis) + maybe + (throwM . Invariant $ "Failed to create new queue: " <> (T.pack . show) q) + (pure . QueueUrl) + (res ^. cqrsQueueURL) + +-- If queue already exists (and has different VisibilityTimeout) +handleExists :: QueueName -> AWS A.CreateQueueResponse -> AWS A.CreateQueueResponse +handleExists q = + handling _QueueNameExists $ \_ -> + -- Get existing queue (using default parameters) + send $ A.createQueue (renderQueueName q) + +-- | Returns the QueueUrl if the Queue already exists and if it doesn't. +-- calls `createQueueRaw` to create the Queue. +createQueue :: QueueName -> Maybe Visibility -> AWS QueueUrl +createQueue q v = do + let + handler = + handle400Error "AWS.SimpleQueueService.NonExistentQueue" + + res <- handler . A.send $ + listQueues + & lqQueueNamePrefix .~ Just (renderQueueName q) + + case res of + Nothing -> + createQueue q v + + Just res' -> + maybe + (createQueueRaw q v) + (pure . QueueUrl) + (listToMaybe . List.filter (isMatchingQueueName q) $ res' ^. lqrsQueueURLs) + +isMatchingQueueName :: QueueName -> Text -> Bool +isMatchingQueueName q url = + case T.split (== '/') url of + [] -> + False + xs -> + List.last xs == renderQueueName q + +deleteQueue :: QueueUrl -> AWS () +deleteQueue = + void . send . A.deleteQueue . renderQueueUrl + +writeMessage :: QueueUrl -> Text -> AWS (MessageId) +writeMessage q m = do + res <- send $ A.sendMessage (renderQueueUrl q) m + maybe + (throwM . Invariant $ "Failed to parse MessageId") + (pure . MessageId) + (res ^. smrsMessageId) + +deleteMessage :: QueueUrl -> A.Message -> AWS () +deleteMessage q m = do + i <- maybe (throwM . Invariant $ "MessageId cannot be Nothing") pure (m ^. mReceiptHandle) + void . send $ A.deleteMessage (renderQueueUrl q) i diff --git a/mismi-sqs/src/Mismi/SQS/Data.hs b/mismi-sqs/src/Mismi/SQS/Data.hs new file mode 100644 index 0000000..f6355cf --- /dev/null +++ b/mismi-sqs/src/Mismi/SQS/Data.hs @@ -0,0 +1,59 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Mismi.SQS.Data ( + QueueName (..) + , Queue (..) + , QueueUrl (..) + , MessageId (..) + + , MessageCount (..) + , Visibility (..) + , WaitTime (..) + ) where + +import Mismi.Kernel.Data (MismiRegion) + +import P + + +-- Queue names are limited to 80 characters. Alphanumeric characters +-- plus hyphens (-) and underscores (_) are allowed. Queue names must +-- be unique within an AWS account. After you delete a queue, you can +-- reuse the queue name. +newtype QueueName = + QueueName { + renderQueueName :: Text + } deriving (Eq, Show) + +data Queue = + Queue { + queueName :: QueueName + , queueRegion :: MismiRegion + } deriving (Eq, Show) + +newtype QueueUrl = + QueueUrl { + renderQueueUrl :: Text + } deriving (Eq, Show) + +newtype MessageId = + MessageId { + renderMessageId :: Text + } deriving (Eq, Show) + + +newtype MessageCount = + MessageCount { + messageCount :: Int + } deriving (Eq, Show) + +newtype Visibility = + Visibility { + visibility :: Int + } deriving (Eq, Show) + +newtype WaitTime = + WaitTime { + waitTime :: Int + } deriving (Eq, Show) diff --git a/mismi-sqs/src/Mismi/SQS/Error.hs b/mismi-sqs/src/Mismi/SQS/Error.hs new file mode 100644 index 0000000..62782ac --- /dev/null +++ b/mismi-sqs/src/Mismi/SQS/Error.hs @@ -0,0 +1,28 @@ +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Mismi.SQS.Error ( + SQSError(..) + , sqsErrorRender + ) where + +import Control.Exception.Base (Exception) + +import qualified Data.Text as T +import Data.Typeable (Typeable) + +import P + +data SQSError = + Invariant Text + deriving (Typeable) + +instance Exception SQSError + +instance Show SQSError where + show = T.unpack . sqsErrorRender + +sqsErrorRender :: SQSError -> Text +sqsErrorRender (Invariant e) = + "[Mismi internal error] - " <> e diff --git a/mismi-sqs/test/Test/IO/Mismi/SQS/Commands.hs b/mismi-sqs/test/Test/IO/Mismi/SQS/Commands.hs new file mode 100644 index 0000000..2c00259 --- /dev/null +++ b/mismi-sqs/test/Test/IO/Mismi/SQS/Commands.hs @@ -0,0 +1,129 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} + +module Test.IO.Mismi.SQS.Commands ( + tests + ) where + +import Control.Lens ((^.)) +import Control.Monad.Trans.Class (lift) + +import Hedgehog + +import Mismi (AWS) +import qualified Mismi.SQS.Amazonka as A +import qualified Mismi.SQS.Commands as SQS +import Mismi.SQS.Data + +import P + +import qualified Test.IO.Mismi.SQS.Util as Util +import Test.Mismi (liftAWS) +import qualified Test.Mismi.SQS.Gen as Gen + +prop_write_read :: Property +prop_write_read = + withTests 2 . property . Util.withQueueUrl $ \q -> do + msg <- forAll Gen.genNonEmptyMessage + writeMessage q msg + ms <- readOneMessage q + validateMessage msg ms + +prop_write_read_twice_visible :: Property +prop_write_read_twice_visible = + withTests 2 . property . Util.withQueueUrlVisibility (Visibility 0) $ \q -> do + msg <- forAll Gen.genNonEmptyMessage + writeMessage q msg + ms1 <- readOneMessage q + validateMessage msg ms1 + ms2 <- readOneMessage q + validateMessage msg ms2 + +prop_write_read_twice_hidden :: Property +prop_write_read_twice_hidden = + withTests 2 . property . Util.withQueueUrl $ \q -> do + msg <- forAll Gen.genNonEmptyMessage + writeMessage q msg + ms1 <- readOneMessage q + ms2 <- readOneMessage q + + validateMessage msg ms1 + [] === fmap (^. A.mBody) ms2 + +prop_write_delete_read :: Property +prop_write_delete_read = + withTests 2 . property . Util.withQueueUrl $ \q -> do + msg <- forAll Gen.genNonEmptyMessage + writeMessage q msg + ms <- readOneMessage q + lift $ forM_ ms (SQS.deleteMessage q) + res <- readOneMessage q + [] === res + +prop_with_queue :: Property +prop_with_queue = + withTests 2 . property . Util.withQueue $ \q -> do + m@(Gen.NonEmptyMessage msg) <- forAll Gen.genNonEmptyMessage + ls <- lift . SQS.onQueue q Nothing $ \url -> do + void $ SQS.writeMessage url msg + SQS.readMessages url (Just $ MessageCount 1) Nothing + validateMessage m ls + +prop_create_upgrade :: Property +prop_create_upgrade = + withTests 2 . property . liftAWS $ do + msg <- forAll Gen.genNonEmptyMessage + queue <- forAll Gen.genQueue + -- create queue with default VisibilityTimeout + q <- Util.newQueueWithVisibility Nothing queue + + -- get existing queue with non-default VisibilityTimeout + q' <- lift $ SQS.createQueue (queueName queue) (Just $ Visibility 8400) + writeMessage q msg + ms <- readOneMessage q' + validateMessage msg ms + +prop_create_downgrade :: Property +prop_create_downgrade = + withTests 2 . property . + -- create queue with non-default VisibilityTimeout + Util.withQueueAndUrlVisibility (Visibility 8400) $ \(queue', q) -> do + msg <- forAll Gen.genNonEmptyMessage + + -- get existing queue with default VisibilityTimeout + q' <- lift $ SQS.createQueue (queueName queue') Nothing + writeMessage q msg + res <- readOneMessage q' + validateMessage msg res + +prop_create_queue :: Property +prop_create_queue = + withTests 1 . property . Util.withQueue $ \queue -> do + lift . SQS.onQueue queue (Just $ Visibility 8400) $ \_ -> + pure () + lift . SQS.onQueue queue (Just $ Visibility 8400) $ \_ -> + pure () + success + +validateMessage :: Monad m => Gen.NonEmptyMessage -> [A.Message] -> PropertyT m () +validateMessage (Gen.NonEmptyMessage b) response = + [Just b] === fmap (^. A.mBody) response + +writeMessage :: QueueUrl -> Gen.NonEmptyMessage -> PropertyT AWS () +writeMessage q (Gen.NonEmptyMessage b) = + void . lift $ SQS.writeMessage q b + +readOneMessage :: QueueUrl -> PropertyT AWS [A.Message] +readOneMessage q = + lift $ SQS.readMessages q oneMessage Nothing + +oneMessage :: Maybe MessageCount +oneMessage = + Just $ MessageCount 1 + + +tests :: IO Bool +tests = + checkParallel $$(discover) diff --git a/mismi-sqs/test/Test/IO/Mismi/SQS/Util.hs b/mismi-sqs/test/Test/IO/Mismi/SQS/Util.hs new file mode 100644 index 0000000..9a70454 --- /dev/null +++ b/mismi-sqs/test/Test/IO/Mismi/SQS/Util.hs @@ -0,0 +1,87 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Test.IO.Mismi.SQS.Util ( + withQueue + , withQueueUrl + , withQueueUrlVisibility + , withQueueAndUrlVisibility + , liftAWSQueue + , newQueue + , newQueueAWS + , newQueueWithVisibility + , newQueueWithVisibilityAWS + ) where + +import Control.Monad.Reader (ask) +import Control.Monad.Morph (hoist) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Resource (register) + +import Hedgehog + +import Mismi (AWS, fromMismiRegion) +import qualified Mismi.Control as Control +import qualified Mismi.Amazonka as A +import Mismi.SQS.Data (Queue (..), QueueUrl, Visibility (..)) +import qualified Mismi.SQS.Commands as SQS + +import P + +import qualified Test.Mismi as X +import qualified Test.Mismi.SQS.Gen as Gen + +withQueue :: (Queue -> PropertyT AWS a) -> PropertyT IO a +withQueue f = do + q <- forAll Gen.genQueue + liftAWSQueue q $ + f q + +withQueueUrl :: (QueueUrl -> PropertyT AWS a) -> PropertyT IO a +withQueueUrl f = do + q <- forAll Gen.genQueue + liftAWSQueue q $ do + url <- newQueue q + f url + +withQueueUrlVisibility :: Visibility -> (QueueUrl -> PropertyT AWS a) -> PropertyT IO a +withQueueUrlVisibility v f = do + q <- forAll Gen.genQueue + liftAWSQueue q $ do + url <- newQueueWithVisibility (Just v) q + f url + +withQueueAndUrlVisibility :: Visibility -> ((Queue, QueueUrl) -> PropertyT AWS a) -> PropertyT IO a +withQueueAndUrlVisibility v f = do + q <- forAll Gen.genQueue + liftAWSQueue q $ do + url <- newQueueWithVisibility (Just v) q + f (q, url) + +liftAWSQueue :: Queue -> PropertyT AWS a -> PropertyT IO a +liftAWSQueue (Queue _ r) = + hoist (X.runAWSDefaultRegion . A.within (fromMismiRegion r)) + +newQueue :: Queue -> PropertyT AWS QueueUrl +newQueue q = + lift (newQueueAWS q) + +newQueueAWS :: Queue -> AWS QueueUrl +newQueueAWS q = + newQueueWithVisibilityAWS testVisibilityTimeout q + +newQueueWithVisibility :: Maybe Visibility -> Queue -> PropertyT AWS QueueUrl +newQueueWithVisibility v q = + lift (newQueueWithVisibilityAWS v q) + +newQueueWithVisibilityAWS :: Maybe Visibility -> Queue -> AWS QueueUrl +newQueueWithVisibilityAWS v (Queue qn r) = + A.within (fromMismiRegion r) $ do + e <- ask + url <- SQS.createQueue qn v + void $ register (Control.unsafeRunAWS e $ SQS.deleteQueue url) + pure url + +testVisibilityTimeout :: Maybe Visibility +testVisibilityTimeout = + Just $ Visibility 8400 diff --git a/mismi-sqs/test/Test/Mismi/SQS/Gen.hs b/mismi-sqs/test/Test/Mismi/SQS/Gen.hs new file mode 100644 index 0000000..8894644 --- /dev/null +++ b/mismi-sqs/test/Test/Mismi/SQS/Gen.hs @@ -0,0 +1,60 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module Test.Mismi.SQS.Gen ( + NonEmptyMessage (..) + , genNonEmptyMessage + + , genQueue + , genQueueName + , genSQSRegion + ) where + +import qualified Data.Text as T + +import Mismi.Kernel.Data +import Mismi.SQS.Data + +import Hedgehog +import qualified Hedgehog.Gen as Gen +import qualified Hedgehog.Range as Range + +import P + + +newtype NonEmptyMessage = + NonEmptyMessage { + unMessage :: Text + } deriving (Eq, Show) + + +-- http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html +-- invalid unicode values #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF] +genNonEmptyMessage :: Gen NonEmptyMessage +genNonEmptyMessage = + NonEmptyMessage <$> genSQSText + +genSQSText :: Gen Text +genSQSText = + Gen.text (Range.linear 5 100) Gen.alphaNum + +genQueue :: Gen Queue +genQueue = + Queue <$> genQueueName <*> genSQSRegion + +genQueueName :: Gen QueueName +genQueueName = + fmap (QueueName . T.pack) . Gen.list (Range.singleton 80) . Gen.element + $ ['a'..'z'] <> ['0'..'9'] <> "-_" + +genSQSRegion :: Gen MismiRegion +genSQSRegion = + Gen.element [ + IrelandRegion + , TokyoRegion + , SingaporeRegion + , SydneyRegion + , NorthCaliforniaRegion + , OregonRegion + , NorthVirginiaRegion + ] diff --git a/mismi-sqs/test/mismi-sqs-test.cabal b/mismi-sqs/test/mismi-sqs-test.cabal new file mode 100644 index 0000000..349e723 --- /dev/null +++ b/mismi-sqs/test/mismi-sqs-test.cabal @@ -0,0 +1,21 @@ +version: 0.0.3 + +name: + mismi-sqs-test + +cabal-version: + >= 1.8 +build-type: + Simple + +library + build-depends: + base >= 3 && < 5 + , mismi-kernel == 0.0.3.* + , mismi-sqs == 0.0.3.* + , mismi-p == 0.0.3.* + , hedgehog + , text >= 1.1 && < 1.3 + + exposed-modules: + Test.Mismi.SQS.Gen diff --git a/mismi-sqs/test/test-io.hs b/mismi-sqs/test/test-io.hs new file mode 100644 index 0000000..d55fee1 --- /dev/null +++ b/mismi-sqs/test/test-io.hs @@ -0,0 +1,18 @@ +import Control.Monad (unless) + +import System.Exit (exitFailure) +import System.IO (BufferMode(..), hSetBuffering, stdout, stderr) + +import qualified Test.IO.Mismi.SQS.Commands +import qualified Test.Mismi as Mismi + +main :: IO () +main = do + hSetBuffering stdout LineBuffering + hSetBuffering stderr LineBuffering + + results <- sequence =<< Mismi.enableTests "AWS_TEST_SQS" [] [ + Test.IO.Mismi.SQS.Commands.tests + ] + + unless (and results) exitFailure diff --git a/stack-8.2.2.yaml b/stack-8.2.2.yaml index 49671cc..664ee08 100644 --- a/stack-8.2.2.yaml +++ b/stack-8.2.2.yaml @@ -14,6 +14,8 @@ packages: - mismi-ec2-core/test - mismi-ec2 - mismi-secretsmanager + - mismi-sqs + - mismi-sqs/test extra-deps: - git: https://github.com/brendanhay/amazonka.git @@ -24,3 +26,4 @@ extra-deps: - amazonka-s3 - amazonka-ec2 - amazonka-secretsmanager + - amazonka-sqs diff --git a/stack-8.4.3.yaml b/stack-8.4.3.yaml index 648ea11..32cdbd8 100644 --- a/stack-8.4.3.yaml +++ b/stack-8.4.3.yaml @@ -14,6 +14,8 @@ packages: - mismi-ec2-core/test - mismi-ec2 - mismi-secretsmanager + - mismi-sqs + - mismi-sqs/test extra-deps: - git: https://github.com/brendanhay/amazonka.git @@ -24,3 +26,4 @@ extra-deps: - amazonka-s3 - amazonka-ec2 - amazonka-secretsmanager + - amazonka-sqs diff --git a/stack-8.6.3.yaml b/stack-8.6.3.yaml index 0b2b953..d926744 100644 --- a/stack-8.6.3.yaml +++ b/stack-8.6.3.yaml @@ -14,6 +14,8 @@ packages: - mismi-ec2-core/test - mismi-secretsmanager - mismi-ec2 + - mismi-sqs + - mismi-sqs/test extra-deps: @@ -25,5 +27,6 @@ extra-deps: - amazonka-s3 - amazonka-ec2 - amazonka-secretsmanager + - amazonka-sqs - hedgehog-0.6.1