@@ -5,20 +5,24 @@ module Main (main) where
5
5
import Control.Concurrent (modifyMVar_ , newMVar , threadDelay ,
6
6
withMVar )
7
7
import Control.Concurrent.Async
8
- import Control.Exception (SomeException (SomeException ), bracket , try )
8
+ import Control.Exception (Exception (.. ),
9
+ SomeException (SomeException ), bracket , try )
9
10
import Control.Monad
10
11
import Control.Monad.Primitive
11
12
import Data.ByteString (ByteString )
12
13
import qualified Data.ByteString as BS
13
14
import qualified Data.ByteString.Char8 as BSC
15
+ import qualified Data.ByteString.Lazy as LBS
14
16
import Data.Foldable (traverse_ )
15
17
import Data.Functor.Compose (Compose (Compose ))
18
+ import qualified Data.List as List
16
19
import Data.Maybe (catMaybes )
17
20
import Data.Primitive.ByteArray
18
21
import Data.Typeable
19
22
import qualified Data.Vector as V
20
23
import qualified Data.Vector.Unboxed as VU
21
24
import System.FS.API
25
+ import qualified System.FS.API.Lazy as FS
22
26
import qualified System.FS.API.Strict as FS
23
27
import System.FS.API.Strict (hPutAllStrict )
24
28
import qualified System.FS.BlockIO.API as FS
@@ -40,7 +44,18 @@ tests = testGroup "blockio:test" [
40
44
, testCase " example_closeIsIdempotent" example_closeIsIdempotent
41
45
, testProperty " prop_readWrite" prop_readWrite
42
46
, testProperty " prop_submitToClosedCtx" prop_submitToClosedCtx
47
+
48
+ -- Context
49
+ , testProperty " prop_submitIO_contextClosed" prop_submitIO_contextClosed
50
+
51
+ -- Pinned vs. unpinned buffers
52
+ , testProperty " prop_submitIO_buffersPinned" prop_submitIO_buffersPinned
53
+ , testProperty " prop_submitIO_buffersUnpinned" prop_submitIO_buffersUnpinned
54
+
55
+ -- File locks
43
56
, testProperty " prop_tryLockFileExclusiveTwice" prop_tryLockFileExclusiveTwice
57
+
58
+ -- Storage synchronisation
44
59
, testProperty " prop_synchronise" prop_synchronise
45
60
, testProperty " prop_synchroniseFile_fileDoesNotExist"
46
61
prop_synchroniseFile_fileDoesNotExist
@@ -118,6 +133,104 @@ prop_submitToClosedCtx bs = ioProperty $ withSystemTempDirectory "prop_a" $ \dir
118
133
Left _ -> Just $ tabulate " submitIO successful" [show False ] $ counterexample " expected failure, but got success" (b === True )
119
134
Right _ -> Just $ tabulate " submitIO successful" [show True ] $ counterexample " expected success, but got failure" (b === False )
120
135
136
+ {- ------------------------------------------------------------------------------
137
+ Closed context
138
+ -------------------------------------------------------------------------------}
139
+
140
+ -- | Test that 'submitIO' on a closed context returns a "context closed" error
141
+ prop_submitIO_contextClosed :: Property
142
+ prop_submitIO_contextClosed =
143
+ ioProperty $
144
+ withTempIOHasBlockIO " prop_submitIO_unpinnedBuffers" $ \ hfs hbio ->
145
+ FS. withFile hfs path (FS. ReadWriteMode FS. MustBeNew ) $ \ h -> do
146
+ void $ FS. hPutAll hfs h $ LBS. pack [1 .. 100 ]
147
+ buf <- newByteArray 17
148
+ let ioops = V. fromList [
149
+ IOOpWrite h 0 buf 0 17
150
+ , IOOpRead h 0 buf 0 17
151
+ ]
152
+ close hbio
153
+ eith <- try @ FsError $ submitIO hbio ioops
154
+ pure $ case eith of
155
+ Left e
156
+ | isClosedError e
157
+ -> property True
158
+ | otherwise
159
+ -> counterexample (" Unexpected error: " <> displayException e) False
160
+ Right _
161
+ -> counterexample (" Unexpected success" ) False
162
+ where
163
+ path = FS. mkFsPath [" temp-file" ]
164
+
165
+ -- TODO: add a property that checks @isClosedError . mkClosedError = True@
166
+ isClosedError :: FsError -> Bool
167
+ isClosedError e
168
+ -- TODO: add an FsResourceVanished constructor to FsErrorType?
169
+ | fsErrorType e == FsOther
170
+ , " HasBlockIO closed: " `List.isPrefixOf` (fsErrorString e)
171
+ = True
172
+ | otherwise
173
+ = False
174
+
175
+ {- ------------------------------------------------------------------------------
176
+ Pinned vs. unpinned buffers
177
+ -------------------------------------------------------------------------------}
178
+
179
+ -- | Test that 'submitIO' using pinned buffers returns /no/ "unpinned buffers"
180
+ -- error
181
+ prop_submitIO_buffersPinned :: Property
182
+ prop_submitIO_buffersPinned =
183
+ ioProperty $
184
+ withTempIOHasBlockIO " prop_submitIO_pinnedBuffers" $ \ hfs hbio ->
185
+ FS. withFile hfs path (FS. ReadWriteMode FS. MustBeNew ) $ \ h -> do
186
+ void $ FS. hPutAll hfs h $ LBS. pack [1 .. 100 ]
187
+ buf <- newPinnedByteArray 17
188
+ let ioops = V. fromList [
189
+ IOOpWrite h 0 buf 0 17
190
+ , IOOpRead h 0 buf 0 17
191
+ ]
192
+ eith <- try @ FsError $ submitIO hbio ioops
193
+ pure $ case eith of
194
+ Left e
195
+ -> counterexample (" Unexpected error: " <> displayException e) False
196
+ Right _
197
+ -> property True
198
+ where
199
+ path = FS. mkFsPath [" temp-file" ]
200
+
201
+ -- | Test that 'submitIO' using unpinned buffers returns an "unpinned buffers" error
202
+ prop_submitIO_buffersUnpinned :: Property
203
+ prop_submitIO_buffersUnpinned =
204
+ ioProperty $
205
+ withTempIOHasBlockIO " prop_submitIO_unpinnedBuffers" $ \ hfs hbio ->
206
+ FS. withFile hfs path (FS. ReadWriteMode FS. MustBeNew ) $ \ h -> do
207
+ void $ FS. hPutAll hfs h $ LBS. pack [1 .. 100 ]
208
+ buf <- newByteArray 17
209
+ let ioops = V. fromList [
210
+ IOOpWrite h 0 buf 0 17
211
+ , IOOpRead h 0 buf 0 17
212
+ ]
213
+ eith <- try @ FsError $ submitIO hbio ioops
214
+ pure $ case eith of
215
+ Left e
216
+ | isNotPinnedError e
217
+ -> property True
218
+ | otherwise
219
+ -> counterexample (" Unexpected error: " <> displayException e) False
220
+ Right _
221
+ -> counterexample (" Unexpected success" ) False
222
+ where
223
+ path = FS. mkFsPath [" temp-file" ]
224
+
225
+ -- TODO: add a property that checks @isNotPinnedError . mkNotPinnedError = True@
226
+ isNotPinnedError :: FsError -> Bool
227
+ isNotPinnedError e
228
+ | fsErrorType e == FsInvalidArgument
229
+ , " MutableByteArray is unpinned: " `List.isPrefixOf` (fsErrorString e)
230
+ = True
231
+ | otherwise
232
+ = False
233
+
121
234
{- ------------------------------------------------------------------------------
122
235
File locks
123
236
-------------------------------------------------------------------------------}
0 commit comments