|
| 1 | +-- | Tests for the 'EventSource' and 'EventSink' implementation in 'Hydra.Events.FileBased'. |
| 2 | +module Hydra.Events.FileBasedSpec where |
| 3 | + |
| 4 | +import Hydra.Prelude hiding (label) |
| 5 | +import Test.Hydra.Prelude |
| 6 | + |
| 7 | +import Hydra.Events (EventSink (..), EventSource (..), StateEvent (..), getEvents, putEvent) |
| 8 | +import Hydra.Ledger.Simple (SimpleTx) |
| 9 | +import Hydra.Persistence (PersistenceIncremental (..), createPersistenceIncremental) |
| 10 | +import Test.QuickCheck (forAllShrink, ioProperty, sublistOf, (===)) |
| 11 | +import Test.QuickCheck.Gen (listOf) |
| 12 | +import Hydra.Events.FileBased (eventPairFromPersistenceIncremental) |
| 13 | + |
| 14 | +spec :: Spec |
| 15 | +spec = do |
| 16 | + describe "eventPairFromPersistenceIncremental" $ do |
| 17 | + prop "can handle continuous events" $ |
| 18 | + forAllShrink genContinuousEvents shrink $ \events -> |
| 19 | + ioProperty $ do |
| 20 | + withEventSourceAndSink $ \EventSource{getEvents} EventSink{putEvent} -> do |
| 21 | + forM_ events putEvent |
| 22 | + loadedEvents <- getEvents |
| 23 | + pure $ |
| 24 | + loadedEvents === events |
| 25 | + |
| 26 | + prop "can handle non-continuous events" $ |
| 27 | + forAllShrink (sublistOf =<< genContinuousEvents) shrink $ \events -> |
| 28 | + ioProperty $ do |
| 29 | + withEventSourceAndSink $ \EventSource{getEvents} EventSink{putEvent} -> do |
| 30 | + forM_ events putEvent |
| 31 | + loadedEvents <- getEvents |
| 32 | + pure $ |
| 33 | + loadedEvents === events |
| 34 | + |
| 35 | + prop "can handle duplicate events" $ |
| 36 | + forAllShrink genContinuousEvents shrink $ \events -> |
| 37 | + ioProperty $ |
| 38 | + withEventSourceAndSink $ \EventSource{getEvents} EventSink{putEvent} -> do |
| 39 | + -- Put some events |
| 40 | + forM_ events putEvent |
| 41 | + loadedEvents <- getEvents |
| 42 | + -- Put the loaded events again (as the node would do) |
| 43 | + forM_ loadedEvents putEvent |
| 44 | + allEvents <- getEvents |
| 45 | + pure $ |
| 46 | + allEvents === loadedEvents |
| 47 | + |
| 48 | + prop "can bootstrap from plain StateChanged events" $ |
| 49 | + forAllShrink genContinuousEvents shrink $ \events -> do |
| 50 | + ioProperty $ do |
| 51 | + withTempDir "hydra-persistence" $ \tmpDir -> do |
| 52 | + -- Store state changes directly (legacy) |
| 53 | + let stateChanges = map stateChanged events |
| 54 | + PersistenceIncremental{append} <- createPersistenceIncremental (tmpDir <> "/data") |
| 55 | + forM_ stateChanges append |
| 56 | + -- Load and store events through the event source interface |
| 57 | + (EventSource{getEvents}, EventSink{putEvent}) <- |
| 58 | + eventPairFromPersistenceIncremental |
| 59 | + =<< createPersistenceIncremental (tmpDir <> "/data") |
| 60 | + loadedEvents <- getEvents |
| 61 | + -- Store all loaded events like the node would do |
| 62 | + forM_ loadedEvents putEvent |
| 63 | + pure $ |
| 64 | + map stateChanged loadedEvents === stateChanges |
| 65 | + |
| 66 | +genContinuousEvents :: Gen [StateEvent SimpleTx] |
| 67 | +genContinuousEvents = |
| 68 | + zipWith StateEvent [0 ..] <$> listOf arbitrary |
| 69 | + |
| 70 | +withEventSourceAndSink :: (EventSource (StateEvent SimpleTx) IO -> EventSink (StateEvent SimpleTx) IO -> IO b) -> IO b |
| 71 | +withEventSourceAndSink action = |
| 72 | + withTempDir "hydra-persistence" $ \tmpDir -> do |
| 73 | + (eventSource, eventSink) <- |
| 74 | + eventPairFromPersistenceIncremental |
| 75 | + =<< createPersistenceIncremental (tmpDir <> "/data") |
| 76 | + action eventSource eventSink |
0 commit comments