@@ -12,6 +12,7 @@ import Universum
1212import qualified Cardano.Wallet.Kernel.DB.Sqlite as SQlite
1313import Cardano.Wallet.Kernel.DB.TxMeta
1414import Control.Exception.Safe (bracket )
15+ import Control.Concurrent.Async
1516import qualified Data.List as List
1617import qualified Data.List.NonEmpty as NonEmpty
1718import qualified Data.Set as Set
@@ -25,7 +26,7 @@ import Serokell.Util.Text (listJsonIndent, pairF)
2526import Test.Hspec (expectationFailure , shouldContain , shouldThrow )
2627import Test.Hspec.QuickCheck (prop )
2728import Test.QuickCheck (Arbitrary , Gen , arbitrary , forAll , suchThat ,
28- vectorOf )
29+ vectorOf , withMaxSuccess )
2930import Test.QuickCheck.Monadic (assert , monadicIO , pick , run )
3031import Util.Buildable (ShowThroughBuild (.. ))
3132import Util.Buildable.Hspec
@@ -167,9 +168,103 @@ sortByCreationAt direction = sortBy sortFn
167168hasDupes :: Ord a => [a ] -> Bool
168169hasDupes xs = length (Set. fromList xs) /= List. length xs
169170
171+
172+ threadRead :: Int -> MetaDBHandle -> IO ()
173+ threadRead times hdl = do
174+ let getNoFilters = getTxMetas hdl (Offset 0 ) (Limit 100 ) Everything Nothing NoFilterOp NoFilterOp Nothing
175+ replicateM_ times getNoFilters
176+
177+ threadWrite :: [TxMeta ] -> MetaDBHandle -> IO ()
178+ threadWrite metas hdl = do
179+ let f meta = do
180+ putTxMetaT hdl meta `shouldReturn` Tx
181+ mapM_ f metas
182+
183+ -- here we try to add the same tx 2 times. The second must fail, but without crashing
184+ -- anything, as this is a no-op.
185+ threadWriteWithNoOp :: [TxMeta ] -> MetaDBHandle -> IO ()
186+ threadWriteWithNoOp metas hdl = do
187+ let f meta = do
188+ putTxMetaT hdl meta `shouldReturn` Tx
189+ putTxMetaT hdl meta `shouldReturn` No
190+ mapM_ f metas
191+
170192-- | Specs which tests the persistent storage and API provided by 'TxMeta'.
171193txMetaStorageSpecs :: Spec
172194txMetaStorageSpecs = do
195+ describe " synchronization" $ do
196+ it " synchronized with 2 write workers and no-ops" $ withMaxSuccess 5 $ monadicIO $ do
197+ -- beware of the big data.
198+ testMetas <- pick (genMetas 2000 )
199+ let metas = unSTB <$> testMetas
200+ (meta0, meta1) = splitAt (div 2000 2 ) metas
201+ run $ withTemporaryDb $ \ hdl -> do
202+ t0 <- async $ threadWriteWithNoOp meta0 hdl
203+ t1 <- async $ threadWriteWithNoOp meta1 hdl
204+ _ <- waitAny [t0, t1]
205+ return ()
206+
207+ it " synchronized with 2 write workers and no-ops: correct count" $ withMaxSuccess 5 $ monadicIO $ do
208+ -- beware of the big data.
209+ testMetas <- pick (genMetas 200 )
210+ let metas = unSTB <$> testMetas
211+ (meta0, meta1) = splitAt (div 200 2 ) metas
212+ run $ withTemporaryDb $ \ hdl -> do
213+ t0 <- async $ threadWriteWithNoOp meta0 hdl
214+ t1 <- async $ threadWriteWithNoOp meta1 hdl
215+ _ <- waitAny [t0, t1]
216+ (ls, count) <- getTxMetas hdl (Offset 0 ) (Limit 300 ) Everything Nothing NoFilterOp NoFilterOp Nothing
217+ count `shouldBe` (Just 200 )
218+ length ls `shouldBe` 200
219+ return ()
220+
221+ it " synchronized with 2 write workers" $ withMaxSuccess 5 $ monadicIO $ do
222+ -- beware of the big data.
223+ testMetas <- pick (genMetas 2000 )
224+ let metas = unSTB <$> testMetas
225+ (meta0, meta1) = splitAt (div 2000 2 ) metas
226+ run $ withTemporaryDb $ \ hdl -> do
227+ t0 <- async $ threadWrite meta0 hdl
228+ t1 <- async $ threadWrite meta1 hdl
229+ _ <- waitAny [t0, t1]
230+ return ()
231+
232+ it " synchronized with 2 write workers: correct count" $ withMaxSuccess 5 $ monadicIO $ do
233+ -- beware of the big data.
234+ testMetas <- pick (genMetas 200 )
235+ let metas = unSTB <$> testMetas
236+ (meta0, meta1) = splitAt (div 200 2 ) metas
237+ run $ withTemporaryDb $ \ hdl -> do
238+ t0 <- async $ threadWrite meta0 hdl
239+ t1 <- async $ threadWrite meta1 hdl
240+ _ <- waitAny [t0, t1]
241+ (ls, count) <- getTxMetas hdl (Offset 0 ) (Limit 300 ) Everything Nothing NoFilterOp NoFilterOp Nothing
242+ count `shouldBe` (Just 200 )
243+ length ls `shouldBe` 200
244+ return ()
245+
246+ it " synchronized 1 write and 1 read workers" $ withMaxSuccess 5 $ monadicIO $ do
247+ -- beware of the big data.
248+ testMetas <- pick (genMetas 2000 )
249+ let metas = unSTB <$> testMetas
250+ run $ withTemporaryDb $ \ hdl -> do
251+ t0 <- async $ threadWriteWithNoOp metas hdl
252+ t1 <- async $ threadRead 2000 hdl
253+ _ <- waitAny [t0, t1]
254+ return ()
255+
256+ it " synchronized 1 write and 1 read workers: correct count" $ withMaxSuccess 5 $ monadicIO $ do
257+ -- beware of the big data.
258+ testMetas <- pick (genMetas 200 )
259+ let metas = unSTB <$> testMetas
260+ run $ withTemporaryDb $ \ hdl -> do
261+ t0 <- async $ threadWriteWithNoOp metas hdl
262+ t1 <- async $ threadRead 200 hdl
263+ _ <- waitAny [t0, t1]
264+ (ls, count) <- getTxMetas hdl (Offset 0 ) (Limit 300 ) Everything Nothing NoFilterOp NoFilterOp Nothing
265+ count `shouldBe` (Just 200 )
266+ length ls `shouldBe` 200
267+ return ()
173268
174269 describe " SQlite transactions" $ do
175270 it " throws an exception when tx with double spending" $ monadicIO $ do
0 commit comments