lsm-tree-1.0.0.1: test/Test/Database/LSMTree/Internal/WriteBufferReader/FS.hs
module Test.Database.LSMTree.Internal.WriteBufferReader.FS (tests) where
import Control.Concurrent.Class.MonadSTM.Strict (MonadSTM (..))
import Control.Concurrent.Class.MonadSTM.Strict.TMVar
import Control.Monad.Class.MonadThrow
import Control.RefCount
import Database.LSMTree.Extras.Generators ()
import Database.LSMTree.Extras.RunData (RunData,
withRunDataAsWriteBuffer, withSerialisedWriteBuffer)
import Database.LSMTree.Internal.Paths (ForKOps (ForKOps),
WriteBufferFsPaths (WriteBufferFsPaths),
writeBufferKOpsPath)
import Database.LSMTree.Internal.RunNumber (RunNumber (RunNumber))
import Database.LSMTree.Internal.Serialise (SerialisedBlob,
SerialisedKey, SerialisedValue (..))
import qualified Database.LSMTree.Internal.WriteBufferBlobs as WBB
import Database.LSMTree.Internal.WriteBufferReader
import System.FS.API
import System.FS.Sim.Error hiding (genErrors)
import qualified System.FS.Sim.MockFS as MockFS
import qualified System.FS.Sim.Stream as Stream
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import Test.Util.FS as FS
tests :: TestTree
tests = testGroup "Test.Database.LSMTree.Internal.WriteBufferReader.FS" [
testProperty "prop_fault_WriteBufferReader" prop_fault_WriteBufferReader
]
-- | Test that 'writeWriteBuffer' roundtrips with 'readWriteBuffer', and test
-- that the presence of disk faults for the latter does not leak file handles
-- and files.
prop_fault_WriteBufferReader ::
NoCleanupErrors
-> RunData SerialisedKey SerialisedValue SerialisedBlob
-> Property
prop_fault_WriteBufferReader (NoCleanupErrors readErrors) rdata =
ioProperty $
withRefCtx $ \refCtx ->
withSimErrorHasBlockIO propPost MockFS.empty emptyErrors $ \hfs hbio fsVar errsVar ->
withRunDataAsWriteBuffer hfs refCtx resolve inPath rdata $ \wb wbb ->
withSerialisedWriteBuffer hfs hbio outPath wb wbb $ do
fsBefore <- atomically $ readTMVar fsVar
eith <-
try @_ @FsError $
withErrors errsVar readErrors' $
withRef wbb $ \wbb' -> do
wb' <- readWriteBuffer resolve hfs hbio outKOpsPath (WBB.blobFile wbb')
pure (wb === wb')
fsAfter <- atomically $ readTMVar fsVar
pure $
case eith of
Left{} -> do
label "FsError" $ property True
Right prop ->
label "Success" $ prop .&&. propEqNumDirEntries root fsBefore fsAfter
where
root = mkFsPath []
-- The run number for the original write buffer. Primarily used to name the
-- 'WriteBufferBlobs' corresponding to the write buffer.
inPath = WriteBufferFsPaths root (RunNumber 0)
-- The run number for the serialised write buffer. Used to name all files
-- that are the result of serialising the write buffer.
outPath = WriteBufferFsPaths root (RunNumber 1)
outKOpsPath = ForKOps (writeBufferKOpsPath outPath)
resolve (SerialisedValue x) (SerialisedValue y) = SerialisedValue (x <> y)
propPost fs = propNoOpenHandles fs .&&. propNoDirEntries root fs
-- TODO: fix, see the TODO on readDiskPage
readErrors' = readErrors {
hGetBufSomeE = Stream.filter (not . isFsReachedEOFError) (hGetBufSomeE readErrors)
}
isFsReachedEOFError = maybe False (either isFsReachedEOF (const False))