module Data.CQRS.Test.EventStore.BackendTest
    ( testBackend
    ) where

import           Data.Conduit (runResourceT, ($$))
import qualified Data.Conduit.List as CL
import           Data.Conduit.Pool (Pool, withResource)
import           Data.CQRS.GUID
import           Data.CQRS.EventStore.Backend
import           Data.CQRS.PersistedEvent
import           Test.Hspec

-- Run tests with a clean slate.
withBackend :: (EventStoreBackend b) => IO (Pool b) -> (b -> IO a) -> IO a
withBackend mkPool a = do
  mkPool >>= (flip withResource) a

-- Test suite for memory backend.
testBackend :: (EventStoreBackend b) => IO (Pool b) -> IO () -> Spec
testBackend mkPool setup = do
  -- Bracket a test with a new event store backend pool.
  let bracket run = do
        setup
        withBackend mkPool run
  -- Examples
  describe "Event store backend" $ do

    it "should be able to retrieve stored events" $ bracket $ \b -> do
      g <- newGUID
      -- Write two events.
      let expectedEvents = [ PersistedEvent g "test event 1" 0
                           , PersistedEvent g "test event 2" 1
                           ]
      (esbStoreEvents b) g 0 expectedEvents
      -- Retrieve the stored events.
      actualEvents <- runResourceT (esbRetrieveEvents b g 0 $$ CL.consume)
      -- Assert that we've retrieved the expected events in order.
      actualEvents `shouldBe` expectedEvents

    it "should be able to enumerate all stored events" $ bracket $ \b -> do
      g1 <- newGUID
      g2 <- newGUID
      let pe1 = PersistedEvent g1 "test event 1" 0
      let pe2 = PersistedEvent g2 "test event 2" 0
      (esbStoreEvents b) g1 0 [ pe1 ]
      (esbStoreEvents b) g2 0 [ pe2 ]
      -- Retrieve the stored events.
      evs <- runResourceT (esbEnumerateAllEvents b $$ CL.consume)
      -- Assert that we've retrieved both events.
      length evs `shouldBe` 2
      (pe1 `elem` evs) `shouldBe` True
      (pe2 `elem` evs) `shouldBe` True

    it "writing first snapshot works" $ bracket $ \b -> do
      g <- newGUID
      -- Write the snapshot.
      let rs = (RawSnapshot 3 "Hello, world")
      esbWriteSnapshot b g rs
      -- Read the snapshot.
      rs' <- esbGetLatestSnapshot b g
      -- Assert that we've retrieved the right snapshot.
      rs' `shouldBe` Just rs

    it "updating snapshot overwrites existing one" $ bracket $ \b -> do
      g <- newGUID
      -- Write snapshot "twice"
      let rs1 = (RawSnapshot 3 "Hello")
      let rs2 = (RawSnapshot 4 "Goodbye")
      esbWriteSnapshot b g rs1
      esbWriteSnapshot b g rs2
      -- Read latest snapshot
      rs' <- esbGetLatestSnapshot b g
      -- Assert that the latter snapshot was retrieved
      rs' `shouldBe` Just rs2