github.com/status-im/status-go@v1.1.0/services/wallet/transfer/concurrent_test.go (about) 1 package transfer 2 3 import ( 4 "context" 5 "errors" 6 "math/big" 7 "sort" 8 "testing" 9 "time" 10 11 "github.com/status-im/status-go/services/wallet/balance" 12 13 "github.com/stretchr/testify/require" 14 15 "github.com/ethereum/go-ethereum/core/types" 16 17 "github.com/ethereum/go-ethereum/common" 18 ) 19 20 func TestConcurrentErrorInterrupts(t *testing.T) { 21 concurrent := NewConcurrentDownloader(context.Background(), NoThreadLimit) 22 var interrupted bool 23 concurrent.Add(func(ctx context.Context) error { 24 select { 25 case <-ctx.Done(): 26 interrupted = true 27 case <-time.After(10 * time.Second): 28 } 29 return nil 30 }) 31 err := errors.New("interrupt") 32 concurrent.Add(func(ctx context.Context) error { 33 return err 34 }) 35 concurrent.Wait() 36 require.True(t, interrupted) 37 require.Equal(t, err, concurrent.Error()) 38 } 39 40 func TestConcurrentCollectsTransfers(t *testing.T) { 41 concurrent := NewConcurrentDownloader(context.Background(), NoThreadLimit) 42 concurrent.Add(func(context.Context) error { 43 concurrent.Push(Transfer{}) 44 return nil 45 }) 46 concurrent.Add(func(context.Context) error { 47 concurrent.Push(Transfer{}) 48 return nil 49 }) 50 concurrent.Wait() 51 require.Len(t, concurrent.Get(), 2) 52 } 53 54 type balancesFixture []*big.Int 55 56 func (f balancesFixture) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { 57 index := int(blockNumber.Int64()) 58 if index > len(f)-1 { 59 return nil, errors.New("balance unknown") 60 } 61 return f[index], nil 62 } 63 64 func (f balancesFixture) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { 65 return uint64(0), nil 66 } 67 68 func (f balancesFixture) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { 69 return &types.Header{ 70 Number: number, 71 }, nil 72 } 73 74 func (f balancesFixture) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 75 return &types.Header{ 76 Number: big.NewInt(0), 77 }, nil 78 } 79 80 func (f balancesFixture) NetworkID() uint64 { 81 return 0 82 } 83 84 func (f balancesFixture) CallBlockHashByTransaction(ctx context.Context, blockNumber *big.Int, index uint) (common.Hash, error) { 85 return common.HexToHash("0x0"), nil 86 } 87 88 type batchesFixture [][]Transfer 89 90 func (f batchesFixture) GetTransfersByNumber(ctx context.Context, number *big.Int) (rst []Transfer, err error) { 91 index := int(number.Int64()) 92 if index > len(f)-1 { 93 return nil, errors.New("unknown block") 94 } 95 return f[index], nil 96 } 97 98 func TestConcurrentEthDownloader(t *testing.T) { 99 type options struct { 100 balances balancesFixture 101 batches batchesFixture 102 result []DBHeader 103 last *big.Int 104 } 105 type testCase struct { 106 desc string 107 options options 108 } 109 for _, tc := range []testCase{ 110 { 111 desc: "NoBalances", 112 options: options{ 113 last: big.NewInt(3), 114 balances: balancesFixture{big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0)}, 115 }, 116 }, 117 { 118 desc: "LastBlock", 119 options: options{ 120 last: big.NewInt(3), 121 balances: balancesFixture{big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(10)}, 122 batches: batchesFixture{{}, {}, {}, {{BlockNumber: big.NewInt(3)}, {BlockNumber: big.NewInt(3)}}}, 123 result: []DBHeader{{Number: big.NewInt(3)}}, 124 }, 125 }, 126 { 127 desc: "ChangesInEveryBlock", 128 options: options{ 129 last: big.NewInt(3), 130 balances: balancesFixture{big.NewInt(0), big.NewInt(3), big.NewInt(7), big.NewInt(10)}, 131 batches: batchesFixture{{}, {{BlockNumber: big.NewInt(1)}}, {{BlockNumber: big.NewInt(2)}}, {{BlockNumber: big.NewInt(3)}}}, 132 result: []DBHeader{{Number: big.NewInt(1)}, {Number: big.NewInt(2)}, {Number: big.NewInt(3)}}, 133 }, 134 }, 135 } { 136 t.Run(tc.desc, func(t *testing.T) { 137 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 138 defer cancel() 139 concurrent := NewConcurrentDownloader(ctx, 0) 140 _, headers, _, _ := findBlocksWithEthTransfers( 141 ctx, tc.options.balances, balance.NewCacherWithTTL(5*time.Minute), 142 common.Address{}, zero, tc.options.last, false, NoThreadLimit) 143 concurrent.Wait() 144 require.NoError(t, concurrent.Error()) 145 rst := concurrent.Get() 146 require.Len(t, headers, len(tc.options.result)) 147 sort.Slice(rst, func(i, j int) bool { 148 return rst[i].BlockNumber.Cmp(rst[j].BlockNumber) < 0 149 }) 150 /*for i := range rst { 151 require.Equal(t, tc.options.result[i].BlockNumber, rst[i].BlockNumber) 152 }*/ 153 }) 154 } 155 }