Skip to content
This repository was archived by the owner on Aug 18, 2020. It is now read-only.

Commit 5df33c5

Browse files
authored
Merge pull request #3469 from input-output-hk/paweljakubas/CBR-366/add-tests-for-account-partial-getters
[CBR-366] Adding test for partial getters
2 parents 68ddd2e + 0843b3d commit 5df33c5

File tree

2 files changed

+247
-8
lines changed

2 files changed

+247
-8
lines changed

integration/AccountSpecs.hs

+56-1
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@ import Universum
77

88
import Cardano.Wallet.API.Indices (accessIx)
99
import Cardano.Wallet.Client.Http
10+
import Control.Concurrent (threadDelay)
1011
import Control.Lens
1112
import Pos.Core.Common (mkCoin)
1213
import Test.Hspec
14+
import Test.QuickCheck (arbitrary, generate, shuffle)
1315
import Util
1416

1517
import qualified Pos.Core as Core
1618
import qualified Prelude
1719

1820

1921
accountSpecs :: WalletRef -> WalletClient IO -> Spec
20-
accountSpecs _ wc =
22+
accountSpecs wRef wc =
2123
describe "Accounts" $ do
2224
it "can retrieve only an account's balance" $ do
2325
let zero = V1 (mkCoin 0)
@@ -43,6 +45,59 @@ accountSpecs _ wc =
4345
forM_ tests $ \PaginationTest{..} -> do
4446
eresp <- getAccountAddresses wc walId accIndex page perPage filters
4547
expectations . acaAddresses . wrData =<< eresp `shouldPrism` _Right
48+
it "can retrieve initial and updated balances of several account from getAccountBalances that are equivalent to what is obtained from getAccount" $ do
49+
genesis <- genesisWallet wc
50+
(fromAcct, _) <- firstAccountAndId wc genesis
51+
52+
wallet <- sampleWallet wRef wc
53+
-- We create 4 accounts, plus one is created automatically
54+
-- by the 'sampleWallet', for a total of 5.
55+
randomNewAccount <- forM [1..4] $ \(_i :: Int) ->
56+
generate arbitrary :: IO NewAccount
57+
forM_ randomNewAccount $ \(rAcc :: NewAccount) ->
58+
postAccount wc (walId wallet) rAcc
59+
60+
accResp' <- getAccounts wc (walId wallet)
61+
accs <- wrData <$> accResp' `shouldPrism` _Right
62+
63+
balancesPartialResp' <- forM (map accIndex accs) $ \(accIndex :: AccountIndex) ->
64+
getAccountBalance wc (walId wallet) accIndex
65+
66+
balancesPartial <- mapM (\resp -> wrData <$> resp `shouldPrism` _Right) balancesPartialResp'
67+
68+
map (AccountBalance . accAmount) accs `shouldBe` balancesPartial
69+
70+
-- Now transfering money to 5 accounts from genesis wallet and checking balances once again
71+
let payment amount toAddr = Payment
72+
{ pmtSource = PaymentSource
73+
{ psWalletId = walId genesis
74+
, psAccountIndex = accIndex fromAcct
75+
}
76+
, pmtDestinations = pure PaymentDistribution
77+
{ pdAddress = addrId toAddr
78+
, pdAmount = V1 (Core.mkCoin amount)
79+
}
80+
, pmtGroupingPolicy = Nothing
81+
, pmtSpendingPassword = Nothing
82+
}
83+
amounts <- generate $ shuffle [1..5]
84+
let addrAndAmount = zip (map (\(addr : _) -> addr) $ map accAddresses accs) amounts
85+
forM_ addrAndAmount $ \(addr, amount) ->
86+
postTransaction wc (payment amount addr)
87+
88+
threadDelay 120000000
89+
90+
accUpdatedResp' <- getAccounts wc (walId wallet)
91+
accsUpdated <- wrData <$> accUpdatedResp' `shouldPrism` _Right
92+
93+
balancesPartialUpdatedResp' <- forM (map accIndex accsUpdated) $
94+
\(accIndex :: AccountIndex) -> getAccountBalance wc (walId wallet) accIndex
95+
96+
balancesPartialUpdated <-
97+
mapM (\resp -> wrData <$> resp `shouldPrism` _Right) balancesPartialUpdatedResp'
98+
99+
map (AccountBalance . accAmount) accsUpdated `shouldBe` balancesPartialUpdated
100+
46101
where
47102
filterByAddress :: WalletAddress -> FilterOperations '[V1 Address] WalletAddress
48103
filterByAddress addr =

test/unit/Test/Spec/Accounts.hs

+191-7
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,25 @@ import qualified Test.Spec.Wallets as Wallets
1212

1313
import Formatting (build, formatToString, (%))
1414

15-
import Cardano.Wallet.Kernel.Accounts (CreateAccountError (..))
16-
import qualified Cardano.Wallet.Kernel.DB.HdWallet as Kernel
17-
import qualified Cardano.Wallet.Kernel.Internal as Internal
18-
import qualified Cardano.Wallet.Kernel.Keystore as Keystore
19-
import Cardano.Wallet.WalletLayer (PassiveWalletLayer)
20-
import qualified Cardano.Wallet.WalletLayer as WalletLayer
21-
2215
import qualified Cardano.Wallet.API.Request as API
2316
import qualified Cardano.Wallet.API.Request.Pagination as API
2417
import qualified Cardano.Wallet.API.Response as API
2518
import Cardano.Wallet.API.V1.Handlers.Accounts as Handlers
2619
import Cardano.Wallet.API.V1.Types (V1 (..))
2720
import qualified Cardano.Wallet.API.V1.Types as V1
21+
import Cardano.Wallet.Kernel.Accounts (CreateAccountError (..))
22+
import qualified Cardano.Wallet.Kernel.DB.HdWallet as Kernel
2823
import qualified Cardano.Wallet.Kernel.DB.Util.IxSet as IxSet
24+
import qualified Cardano.Wallet.Kernel.Internal as Internal
25+
import qualified Cardano.Wallet.Kernel.Keystore as Keystore
26+
import Cardano.Wallet.WalletLayer (PassiveWalletLayer)
27+
import qualified Cardano.Wallet.WalletLayer as WalletLayer
2928
import qualified Cardano.Wallet.WalletLayer.Kernel.Wallets as Wallets
3029
import Control.Monad.Except (runExceptT)
3130
import Servant.Server
3231

32+
import Pos.Core.Common (mkCoin)
33+
3334
import Test.Spec.Fixture (GenPassiveWalletFixture,
3435
genSpendingPassword, withLayer, withPassiveWalletFixture)
3536
import Util.Buildable (ShowThroughBuild (..))
@@ -367,3 +368,186 @@ spec = describe "Accounts" $ do
367368
case res of
368369
Left e -> fail (show e)
369370
Right wr -> (length $ API.wrData wr) `shouldBe` 5
371+
372+
373+
describe "GetAccountAddresses" $ do
374+
375+
prop "fails if the account doesn't exists" $ withMaxSuccess 50 $ do
376+
monadicIO $ do
377+
withFixture $ \_ layer _ Fixture{..} -> do
378+
let params = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
379+
let filters = API.NoFilters
380+
res <- WalletLayer.getAccountAddresses layer
381+
(V1.walId fixtureV1Wallet)
382+
(V1.unsafeMkAccountIndex 2147483648)
383+
params
384+
filters
385+
case res of
386+
Left (WalletLayer.GetAccountError (V1 (Kernel.UnknownHdAccount _))) ->
387+
return ()
388+
Left unexpectedErr ->
389+
fail $ "expecting different failure than " <> show unexpectedErr
390+
Right _ ->
391+
let errMsg = "expecting account not to be retrieved, but it was. random WalletId "
392+
% build
393+
% " , V1.Wallet "
394+
in fail $ formatToString errMsg (V1.walId fixtureV1Wallet)
395+
396+
397+
prop "applied to each newly created accounts gives addresses as obtained from GetAccounts" $ withMaxSuccess 25 $ do
398+
monadicIO $ do
399+
withFixture $ \_ layer _ Fixture{..} -> do
400+
-- We create 4 accounts, plus one is created automatically
401+
-- by the 'createWallet' endpoint, for a total of 5.
402+
forM_ [1..4] $ \(_i :: Int) ->
403+
WalletLayer.createAccount layer (V1.walId fixtureV1Wallet)
404+
fixtureNewAccountRq
405+
accounts <- WalletLayer.getAccounts layer (V1.walId fixtureV1Wallet)
406+
let accountIndices =
407+
case accounts of
408+
Left _ -> []
409+
Right accs -> map V1.accIndex $ IxSet.toList accs
410+
let params = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
411+
let filters = API.NoFilters
412+
partialAddresses <- forM accountIndices $ \(ind :: V1.AccountIndex) ->
413+
WalletLayer.getAccountAddresses layer (V1.walId fixtureV1Wallet) ind params filters
414+
case accounts of
415+
Right accs -> (map V1.accAddresses $ IxSet.toList accs)
416+
`shouldBe`
417+
(map (\(Right addr) -> API.wrData addr) partialAddresses)
418+
Left err -> fail (show err)
419+
420+
421+
prop "and this also works when called from Servant" $ withMaxSuccess 25 $ do
422+
monadicIO $ do
423+
withFixture $ \_ layer _ Fixture{..} -> do
424+
let create = Handlers.newAccount layer (V1.walId fixtureV1Wallet) fixtureNewAccountRq
425+
-- We create 4 accounts, plus one is created automatically
426+
-- by the 'createWallet' endpoint, for a total of 5.
427+
forM_ [1..4] $ \(_i :: Int) -> runExceptT . runHandler' $ create
428+
let params = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
429+
let fetchForAccounts = Handlers.listAccounts layer (V1.walId fixtureV1Wallet) params
430+
accounts <- runExceptT . runHandler' $ fetchForAccounts
431+
let accountIndices =
432+
case accounts of
433+
Left _ -> []
434+
Right accs -> map V1.accIndex $ API.wrData accs
435+
let reqParams = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
436+
let filters = API.NoFilters
437+
let fetchForAccountAddresses ind =
438+
Handlers.getAccountAddresses layer (V1.walId fixtureV1Wallet)
439+
ind reqParams filters
440+
partialAddresses <- forM accountIndices $ \(ind :: V1.AccountIndex) ->
441+
runExceptT . runHandler' $ fetchForAccountAddresses ind
442+
case accounts of
443+
Right accs -> (map V1.accAddresses $ API.wrData accs)
444+
`shouldBe`
445+
(map (\(Right bal) -> (V1.acaAddresses . API.wrData) bal) partialAddresses)
446+
Left err -> fail (show err)
447+
448+
449+
prop "applied to accounts that were just updated via address creation is the same as obtained from GetAccounts" $ withMaxSuccess 25 $ do
450+
monadicIO $ do
451+
withFixture $ \_ layer _ Fixture{..} -> do
452+
-- We create 4 accounts, plus one is created automatically
453+
-- by the 'createWallet' endpoint, for a total of 5.
454+
forM_ [1..4] $ \(_i :: Int) ->
455+
WalletLayer.createAccount layer (V1.walId fixtureV1Wallet)
456+
fixtureNewAccountRq
457+
accountsBefore <- WalletLayer.getAccounts layer (V1.walId fixtureV1Wallet)
458+
let accountIndices =
459+
case accountsBefore of
460+
Left _ -> []
461+
Right accs -> map V1.accIndex $ IxSet.toList accs
462+
forM_ accountIndices $ \(accIdx :: V1.AccountIndex) ->
463+
WalletLayer.createAddress layer (V1.NewAddress Nothing accIdx (V1.walId fixtureV1Wallet))
464+
accountsUpdated <- WalletLayer.getAccounts layer (V1.walId fixtureV1Wallet)
465+
let params = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
466+
let filters = API.NoFilters
467+
partialAddresses <- forM accountIndices $ \(ind :: V1.AccountIndex) ->
468+
WalletLayer.getAccountAddresses layer (V1.walId fixtureV1Wallet) ind params filters
469+
case accountsUpdated of
470+
Right accs -> (map V1.accAddresses $ IxSet.toList accs)
471+
`shouldBe`
472+
(map (\(Right addr) -> API.wrData addr) partialAddresses)
473+
Left err -> fail (show err)
474+
475+
476+
describe "GetAccountBalance" $ do
477+
478+
prop "gives zero balance for newly created account" $ withMaxSuccess 25 $ do
479+
monadicIO $ do
480+
withFixture $ \_ layer _ Fixture{..} -> do
481+
let zero = V1 (mkCoin 0)
482+
(Right V1.Account{..}) <-
483+
WalletLayer.createAccount layer (V1.walId fixtureV1Wallet)
484+
fixtureNewAccountRq
485+
res <- WalletLayer.getAccountBalance layer (V1.walId fixtureV1Wallet)
486+
accIndex
487+
case res of
488+
Left e -> fail (show e)
489+
Right balance -> balance `shouldBe` V1.AccountBalance zero
490+
491+
prop "fails if the account doesn't exists" $ withMaxSuccess 50 $ do
492+
monadicIO $ do
493+
withFixture $ \_ layer _ Fixture{..} -> do
494+
res <- WalletLayer.getAccountBalance layer
495+
(V1.walId fixtureV1Wallet)
496+
(V1.unsafeMkAccountIndex 2147483648)
497+
case res of
498+
Left (WalletLayer.GetAccountError (V1 (Kernel.UnknownHdAccount _))) ->
499+
return ()
500+
Left unexpectedErr ->
501+
fail $ "expecting different failure than " <> show unexpectedErr
502+
Right _ ->
503+
let errMsg = "expecting account not to be retrieved, but it was. random WalletId "
504+
% build
505+
% " , V1.Wallet "
506+
in fail $ formatToString errMsg (V1.walId fixtureV1Wallet)
507+
508+
509+
510+
prop "applied to each newly created account gives balances as obtained from GetAccounts" $ withMaxSuccess 25 $ do
511+
monadicIO $ do
512+
withFixture $ \_ layer _ Fixture{..} -> do
513+
-- We create 4 accounts, plus one is created automatically
514+
-- by the 'createWallet' endpoint, for a total of 5.
515+
forM_ [1..4] $ \(_i :: Int) ->
516+
WalletLayer.createAccount layer (V1.walId fixtureV1Wallet)
517+
fixtureNewAccountRq
518+
accounts <- WalletLayer.getAccounts layer (V1.walId fixtureV1Wallet)
519+
let accountIndices =
520+
case accounts of
521+
Left _ -> []
522+
Right accs -> map V1.accIndex $ IxSet.toList accs
523+
partialBalances <- forM accountIndices $ \(ind :: V1.AccountIndex) ->
524+
WalletLayer.getAccountBalance layer (V1.walId fixtureV1Wallet) ind
525+
case (accounts, length partialBalances /= 5) of
526+
(Right accs, False) -> (map (V1.AccountBalance . V1.accAmount) $ IxSet.toList accs)
527+
`shouldBe`
528+
(map (\(Right bal) -> bal) partialBalances)
529+
_ -> fail "expecting to get 5 balances from partial getters"
530+
531+
532+
prop "and this also works when called from Servant" $ withMaxSuccess 25 $ do
533+
monadicIO $ do
534+
withFixture $ \_ layer _ Fixture{..} -> do
535+
let create = Handlers.newAccount layer (V1.walId fixtureV1Wallet) fixtureNewAccountRq
536+
-- We create 4 accounts, plus one is created automatically
537+
-- by the 'createWallet' endpoint, for a total of 5.
538+
forM_ [1..4] $ \(_i :: Int) -> runExceptT . runHandler' $ create
539+
let params = API.RequestParams (API.PaginationParams (API.Page 1) (API.PerPage 10))
540+
let fetchForAccounts = Handlers.listAccounts layer (V1.walId fixtureV1Wallet) params
541+
accounts <- runExceptT . runHandler' $ fetchForAccounts
542+
let accountIndices =
543+
case accounts of
544+
Left _ -> []
545+
Right accs -> map V1.accIndex $ API.wrData accs
546+
let fetchForAccountBalance = Handlers.getAccountBalance layer (V1.walId fixtureV1Wallet)
547+
partialBalances <- forM accountIndices $ \(ind :: V1.AccountIndex) ->
548+
runExceptT . runHandler' $ fetchForAccountBalance ind
549+
case (accounts, length partialBalances /= 5) of
550+
(Right accs, False) -> (map (V1.AccountBalance . V1.accAmount) $ API.wrData accs)
551+
`shouldBe`
552+
(map (\(Right bal) -> API.wrData bal) partialBalances)
553+
_ -> fail "expecting to get 5 balances from partial getters"

0 commit comments

Comments
 (0)