shibuya-core-0.8.0.0: test/Shibuya/BatchSpec.hs
module Shibuya.BatchSpec (spec) where
import Data.Map.Strict qualified as Map
import Shibuya.Batch
import Shibuya.Core.Ack (AckDecision (..), DeadLetterReason (..), RetryDelay (..))
import Shibuya.Core.Types (MessageId (..))
import Test.Hspec
-- | A concrete 'BatchConfig' so field access and 'validateBatchConfig' resolve
-- without ambiguous @es@/@msg@ type variables.
cfg :: BatchConfig '[] Int
cfg = defaultBatchConfig
spec :: Spec
spec = describe "Shibuya.Batch" $ do
describe "defaultBatchConfig" $ do
it "has size 100 and 1s timeout" $ do
cfg.batchSize `shouldBe` 100
cfg.batchTimeout `shouldBe` 1
it "routes every message to the default key" $
cfg.batchKey undefined `shouldBe` defaultBatchKey
describe "validateBatchConfig" $ do
it "accepts the default config" $
validateBatchConfig cfg `shouldBe` Right ()
it "rejects size 0" $
validateBatchConfig cfg {batchSize = 0}
`shouldBe` Left (BatchSizeNotPositive 0)
it "rejects non-positive timeout" $
validateBatchConfig cfg {batchTimeout = 0}
`shouldBe` Left (BatchTimeoutNotPositive 0)
it "rejects non-positive tick interval" $
validateBatchConfig cfg {tickInterval = Just 0}
`shouldBe` Left (TickIntervalNotPositive 0)
describe "BatchAck smart constructors" $ do
it "ackAllOk falls back to AckOk with no overrides" $ do
ackAllOk.fallback `shouldBe` AckOk
Map.null ackAllOk.decisions `shouldBe` True
it "ackAll sets the fallback for everything" $ do
let a = ackAll (AckRetry (RetryDelay 5))
Map.null a.decisions `shouldBe` True
a.fallback `shouldBe` AckRetry (RetryDelay 5)
it "ackExcept keeps AckOk fallback and records overrides" $ do
let a = ackExcept [(MessageId "m1", AckDeadLetter MaxRetriesExceeded)]
a.fallback `shouldBe` AckOk
Map.lookup (MessageId "m1") a.decisions
`shouldBe` Just (AckDeadLetter MaxRetriesExceeded)
it "failMessages dead-letters the listed ids" $ do
let a = failMessages [(MessageId "bad", PoisonPill "nope")]
a.fallback `shouldBe` AckOk
Map.lookup (MessageId "bad") a.decisions
`shouldBe` Just (AckDeadLetter (PoisonPill "nope"))
it "withFallback uses the given fallback" $ do
let a = withFallback (AckDeadLetter MaxRetriesExceeded) [(MessageId "ok", AckOk)]
a.fallback `shouldBe` AckDeadLetter MaxRetriesExceeded
Map.lookup (MessageId "ok") a.decisions `shouldBe` Just AckOk