shrub/pkg/king/test/LogTests.hs

188 lines
5.9 KiB
Haskell
Raw Normal View History

module LogTests (tests) where
import Data.Acquire
import Test.QuickCheck hiding ((.&.))
import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.TH
import UrbitPrelude
import Vere.Log
import Vere.Pier.Types
import Data.Conduit
2019-08-21 02:32:46 +03:00
import Data.Conduit.List hiding (filter)
import Control.Concurrent (threadDelay, runInBoundThread)
import Data.LargeWord (LargeKey(..))
import GHC.Natural (Natural)
import qualified Vere.Log as Log
-- Utils -----------------------------------------------------------------------
withTestDir :: (FilePath -> IO a) -> IO a
withTestDir = withTempDirectory "./" ".testlog."
data NotEqual = NotEqual String String
deriving (Eq, Ord, Show)
instance Exception NotEqual where
assertEqual :: (Show a, Eq a) => a -> a -> IO ()
assertEqual x y = do
unless (x == y) $
throwIO (NotEqual (show x) (show y))
-- Database Operations ---------------------------------------------------------
2019-08-21 02:32:46 +03:00
data Db = Db LogIdentity [ByteString] (Map Word64 ByteString)
deriving (Eq, Ord, Show)
addEvents :: Db -> [ByteString] -> Db
2019-08-21 02:32:46 +03:00
addEvents (Db id evs efs) new = Db id (evs <> new) efs
readDb :: EventLog -> IO Db
readDb log = do
2019-08-21 02:32:46 +03:00
events <- runConduit (streamEvents log 1 .| consume)
effects <- runConduit (streamEffectsRows log 0 .| consume)
pure $ Db (Log.identity log) events (mapFromList effects)
withDb :: FilePath -> Db -> (EventLog -> IO a) -> IO a
2019-08-21 02:32:46 +03:00
withDb dir (Db dId dEvs dFx) act = do
with (Log.new dir dId) $ \log -> do
Log.appendEvents log (fromList dEvs)
2019-08-21 02:32:46 +03:00
for_ (mapToList dFx) $ \(k,v) ->
Log.writeEffectsRow log k v
act log
--------------------------------------------------------------------------------
tryReadIdentity :: Property
tryReadIdentity = forAll arbitrary (ioProperty . runTest)
where
runTest :: LogIdentity -> IO Bool
runTest ident = do
runInBoundThread $
withTestDir $ \dir -> do
with (Log.new dir ident) $ \log ->
assertEqual ident (Log.identity log)
with (Log.existing dir) $ \log ->
assertEqual ident (Log.identity log)
with (Log.existing dir) $ \log ->
assertEqual ident (Log.identity log)
pure True
tryReadDatabase :: Property
tryReadDatabase = forAll arbitrary (ioProperty . runTest)
2019-08-21 02:32:46 +03:00
where
runTest :: Db -> IO Bool
runTest db = do
runInBoundThread $
withTestDir $ \dir -> do
withDb dir db $ \log -> do
readDb log >>= assertEqual db
pure True
tryReadDatabaseFuzz :: Property
tryReadDatabaseFuzz = forAll arbitrary (ioProperty . runTest)
where
runTest :: Db -> IO Bool
runTest db = do
runInBoundThread $
withTestDir $ \dir -> do
withDb dir db $ \log -> do
readDb log >>= assertEqual db
with (Log.existing dir) $ \log -> do
readDb log >>= assertEqual db
with (Log.existing dir) $ \log -> do
readDb log >>= assertEqual db
readDb log >>= assertEqual db
pure True
tryAppend :: Property
tryAppend = forAll arbitrary (ioProperty . runTest)
where
runTest :: ([ByteString], Db) -> IO Bool
runTest (extra, db) = do
runInBoundThread $
withTestDir $ \dir -> do
db' <- pure (addEvents db extra)
withDb dir db $ \log -> do
readDb log >>= assertEqual db
Log.appendEvents log (fromList extra)
readDb log >>= assertEqual db'
with (Log.existing dir) $ \log -> do
readDb log >>= assertEqual db'
pure True
tryAppendHuge :: Property
tryAppendHuge = forAll arbitrary (ioProperty . runTest)
where
runTest :: ([ByteString], Db) -> IO Bool
runTest (extra, db) = do
runInBoundThread $ do
2019-08-21 02:32:46 +03:00
extra <- do b <- readFile "/home/benajmin/r/urbit/bin/brass.pill"
pure (extra <> [b] <> extra)
withTestDir $ \dir -> do
db' <- pure (addEvents db extra)
withDb dir db $ \log -> do
readDb log >>= assertEqual db
Log.appendEvents log (fromList extra)
readDb log >>= assertEqual db'
with (Log.existing dir) $ \log -> do
readDb log >>= assertEqual db'
pure True
tests :: TestTree
tests =
testGroup "Log"
[ localOption (QuickCheckTests 10) $
testProperty "Read/Write Log Identity" $
tryReadIdentity
2019-08-21 02:32:46 +03:00
, localOption (QuickCheckTests 15) $
testProperty "Read/Write Database" $
tryReadDatabase
2019-08-21 02:32:46 +03:00
, localOption (QuickCheckTests 5) $
testProperty "Read/Write Database Multiple Times" $
tryReadDatabaseFuzz
, localOption (QuickCheckTests 10) $
testProperty "Append Random Events" $
tryAppend
, localOption (QuickCheckTests 1) $
testProperty "Append Huge Events" $
tryAppendHuge
]
-- Generate Arbitrary Values ---------------------------------------------------
arb :: Arbitrary a => Gen a
arb = arbitrary
instance Arbitrary ByteString where
arbitrary = pack <$> arbitrary
instance (Arbitrary a, Arbitrary b) => Arbitrary (LargeKey a b) where
arbitrary = LargeKey <$> arb <*> arb
instance Arbitrary Ship where
arbitrary = Ship <$> arb
2019-08-21 02:32:46 +03:00
arbEffects :: [ByteString] -> Gen (Map Word64 ByteString)
arbEffects evs = do
hax <- for (zip [1..] evs) $ \(i, bs) -> do keep :: Bool <- arbitrary
pure (keep, (i, bs))
pure $ mapFromList $ snd <$> filter fst hax
instance Arbitrary Db where
2019-08-21 02:32:46 +03:00
arbitrary = do
ident <- arbitrary
evs <- arbitrary
efs <- arbEffects evs
pure (Db ident evs efs)
instance Arbitrary LogIdentity where
arbitrary = LogIdentity <$> arb <*> arb <*> arb