lsm-tree-1.0.0.0: test/Test/Database/LSMTree/Internal/WriteBufferBlobs/FS.hs
module Test.Database.LSMTree.Internal.WriteBufferBlobs.FS (tests) where
import Control.Concurrent.Class.MonadSTM.Strict
import Control.Monad
import Control.Monad.Class.MonadThrow
import Control.RefCount
import Database.LSMTree.Extras.Generators ()
import Database.LSMTree.Internal.BlobRef (readRawBlobRef)
import Database.LSMTree.Internal.Serialise (SerialisedBlob)
import Database.LSMTree.Internal.WriteBufferBlobs
import System.FS.API
import System.FS.Sim.Error hiding (genErrors)
import qualified System.FS.Sim.MockFS as MockFS
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import Test.Util.FS
tests :: TestTree
tests = testGroup "Test.Database.LSMTree.Internal.WriteBufferBlobs.FS" [
testProperty "prop_fault_WriteBufferBlobs" prop_fault_WriteBufferBlobs
]
-- Test that opening and releasing a 'WriteBufferBlobs' properly cleans handles
-- and files in the presence of disk faults. Also test that we can write then
-- read blobs correctly in the presence of disk faults.
--
-- By testing 'open', we also test 'new'.
prop_fault_WriteBufferBlobs ::
Bool -- ^ create the file or not
-> AllowExisting
-> NoCleanupErrors
-> Errors
-> NoCleanupErrors
-> SerialisedBlob
-> SerialisedBlob
-> Property
prop_fault_WriteBufferBlobs doCreateFile ae
(NoCleanupErrors openErrors)
errs
(NoCleanupErrors releaseErrors)
b1 b2 =
ioProperty $
withSimErrorHasFS propPost MockFS.empty emptyErrors $ \hfs fsVar errsVar -> do
when doCreateFile $
withFile hfs path (WriteMode MustBeNew) $ \_ -> pure ()
eith <- try @_ @FsError $
bracket (acquire hfs errsVar) (release errsVar) $ \wbb -> do
fs' <- atomically $ readTMVar fsVar
let prop = propNumOpenHandles 1 fs' .&&. propNumDirEntries root 1 fs'
props <- blobRoundtrips hfs errsVar wbb
pure (prop .&&. props)
pure $ case eith of
Left{} -> do
label "FsError" $ property True
Right prop ->
label "Success" $ prop
where
root = mkFsPath []
path = mkFsPath ["wbb"]
acquire hfs errsVar = withErrors errsVar openErrors $ open hfs path ae
-- Test that we can roundtrip blobs
blobRoundtrips hfs errsVar wbb = withErrors errsVar errs $ do
props <-
forM [b1, b2] $ \b -> do
bspan <- addBlob hfs wbb b
let bref = mkRawBlobRef wbb bspan
b' <- readRawBlobRef hfs bref
pure (b === b')
pure $ conjoin props
release errsVar wbb = withErrors errsVar releaseErrors $ releaseRef wbb
propPost fs = propNoOpenHandles fs .&&.
if doCreateFile then
case ae of
AllowExisting ->
-- TODO: fix, see the TODO on openBlobFile
propNoDirEntries root fs .||. propNumDirEntries root 1 fs
MustBeNew ->
propNumDirEntries root 1 fs
MustExist ->
-- TODO: fix, see the TODO on openBlobFile
propNoDirEntries root fs .||. propNumDirEntries root 1 fs
else
propNoDirEntries root fs