@@ -50,6 +50,8 @@ module Test.Database.LSMTree.Normal.StateMachine (
50
50
, labelledExamples
51
51
) where
52
52
53
+ import Control.Concurrent.Class.MonadSTM.Strict
54
+ import Control.Exception (assert )
53
55
import Control.Monad ((<=<) )
54
56
import Control.Monad.Class.MonadThrow (Handler (.. ), MonadCatch (.. ),
55
57
MonadThrow (.. ))
@@ -81,7 +83,10 @@ import System.Directory (removeDirectoryRecursive)
81
83
import System.FS.API (HasFS , MountPoint (.. ), mkFsPath )
82
84
import System.FS.BlockIO.API (HasBlockIO , defaultIOCtxParams )
83
85
import System.FS.BlockIO.IO (ioHasBlockIO )
86
+ import System.FS.BlockIO.Sim (simHasBlockIO )
84
87
import System.FS.IO (HandleIO , ioHasFS )
88
+ import qualified System.FS.Sim.MockFS as MockFS
89
+ import System.FS.Sim.MockFS (MockFS )
85
90
import System.IO.Error
86
91
import System.IO.Temp (createTempDirectory ,
87
92
getCanonicalTemporaryDirectory )
@@ -104,18 +109,22 @@ import Test.Util.TypeFamilyWrappers (WrapBlob (..), WrapBlobRef (..),
104
109
105
110
tests :: TestTree
106
111
tests = testGroup " Normal.StateMachine" [
107
- propLockstepIO_ModelIOImpl
108
- , propLockstepIO_RealImpl_RealFS
109
- {- TODO: temporarily disabled until we start on I/O fault testing.
110
- , propLockstepIO_RealImpl_MockFS
111
- -}
112
+ testProperty " prop_lockstepIO_ModelIOImpl"
113
+ prop_lockstepIO_ModelIOImpl
114
+
115
+ , testProperty " prop_lockstepIO_RealImpl_RealFS"
116
+ prop_lockstepIO_RealImpl_RealFS
117
+
118
+ , testProperty " prop_lockstepIO_RealImpl_MockFS"
119
+ prop_lockstepIO_RealImpl_MockFS
112
120
]
113
121
114
122
labelledExamples :: IO ()
115
123
labelledExamples = QC. labelledExamples $ Lockstep.Run. tagActions (Proxy @ (ModelState R. TableHandle ))
116
124
117
- propLockstepIO_ModelIOImpl :: TestTree
118
- propLockstepIO_ModelIOImpl = testProperty " propLockstepIO_ModelIOImpl" $
125
+ prop_lockstepIO_ModelIOImpl :: Actions (Lockstep (ModelState M. TableHandle ))
126
+ -> QC. Property
127
+ prop_lockstepIO_ModelIOImpl =
119
128
runActionsBracket'
120
129
(Proxy @ (ModelState M. TableHandle ))
121
130
acquire
@@ -168,18 +177,19 @@ propLockstepIO_ModelIOImpl = testProperty "propLockstepIO_ModelIOImpl" $
168
177
deriving via AllowThunk (M. Session IO )
169
178
instance NoThunks (M. Session IO )
170
179
171
- propLockstepIO_RealImpl_RealFS :: TestTree
172
- propLockstepIO_RealImpl_RealFS = testProperty " propLockstepIO_RealImpl_RealFS" $
180
+ prop_lockstepIO_RealImpl_RealFS :: Actions (Lockstep (ModelState R. TableHandle ))
181
+ -> QC. Property
182
+ prop_lockstepIO_RealImpl_RealFS =
173
183
runActionsBracket'
174
184
(Proxy @ (ModelState R. TableHandle ))
175
185
acquire
176
186
release
177
- (\ r (_, session) -> runReaderT r (session, handler ))
187
+ (\ r (_, session) -> runReaderT r (session, realHandler @ IO ))
178
188
tagFinalState'
179
189
where
180
190
acquire :: IO (FilePath , WrapSession R. TableHandle IO )
181
191
acquire = do
182
- (tmpDir, hasFS, hasBlockIO) <- createSystemTempDirectory " propLockstepIO_RealIO "
192
+ (tmpDir, hasFS, hasBlockIO) <- createSystemTempDirectory " prop_lockstepIO_RealIO "
183
193
session <- R. openSession nullTracer hasFS hasBlockIO (mkFsPath [] )
184
194
pure (tmpDir, WrapSession session)
185
195
@@ -188,42 +198,40 @@ propLockstepIO_RealImpl_RealFS = testProperty "propLockstepIO_RealImpl_RealFS" $
188
198
R. closeSession session
189
199
removeDirectoryRecursive tmpDir
190
200
191
- handler :: Handler IO (Maybe Model. Err )
192
- handler = Handler $ pure . handler'
193
- where
194
- handler' :: LSMTreeError -> Maybe Model. Err
195
- handler' ErrTableClosed = Just Model. ErrTableHandleClosed
196
- handler' ErrCursorClosed = Just Model. ErrCursorClosed
197
- handler' (ErrSnapshotNotExists _snap) = Just Model. ErrSnapshotDoesNotExist
198
- handler' (ErrSnapshotExists _snap) = Just Model. ErrSnapshotExists
199
- handler' (ErrSnapshotWrongType _snap) = Just Model. ErrSnapshotWrongType
200
- handler' (ErrBlobRefInvalid _) = Just Model. ErrBlobRefInvalidated
201
- handler' _ = Nothing
202
-
203
- {- TODO: temporarily disabled until we start on I/O fault testing.
204
- propLockstepIO_RealImpl_MockFS :: TestTree
205
- propLockstepIO_RealImpl_MockFS = testProperty "propLockstepIO_RealImpl_MockFS" $
206
- QC.expectFailure $ -- TODO: remove once we have a real implementation
207
- Lockstep.Run.runActionsBracket
201
+ prop_lockstepIO_RealImpl_MockFS :: Actions (Lockstep (ModelState R. TableHandle ))
202
+ -> QC. Property
203
+ prop_lockstepIO_RealImpl_MockFS =
204
+ runActionsBracket'
208
205
(Proxy @ (ModelState R. TableHandle ))
209
206
acquire
210
207
release
211
- (\r session -> runReaderT r (session, handler))
208
+ (\ r (_, session) -> runReaderT r (session, realHandler @ IO ))
209
+ tagFinalState'
212
210
where
213
- acquire :: IO (WrapSession R.TableHandle IO)
211
+ acquire :: IO (StrictTMVar IO MockFS , WrapSession R. TableHandle IO )
214
212
acquire = do
215
- someHasFS <- SomeHasFS <$> simHasFS' MockFS.empty
216
- WrapSession <$> R.openSession someHasFS (mkFsPath [])
217
-
218
- release :: WrapSession R.TableHandle IO -> IO ()
219
- release (WrapSession session) = R.closeSession session
220
-
221
- handler :: Handler IO (Maybe Model.Err)
222
- handler = Handler $ pure . handler'
223
- where
224
- handler' :: IOError -> Maybe Model.Err
225
- handler' _err = Nothing
226
- -}
213
+ fsVar <- newTMVarIO MockFS. empty
214
+ (hfs, hbio) <- simHasBlockIO fsVar
215
+ session <- R. openSession nullTracer hfs hbio (mkFsPath [] )
216
+ pure (fsVar, WrapSession session)
217
+
218
+ release :: (StrictTMVar IO MockFS , WrapSession R. TableHandle IO ) -> IO ()
219
+ release (fsVar, WrapSession session) = do
220
+ R. closeSession session
221
+ mockfs <- atomically $ readTMVar fsVar
222
+ assert (MockFS. numOpenHandles mockfs == 0 ) $ pure ()
223
+
224
+ realHandler :: Monad m => Handler m (Maybe Model. Err )
225
+ realHandler = Handler $ pure . handler'
226
+ where
227
+ handler' :: LSMTreeError -> Maybe Model. Err
228
+ handler' ErrTableClosed = Just Model. ErrTableHandleClosed
229
+ handler' ErrCursorClosed = Just Model. ErrCursorClosed
230
+ handler' (ErrSnapshotNotExists _snap) = Just Model. ErrSnapshotDoesNotExist
231
+ handler' (ErrSnapshotExists _snap) = Just Model. ErrSnapshotExists
232
+ handler' (ErrSnapshotWrongType _snap) = Just Model. ErrSnapshotWrongType
233
+ handler' (ErrBlobRefInvalid _) = Just Model. ErrBlobRefInvalidated
234
+ handler' _ = Nothing
227
235
228
236
createSystemTempDirectory :: [Char ] -> IO (FilePath , HasFS IO HandleIO , HasBlockIO IO HandleIO )
229
237
createSystemTempDirectory prefix = do
@@ -385,7 +393,7 @@ instance ( Show (Class.TableConfig h)
385
393
-- TODO: show instance does not show key-value-blob types. Example:
386
394
--
387
395
-- Normal.StateMachine
388
- -- propLockstepIO_ModelIOImpl : FAIL
396
+ -- prop_lockstepIO_ModelIOImpl : FAIL
389
397
-- *** Failed! Exception: 'open: inappropriate type (table type mismatch)' (after 25 tests and 2 shrinks):
390
398
-- do action $ New TableConfig
391
399
-- action $ Snapshot "snap" (GVar var1 (FromRight . id))
0 commit comments