|
1 |
| - |
2 |
| -{-# LANGUAGE TypeFamilies #-} |
3 |
| -{-# LANGUAGE GADTs #-} |
4 | 1 | {-# LANGUAGE DeriveGeneric #-}
|
5 |
| -{-# LANGUAGE StandaloneDeriving #-} |
| 2 | +{-# LANGUAGE DerivingStrategies #-} |
| 3 | +{-# LANGUAGE FlexibleContexts #-} |
6 | 4 | {-# LANGUAGE FlexibleInstances #-}
|
| 5 | +{-# LANGUAGE GADTs #-} |
| 6 | +{-# LANGUAGE LambdaCase #-} |
| 7 | +{-# LANGUAGE MultiParamTypeClasses #-} |
| 8 | +{-# LANGUAGE NamedFieldPuns #-} |
| 9 | +{-# LANGUAGE OverloadedRecordDot #-} |
| 10 | +{-# LANGUAGE OverloadedStrings #-} |
| 11 | +{-# LANGUAGE StandaloneDeriving #-} |
| 12 | +{-# LANGUAGE TypeFamilies #-} |
| 13 | +{-# LANGUAGE UndecidableInstances #-} |
| 14 | +{-# OPTIONS_GHC -Wno-orphans #-} |
| 15 | + |
7 | 16 | module Test.Ouroboros.Storage.PerasCertDB.StateMachine (tests) where
|
8 |
| -import Test.Tasty (TestTree) |
9 |
| -import Test.Ouroboros.Storage.TestBlock (TestBlock) |
10 |
| -import Ouroboros.Consensus.Block.SupportsPeras |
11 |
| -import Test.Ouroboros.Storage.PerasCertDB.Model |
| 17 | + |
| 18 | +import Control.Monad.State |
| 19 | +import Control.Tracer (nullTracer) |
| 20 | +import qualified Data.List.NonEmpty as NE |
| 21 | +import Ouroboros.Consensus.Block |
| 22 | +import qualified Ouroboros.Consensus.Storage.PerasCertDB as PerasCertDB |
| 23 | +import Ouroboros.Consensus.Storage.PerasCertDB.API (PerasCertDB, PerasWeightSnapshot) |
| 24 | +import Ouroboros.Consensus.Util.IOLike |
| 25 | +import qualified Test.Ouroboros.Storage.PerasCertDB.Model as Model |
| 26 | +import Test.QuickCheck |
| 27 | +import qualified Test.QuickCheck.Monadic as QC |
12 | 28 | import Test.QuickCheck.StateModel
|
13 |
| -import Ouroboros.Consensus.Storage.PerasCertDB.API (PerasWeightSnapshot) |
14 |
| -import Ouroboros.Consensus.Storage.PerasCertDB (PerasCertDbError) |
| 29 | +import Test.Tasty |
| 30 | +import Test.Tasty.QuickCheck |
| 31 | +import Test.Util.TestBlock (TestBlock, TestHash (..)) |
| 32 | +import Test.Util.TestEnv (adjustQuickCheckTests) |
15 | 33 |
|
16 | 34 | tests :: TestTree
|
17 |
| -tests = undefined |
| 35 | +tests = |
| 36 | + testGroup |
| 37 | + "PerasCertDB" |
| 38 | + [ adjustQuickCheckTests (* 100) $ testProperty "q-d" $ prop_qd |
| 39 | + ] |
| 40 | + |
| 41 | +prop_qd :: Actions Model -> Property |
| 42 | +prop_qd actions = QC.monadic f $ property () <$ runActions actions |
| 43 | + where |
| 44 | + f :: StateT (PerasCertDB IO TestBlock) IO Property -> Property |
| 45 | + f = ioProperty . flip evalStateT (error "unreachable") |
18 | 46 |
|
19 | 47 | type Block = TestBlock
|
20 |
| -newtype Model = Model (PerasCertDBModel Block) deriving (Show, Generic) |
| 48 | +newtype Model = Model (Model.Model Block) deriving (Show, Generic) |
21 | 49 |
|
22 | 50 | instance StateModel Model where
|
23 | 51 | data Action Model a where
|
24 | 52 | OpenDB :: Action Model ()
|
25 | 53 | CloseDB :: Action Model ()
|
26 |
| - AddCert :: PerasCert Block -> Action Model (Either PerasCertDbError ()) |
27 |
| - GetWeightSnapshot :: Action Model (Either PerasCertDbError (PerasWeightSnapshot Block)) |
| 54 | + AddCert :: PerasCert Block -> Action Model () |
| 55 | + GetWeightSnapshot :: Action Model (PerasWeightSnapshot Block) |
| 56 | + |
| 57 | + arbitraryAction _ (Model model) |
| 58 | + | model.open = |
| 59 | + frequency |
| 60 | + [ (1, pure $ Some CloseDB) |
| 61 | + , (20, Some <$> genAddCert) |
| 62 | + , (20, pure $ Some GetWeightSnapshot) |
| 63 | + ] |
| 64 | + | otherwise = pure $ Some OpenDB |
| 65 | + where |
| 66 | + genAddCert = do |
| 67 | + pcCertRound <- PerasRoundNo <$> arbitrary |
| 68 | + pcCertBoostedBlock <- arbitrary |
| 69 | + pure $ AddCert PerasCert{pcCertRound, pcCertBoostedBlock} |
| 70 | + |
| 71 | + initialState = Model Model.initModel |
28 | 72 |
|
29 |
| - arbitraryAction _ _ = error "arbitraryAction not implemented" |
30 |
| - initialState = error "initialState not implemented" |
| 73 | + nextState (Model model) action _ = Model $ case action of |
| 74 | + OpenDB -> Model.openDB model |
| 75 | + CloseDB -> Model.closeDB model |
| 76 | + AddCert cert -> Model.addCert model cert |
| 77 | + GetWeightSnapshot -> model |
31 | 78 |
|
32 |
| -deriving instance Show (Action Model a) |
| 79 | + precondition (Model model) = \case |
| 80 | + OpenDB -> not model.open |
| 81 | + action -> |
| 82 | + model.open && case action of |
| 83 | + CloseDB -> True |
| 84 | + AddCert cert -> all p model.certs |
| 85 | + where |
| 86 | + p cert' = perasCertRound cert /= perasCertRound cert' || cert == cert' |
| 87 | + GetWeightSnapshot -> True |
| 88 | + |
| 89 | +deriving stock instance Show (Action Model a) |
| 90 | +deriving stock instance Eq (Action Model a) |
33 | 91 |
|
34 | 92 | instance HasVariables (Action Model a) where
|
35 | 93 | getAllVariables _ = mempty
|
36 | 94 |
|
| 95 | +instance RunModel Model (StateT (PerasCertDB IO TestBlock) IO) where |
| 96 | + perform _ action _ = case action of |
| 97 | + OpenDB -> do |
| 98 | + perasCertDB <- lift $ PerasCertDB.openDB (PerasCertDB.PerasCertDbArgs nullTracer) |
| 99 | + put perasCertDB |
| 100 | + CloseDB -> do |
| 101 | + perasCertDB <- get |
| 102 | + lift $ PerasCertDB.closeDB perasCertDB |
| 103 | + AddCert cert -> do |
| 104 | + perasCertDB <- get |
| 105 | + lift $ PerasCertDB.addCert perasCertDB cert |
| 106 | + GetWeightSnapshot -> do |
| 107 | + perasCertDB <- get |
| 108 | + lift $ atomically $ PerasCertDB.getWeightSnapshot perasCertDB |
| 109 | + |
| 110 | + -- TODO: check open state consistency |
| 111 | + postcondition (Model model, _) GetWeightSnapshot _ actual = do |
| 112 | + let expected = Model.getWeightSnapshot model |
| 113 | + counterexamplePost $ "Model: " <> show expected |
| 114 | + counterexamplePost $ "SUT: " <> show actual |
| 115 | + pure $ expected == actual |
| 116 | + postcondition _ _ _ _ = pure True |
| 117 | + |
| 118 | +-- TODO very ugly |
| 119 | +instance Arbitrary (Point TestBlock) where |
| 120 | + arbitrary = |
| 121 | + oneof |
| 122 | + [ return GenesisPoint |
| 123 | + , BlockPoint <$> (SlotNo <$> arbitrary) <*> (TestHash . NE.fromList . getNonEmpty <$> arbitrary) |
| 124 | + ] |
0 commit comments