packages feed

eventium-memory-0.3.2: tests/Eventium/MetadataEnrichmentSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Eventium.MetadataEnrichmentSpec (spec) where

import Control.Concurrent.STM
import Data.IORef
import Data.Maybe (isJust)
import Eventium
import Eventium.Store.Memory
import Test.Hspec

spec :: Spec
spec = describe "Metadata enrichment" $ do
  describe "metadataEnrichingEventStoreWriter" $ do
    it "populates event type name from Typeable" $ do
      tvar <- eventMapTVar
      let taggedWriter = tvarTaggedEventStoreWriter tvar
          enrichedWriter = metadataEnrichingEventStoreWriter testCodec (runEventStoreWriterUsing atomically taggedWriter)
          reader = runEventStoreReaderUsing atomically (tvarEventStoreReader tvar)
          uuid = uuidFromInteger 1
      _ <- enrichedWriter.storeEvents uuid NoStream [42 :: Int, 99]
      events <- reader.getEvents (allEvents uuid)
      map (\e -> e.metadata.eventType) events `shouldBe` ["Int", "Int"]

    it "populates createdAt timestamp" $ do
      tvar <- eventMapTVar
      let taggedWriter = tvarTaggedEventStoreWriter tvar
          enrichedWriter = metadataEnrichingEventStoreWriter testCodec (runEventStoreWriterUsing atomically taggedWriter)
          reader = runEventStoreReaderUsing atomically (tvarEventStoreReader tvar)
          uuid = uuidFromInteger 1
      _ <- enrichedWriter.storeEvents uuid NoStream [42 :: Int]
      events <- reader.getEvents (allEvents uuid)
      all (\e -> isJust e.metadata.createdAt) events `shouldBe` True

  describe "metadataEnrichingEventStoreWriterWithEnricher" $ do
    it "applies MetadataEnricher to set correlationId" $ do
      tvar <- eventMapTVar
      let corrId = uuidFromInteger 99
          enricher m = m {correlationId = Just corrId}
          taggedWriter = tvarTaggedEventStoreWriter tvar
          enrichedWriter = metadataEnrichingEventStoreWriterWithEnricher enricher testCodec (runEventStoreWriterUsing atomically taggedWriter)
          reader = runEventStoreReaderUsing atomically (tvarEventStoreReader tvar)
          uuid = uuidFromInteger 1
      _ <- enrichedWriter.storeEvents uuid NoStream [42 :: Int]
      events <- reader.getEvents (allEvents uuid)
      map (\e -> e.metadata.correlationId) events `shouldBe` [Just corrId]

    it "leaves correlationId unset when enricher is id" $ do
      tvar <- eventMapTVar
      let taggedWriter = tvarTaggedEventStoreWriter tvar
          enrichedWriter = metadataEnrichingEventStoreWriterWithEnricher id testCodec (runEventStoreWriterUsing atomically taggedWriter)
          reader = runEventStoreReaderUsing atomically (tvarEventStoreReader tvar)
          uuid = uuidFromInteger 1
      _ <- enrichedWriter.storeEvents uuid NoStream [42 :: Int]
      events <- reader.getEvents (allEvents uuid)
      map (\e -> e.metadata.correlationId) events `shouldBe` [Nothing]

  describe "backward compatibility" $ do
    it "non-tagged writer still uses empty metadata" $ do
      tvar <- eventMapTVar
      let writer = runEventStoreWriterUsing atomically (tvarEventStoreWriter tvar)
          reader = runEventStoreReaderUsing atomically (tvarEventStoreReader tvar)
          uuid = uuidFromInteger 1
      _ <- writer.storeEvents uuid NoStream [42 :: Int]
      events <- reader.getEvents (allEvents uuid)
      map (\e -> e.metadata.eventType) events `shouldBe` [""]

  describe "publishingTaggedCodecEventStoreWriter" $ do
    it "propagates metadata to published StreamEvents" $ do
      tvar <- eventMapTVar
      publishedRef <- newIORef []
      let taggedWriter = runEventStoreWriterUsing atomically (tvarTaggedEventStoreWriter tvar)
          handler = EventHandler $ \(StreamEvent _ _ meta _) ->
            modifyIORef publishedRef (++ [meta.eventType])
          publisher = synchronousPublisher handler
          pubWriter = publishingTaggedCodecEventStoreWriter testCodec taggedWriter publisher
          enrichedWriter = metadataEnrichingEventStoreWriter testCodec pubWriter
          uuid = uuidFromInteger 1
      _ <- enrichedWriter.storeEvents uuid NoStream [42 :: Int, 99]
      published <- readIORef publishedRef
      published `shouldBe` ["Int", "Int"]

-- A simple test codec for Int
testCodec :: Codec Int Int
testCodec = Codec id Just