atelier-core-0.3.0.0: test/Unit/Atelier/Effects/PublishingSpec.hs
module Unit.Atelier.Effects.PublishingSpec (spec_Publishing) where
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)
import Data.Time (UTCTime, getCurrentTime)
import Effectful (IOE, runEff)
import Effectful.Concurrent (Concurrent, runConcurrent)
import Test.Hspec (Spec, describe, it, shouldBe)
import Atelier.Effects.Chan (Chan, runChan)
import Atelier.Effects.Clock (Clock, runClock, runClockConst)
import Atelier.Effects.Conc (Conc, runConc)
import Atelier.Effects.Monitoring.Tracing (Tracing, runTracingNoOp)
import Atelier.Effects.Publishing (runPubSub)
import Atelier.Effects.Publishing.Pub (Pub)
import Atelier.Effects.Publishing.Sub (Sub)
import Atelier.Effects.Publishing.Pub qualified as Pub
import Atelier.Effects.Publishing.Sub qualified as Sub
data TestEvent = TestEvent Text
deriving stock (Eq, Show)
spec_Publishing :: Spec
spec_Publishing = do
describe "runPubSub" do
it "listener receives a published event" do
result <- runPubSubTest $ do
received <- liftIO newEmptyMVar
Sub.forkListener_ @TestEvent \event ->
liftIO $ putMVar received event
Pub.publish (TestEvent "hello")
liftIO $ takeMVar received
result `shouldBe` TestEvent "hello"
it "event timestamp matches Clock at publish time" do
t0 <- getCurrentTime
result <- runPubSubTestWithClock t0 $ do
received <- liftIO newEmptyMVar
Sub.forkListener @TestEvent \ts _event ->
liftIO $ putMVar received ts
Pub.publish (TestEvent "hello")
liftIO $ takeMVar received
result `shouldBe` t0
it "multiple listeners each receive the published event" do
result <- runPubSubTest $ do
recv1 <- liftIO newEmptyMVar
recv2 <- liftIO newEmptyMVar
Sub.forkListener_ @TestEvent \event -> liftIO $ putMVar recv1 event
Sub.forkListener_ @TestEvent \event -> liftIO $ putMVar recv2 event
Pub.publish (TestEvent "hello")
e1 <- liftIO $ takeMVar recv1
e2 <- liftIO $ takeMVar recv2
pure (e1, e2)
result `shouldBe` (TestEvent "hello", TestEvent "hello")
--------------------------------------------------------------------------------
-- Test Helpers
--------------------------------------------------------------------------------
runPubSubTest
:: Eff '[Pub TestEvent, Sub TestEvent, Chan, Clock, Tracing, Conc, Concurrent, IOE] a
-> IO a
runPubSubTest =
runEff
. runConcurrent
. runConc
. runTracingNoOp
. runClock
. runChan
. runPubSub @TestEvent
runPubSubTestWithClock
:: UTCTime
-> Eff '[Pub TestEvent, Sub TestEvent, Chan, Clock, Tracing, Conc, Concurrent, IOE] a
-> IO a
runPubSubTestWithClock t =
runEff
. runConcurrent
. runConc
. runTracingNoOp
. runClockConst t
. runChan
. runPubSub @TestEvent