From 29c5534f216968365c2d67649b30ee22504502b7 Mon Sep 17 00:00:00 2001 From: Dmitry Shulyak Date: Wed, 3 Jan 2018 13:01:00 +0200 Subject: [PATCH] Add mock generation to makefile and cleanup tests --- Makefile | 1 + geth/txqueue/ethtxclient.go | 4 +- geth/txqueue/fake/mock.go | 73 ++++++++++----------- geth/txqueue/fake/txservice.go | 14 ++-- geth/txqueue/txqueue_manager.go | 22 +++---- geth/txqueue/txqueue_manager_test.go | 98 +++++++++++++++------------- testing/testing.go | 17 +++++ 7 files changed, 124 insertions(+), 105 deletions(-) diff --git a/Makefile b/Makefile index 7039c58991d..0cb729f3bb6 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ mock: ##@other Regenerate mocks mockgen -source=geth/mailservice/mailservice.go -destination=geth/mailservice/mailservice_mock.go -package=mailservice mockgen -source=geth/common/notification.go -destination=geth/common/notification_mock.go -package=common -imports fcm=github.com/NaySoftware/go-fcm mockgen -source=geth/notification/fcm/client.go -destination=geth/notification/fcm/client_mock.go -package=fcm -imports fcm=github.com/NaySoftware/go-fcm + mockgen -source=geth/txqueue/fake/txservice.go -destination=geth/txqueue/fake/mock.go -package=fake test: test-unit-coverage ##@tests Run basic, short tests during development diff --git a/geth/txqueue/ethtxclient.go b/geth/txqueue/ethtxclient.go index 59084d851dc..d83d8da942c 100644 --- a/geth/txqueue/ethtxclient.go +++ b/geth/txqueue/ethtxclient.go @@ -12,8 +12,8 @@ import ( "github.com/status-im/status-go/geth/rpc" ) -// EthereumTransactor provides methods to create transactions for ethereum network. -type EthereumTransactor interface { +// EthTransactor provides methods to create transactions for ethereum network. +type EthTransactor interface { PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) ethereum.GasEstimator ethereum.GasPricer diff --git a/geth/txqueue/fake/mock.go b/geth/txqueue/fake/mock.go index 13dce62a42f..0e002858ec1 100644 --- a/geth/txqueue/fake/mock.go +++ b/geth/txqueue/fake/mock.go @@ -1,91 +1,90 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/status-im/status-go/geth/txqueue/fake (interfaces: FakePublicTxApi) +// Source: geth/txqueue/fake/txservice.go // Package fake is a generated GoMock package. package fake import ( context "context" - big "math/big" - reflect "reflect" - common "github.com/ethereum/go-ethereum/common" hexutil "github.com/ethereum/go-ethereum/common/hexutil" rpc "github.com/ethereum/go-ethereum/rpc" gomock "github.com/golang/mock/gomock" + big "math/big" + reflect "reflect" ) -// MockFakePublicTxApi is a mock of FakePublicTxApi interface -type MockFakePublicTxApi struct { +// MockFakePublicTransactionPoolAPI is a mock of FakePublicTransactionPoolAPI interface +type MockFakePublicTransactionPoolAPI struct { ctrl *gomock.Controller - recorder *MockFakePublicTxApiMockRecorder + recorder *MockFakePublicTransactionPoolAPIMockRecorder } -// MockFakePublicTxApiMockRecorder is the mock recorder for MockFakePublicTxApi -type MockFakePublicTxApiMockRecorder struct { - mock *MockFakePublicTxApi +// MockFakePublicTransactionPoolAPIMockRecorder is the mock recorder for MockFakePublicTransactionPoolAPI +type MockFakePublicTransactionPoolAPIMockRecorder struct { + mock *MockFakePublicTransactionPoolAPI } -// NewMockFakePublicTxApi creates a new mock instance -func NewMockFakePublicTxApi(ctrl *gomock.Controller) *MockFakePublicTxApi { - mock := &MockFakePublicTxApi{ctrl: ctrl} - mock.recorder = &MockFakePublicTxApiMockRecorder{mock} +// NewMockFakePublicTransactionPoolAPI creates a new mock instance +func NewMockFakePublicTransactionPoolAPI(ctrl *gomock.Controller) *MockFakePublicTransactionPoolAPI { + mock := &MockFakePublicTransactionPoolAPI{ctrl: ctrl} + mock.recorder = &MockFakePublicTransactionPoolAPIMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use -func (m *MockFakePublicTxApi) EXPECT() *MockFakePublicTxApiMockRecorder { +func (m *MockFakePublicTransactionPoolAPI) EXPECT() *MockFakePublicTransactionPoolAPIMockRecorder { return m.recorder } -// EstimateGas mocks base method -func (m *MockFakePublicTxApi) EstimateGas(arg0 context.Context, arg1 CallArgs) (*hexutil.Big, error) { - ret := m.ctrl.Call(m, "EstimateGas", arg0, arg1) - ret0, _ := ret[0].(*hexutil.Big) +// GasPrice mocks base method +func (m *MockFakePublicTransactionPoolAPI) GasPrice(ctx context.Context) (*big.Int, error) { + ret := m.ctrl.Call(m, "GasPrice", ctx) + ret0, _ := ret[0].(*big.Int) ret1, _ := ret[1].(error) return ret0, ret1 } -// EstimateGas indicates an expected call of EstimateGas -func (mr *MockFakePublicTxApiMockRecorder) EstimateGas(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockFakePublicTxApi)(nil).EstimateGas), arg0, arg1) +// GasPrice indicates an expected call of GasPrice +func (mr *MockFakePublicTransactionPoolAPIMockRecorder) GasPrice(ctx interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GasPrice", reflect.TypeOf((*MockFakePublicTransactionPoolAPI)(nil).GasPrice), ctx) } -// GasPrice mocks base method -func (m *MockFakePublicTxApi) GasPrice(arg0 context.Context) (*big.Int, error) { - ret := m.ctrl.Call(m, "GasPrice", arg0) - ret0, _ := ret[0].(*big.Int) +// EstimateGas mocks base method +func (m *MockFakePublicTransactionPoolAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { + ret := m.ctrl.Call(m, "EstimateGas", ctx, args) + ret0, _ := ret[0].(*hexutil.Big) ret1, _ := ret[1].(error) return ret0, ret1 } -// GasPrice indicates an expected call of GasPrice -func (mr *MockFakePublicTxApiMockRecorder) GasPrice(arg0 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GasPrice", reflect.TypeOf((*MockFakePublicTxApi)(nil).GasPrice), arg0) +// EstimateGas indicates an expected call of EstimateGas +func (mr *MockFakePublicTransactionPoolAPIMockRecorder) EstimateGas(ctx, args interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EstimateGas", reflect.TypeOf((*MockFakePublicTransactionPoolAPI)(nil).EstimateGas), ctx, args) } // GetTransactionCount mocks base method -func (m *MockFakePublicTxApi) GetTransactionCount(arg0 context.Context, arg1 common.Address, arg2 rpc.BlockNumber) (*hexutil.Uint64, error) { - ret := m.ctrl.Call(m, "GetTransactionCount", arg0, arg1, arg2) +func (m *MockFakePublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { + ret := m.ctrl.Call(m, "GetTransactionCount", ctx, address, blockNr) ret0, _ := ret[0].(*hexutil.Uint64) ret1, _ := ret[1].(error) return ret0, ret1 } // GetTransactionCount indicates an expected call of GetTransactionCount -func (mr *MockFakePublicTxApiMockRecorder) GetTransactionCount(arg0, arg1, arg2 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionCount", reflect.TypeOf((*MockFakePublicTxApi)(nil).GetTransactionCount), arg0, arg1, arg2) +func (mr *MockFakePublicTransactionPoolAPIMockRecorder) GetTransactionCount(ctx, address, blockNr interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionCount", reflect.TypeOf((*MockFakePublicTransactionPoolAPI)(nil).GetTransactionCount), ctx, address, blockNr) } // SendRawTransaction mocks base method -func (m *MockFakePublicTxApi) SendRawTransaction(arg0 context.Context, arg1 hexutil.Bytes) (common.Hash, error) { - ret := m.ctrl.Call(m, "SendRawTransaction", arg0, arg1) +func (m *MockFakePublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { + ret := m.ctrl.Call(m, "SendRawTransaction", ctx, encodedTx) ret0, _ := ret[0].(common.Hash) ret1, _ := ret[1].(error) return ret0, ret1 } // SendRawTransaction indicates an expected call of SendRawTransaction -func (mr *MockFakePublicTxApiMockRecorder) SendRawTransaction(arg0, arg1 interface{}) *gomock.Call { - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendRawTransaction", reflect.TypeOf((*MockFakePublicTxApi)(nil).SendRawTransaction), arg0, arg1) +func (mr *MockFakePublicTransactionPoolAPIMockRecorder) SendRawTransaction(ctx, encodedTx interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendRawTransaction", reflect.TypeOf((*MockFakePublicTransactionPoolAPI)(nil).SendRawTransaction), ctx, encodedTx) } diff --git a/geth/txqueue/fake/txservice.go b/geth/txqueue/fake/txservice.go index 80eb207f67e..ee2a8834a0b 100644 --- a/geth/txqueue/fake/txservice.go +++ b/geth/txqueue/fake/txservice.go @@ -1,18 +1,18 @@ package fake import ( - context "context" - big "math/big" + "context" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/rpc" - gomock "github.com/golang/mock/gomock" + "github.com/golang/mock/gomock" ) -func NewTestServer(ctrl *gomock.Controller) (*rpc.Server, *MockFakePublicTxApi) { +func NewTestServer(ctrl *gomock.Controller) (*rpc.Server, *MockFakePublicTransactionPoolAPI) { srv := rpc.NewServer() - svc := NewMockFakePublicTxApi(ctrl) + svc := NewMockFakePublicTransactionPoolAPI(ctrl) if err := srv.RegisterName("eth", svc); err != nil { panic(err) } @@ -29,10 +29,10 @@ type CallArgs struct { Data hexutil.Bytes `json:"data"` } -// FakePublicTxApi used to generate mock by mockgen util. +// FakePublicTransactionPoolAPI used to generate mock by mockgen util. // This was done because PublicTransactionPoolAPI is located in internal/ethapi module // and there is no easy way to generate mocks from internal modules. -type FakePublicTxApi interface { +type FakePublicTransactionPoolAPI interface { GasPrice(ctx context.Context) (*big.Int, error) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) diff --git a/geth/txqueue/txqueue_manager.go b/geth/txqueue/txqueue_manager.go index d9b455586fc..ca5f16c8cd7 100644 --- a/geth/txqueue/txqueue_manager.go +++ b/geth/txqueue/txqueue_manager.go @@ -27,7 +27,7 @@ const ( defaultGas = 90000 - cancelTimeout = time.Minute + defaultTimeout = time.Minute ) // Send transaction response codes @@ -51,7 +51,7 @@ type Manager struct { nodeManager common.NodeManager accountManager common.AccountManager txQueue *TxQueue - ethTxClient EthereumTransactor + ethTxClient EthTransactor addrLock *AddrLocker } @@ -164,7 +164,7 @@ func (m *Manager) CompleteTransaction(id common.QueuedTxID, password string) (ge return gethcommon.Hash{}, ErrInvalidCompleteTxSender } // Send the transaction finally. - hash, err := m.completeTransaction(selectedAccount, queuedTx, password) + hash, err := m.completeTransaction(queuedTx, selectedAccount, password) // when incorrect sender tries to complete the account, // notify and keep tx in queue (so that correct sender can complete) @@ -183,10 +183,9 @@ func (m *Manager) CompleteTransaction(id common.QueuedTxID, password string) (ge return hash, err } -func (m *Manager) completeTransaction(selectedAccount *common.SelectedExtKey, queuedTx *common.QueuedTx, password string) (gethcommon.Hash, error) { +func (m *Manager) completeTransaction(queuedTx *common.QueuedTx, selectedAccount *common.SelectedExtKey, password string) (gethcommon.Hash, error) { log.Info("complete transaction", "id", queuedTx.ID) var emptyHash gethcommon.Hash - log.Info("verifying account password for transaction", "id", queuedTx.ID) config, err := m.nodeManager.NodeConfig() if err != nil { return emptyHash, err @@ -198,7 +197,7 @@ func (m *Manager) completeTransaction(selectedAccount *common.SelectedExtKey, qu } // update transaction with nonce, gas price and gas estimates - ctx, cancel := context.WithTimeout(context.Background(), cancelTimeout) + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) defer cancel() m.addrLock.LockAddr(queuedTx.Args.From) defer m.addrLock.UnlockAddr(queuedTx.Args.From) @@ -207,17 +206,14 @@ func (m *Manager) completeTransaction(selectedAccount *common.SelectedExtKey, qu return emptyHash, err } args := queuedTx.Args - var gasPrice *big.Int + gasPrice := (*big.Int)(args.GasPrice) if args.GasPrice == nil { - ctx, cancel = context.WithTimeout(context.Background(), cancelTimeout) + ctx, cancel = context.WithTimeout(context.Background(), defaultTimeout) defer cancel() gasPrice, err = m.ethTxClient.SuggestGasPrice(ctx) if err != nil { return emptyHash, err } - - } else { - gasPrice = (*big.Int)(args.GasPrice) } chainID := big.NewInt(int64(config.NetworkID)) @@ -227,7 +223,7 @@ func (m *Manager) completeTransaction(selectedAccount *common.SelectedExtKey, qu if args.To != nil { toAddr = *args.To } - ctx, cancel = context.WithTimeout(context.Background(), cancelTimeout) + ctx, cancel = context.WithTimeout(context.Background(), defaultTimeout) defer cancel() gas, err := m.ethTxClient.EstimateGas(ctx, ethereum.CallMsg{ From: args.From, @@ -257,7 +253,7 @@ func (m *Manager) completeTransaction(selectedAccount *common.SelectedExtKey, qu if err != nil { return emptyHash, err } - ctx, cancel = context.WithTimeout(context.Background(), cancelTimeout) + ctx, cancel = context.WithTimeout(context.Background(), defaultTimeout) defer cancel() if err := m.ethTxClient.SendTransaction(ctx, signedTx); err != nil { return emptyHash, err diff --git a/geth/txqueue/txqueue_manager_test.go b/geth/txqueue/txqueue_manager_test.go index f8a39eb5e90..c4294a76fa0 100644 --- a/geth/txqueue/txqueue_manager_test.go +++ b/geth/txqueue/txqueue_manager_test.go @@ -2,10 +2,10 @@ package txqueue import ( "context" - "errors" "math/big" "sync" "testing" + "time" "github.com/ethereum/go-ethereum/accounts/keystore" gethcommon "github.com/ethereum/go-ethereum/common" @@ -22,8 +22,6 @@ import ( . "github.com/status-im/status-go/testing" ) -var errTxAssumedSent = errors.New("assume tx is done") - func TestTxQueueTestSuite(t *testing.T) { suite.Run(t, new(TxQueueTestSuite)) } @@ -37,7 +35,7 @@ type TxQueueTestSuite struct { server *gethrpc.Server client *gethrpc.Client txServiceMockCtrl *gomock.Controller - txServiceMock *fake.MockFakePublicTxApi + txServiceMock *fake.MockFakePublicTransactionPoolAPI } func (s *TxQueueTestSuite) SetupTest() { @@ -62,25 +60,33 @@ func (s *TxQueueTestSuite) TearDownTest() { s.client.Close() } -func (s *TxQueueTestSuite) TestCompleteTransaction() { +func (s *TxQueueTestSuite) setupTransactionPoolAPI(account *common.SelectedExtKey, nonce hexutil.Uint64, gas hexutil.Big, txErr error) { + s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), account.Address, gethrpc.PendingBlockNumber).Return(&nonce, nil) + s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(big.NewInt(10), nil) + s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(&gas, nil) + s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), gomock.Any()).Return(gethcommon.Hash{}, txErr) +} + +func (s *TxQueueTestSuite) setupStatusBackend(account *common.SelectedExtKey, password string, passwordErr error) { nodeConfig, nodeErr := params.NewNodeConfig("/tmp", params.RopstenNetworkID, true) + s.nodeManagerMock.EXPECT().NodeConfig().Return(nodeConfig, nodeErr) + s.accountManagerMock.EXPECT().SelectedAccount().Return(account, nil) + s.accountManagerMock.EXPECT().VerifyAccountPassword(nodeConfig.KeyStoreDir, account.Address.String(), password).Return( + nil, passwordErr) +} + +func (s *TxQueueTestSuite) TestCompleteTransaction() { password := TestConfig.Account1.Password key, _ := crypto.GenerateKey() account := &common.SelectedExtKey{ Address: common.FromAddress(TestConfig.Account1.Address), AccountKey: &keystore.Key{PrivateKey: key}, } - s.accountManagerMock.EXPECT().SelectedAccount().Return(account, nil) - s.accountManagerMock.EXPECT().VerifyAccountPassword(nodeConfig.KeyStoreDir, account.Address.String(), password).Return( - nil, nil) - s.nodeManagerMock.EXPECT().NodeConfig().Return(nodeConfig, nodeErr) + s.setupStatusBackend(account, password, nil) nonce := hexutil.Uint64(10) - s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), account.Address, gethrpc.PendingBlockNumber).Return(&nonce, nil) - s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(big.NewInt(10), nil) gas := hexutil.Big(*big.NewInt(defaultGas + 1)) - s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(&gas, nil) - s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), gomock.Any()).Return(gethcommon.Hash{}, nil) + s.setupTransactionPoolAPI(account, nonce, gas, nil) txQueueManager := NewManager(s.nodeManagerMock, s.accountManagerMock) @@ -99,15 +105,18 @@ func (s *TxQueueTestSuite) TestCompleteTransaction() { txQueueManager.SetTransactionReturnHandler(func(queuedTx *common.QueuedTx, err error) { s.Equal(tx.ID, queuedTx.ID) - s.Equal(errTxAssumedSent, err) + s.NoError(err) }) err := txQueueManager.QueueTransaction(tx) s.NoError(err) + w := make(chan struct{}) go func() { - _, errCompleteTransaction := txQueueManager.CompleteTransaction(tx.ID, password) - s.NoError(errCompleteTransaction) + hash, err := txQueueManager.CompleteTransaction(tx.ID, password) + s.NoError(err) + s.Equal(tx.Hash, hash) + close(w) }() err = txQueueManager.WaitForTransaction(tx) @@ -116,27 +125,21 @@ func (s *TxQueueTestSuite) TestCompleteTransaction() { s.NoError(tx.Err) // Transaction should be already removed from the queue. s.False(txQueueManager.TransactionQueue().Has(tx.ID)) + s.NoError(WaitClosed(w, time.Second)) } func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() { - nodeConfig, nodeErr := params.NewNodeConfig("/tmp", params.RopstenNetworkID, true) password := TestConfig.Account1.Password key, _ := crypto.GenerateKey() account := &common.SelectedExtKey{ Address: common.FromAddress(TestConfig.Account1.Address), AccountKey: &keystore.Key{PrivateKey: key}, } - s.accountManagerMock.EXPECT().SelectedAccount().Return(account, nil) - s.accountManagerMock.EXPECT().VerifyAccountPassword(nodeConfig.KeyStoreDir, account.Address.String(), password).Return( - nil, nil) - s.nodeManagerMock.EXPECT().NodeConfig().Return(nodeConfig, nodeErr) + s.setupStatusBackend(account, password, nil) nonce := hexutil.Uint64(10) - s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), account.Address, gethrpc.PendingBlockNumber).Return(&nonce, nil) - s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(big.NewInt(10), nil) gas := hexutil.Big(*big.NewInt(defaultGas + 1)) - s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(&gas, nil) - s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), gomock.Any()).Return(gethcommon.Hash{}, nil) + s.setupTransactionPoolAPI(account, nonce, gas, nil) txQueueManager := NewManager(s.nodeManagerMock, s.accountManagerMock) @@ -161,16 +164,26 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() { err := txQueueManager.QueueTransaction(tx) s.NoError(err) - var wg sync.WaitGroup - var mu sync.Mutex - completeTxErrors := map[error]int{} - for i := 0; i < 3; i++ { + var ( + wg sync.WaitGroup + mu sync.Mutex + completedTx int + inprogressTx int + txCount = 3 + ) + for i := 0; i < txCount; i++ { wg.Add(1) go func() { defer wg.Done() - _, errCompleteTransaction := txQueueManager.CompleteTransaction(tx.ID, password) + _, err := txQueueManager.CompleteTransaction(tx.ID, password) mu.Lock() - completeTxErrors[errCompleteTransaction]++ + if err == nil { + completedTx++ + } else if err == ErrQueuedTxInProgress { + inprogressTx++ + } else { + s.Fail("tx failed with unexpected error: ", err.Error()) + } mu.Unlock() }() } @@ -184,7 +197,8 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() { // Wait for all CompleteTransaction calls. wg.Wait() - s.Equal(completeTxErrors[nil], 1) + s.Equal(1, completedTx, "only 1 tx expected to be completed") + s.Equal(txCount-1, inprogressTx, "txs expected to be reported as inprogress") } func (s *TxQueueTestSuite) TestAccountMismatch() { @@ -227,24 +241,13 @@ func (s *TxQueueTestSuite) TestAccountMismatch() { } func (s *TxQueueTestSuite) TestInvalidPassword() { - nodeConfig, nodeErr := params.NewNodeConfig("/tmp", params.RopstenNetworkID, true) password := "invalid-password" key, _ := crypto.GenerateKey() account := &common.SelectedExtKey{ Address: common.FromAddress(TestConfig.Account1.Address), AccountKey: &keystore.Key{PrivateKey: key}, } - s.accountManagerMock.EXPECT().SelectedAccount().Return(account, nil) - s.accountManagerMock.EXPECT().VerifyAccountPassword(nodeConfig.KeyStoreDir, account.Address.String(), password).Return( - nil, nil) - s.nodeManagerMock.EXPECT().NodeConfig().Return(nodeConfig, nodeErr) - - nonce := hexutil.Uint64(10) - s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), account.Address, gethrpc.PendingBlockNumber).Return(&nonce, nil) - s.txServiceMock.EXPECT().GasPrice(gomock.Any()).Return(big.NewInt(10), nil) - gas := hexutil.Big(*big.NewInt(defaultGas + 1)) - s.txServiceMock.EXPECT().EstimateGas(gomock.Any(), gomock.Any()).Return(&gas, nil) - s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), gomock.Any()).Return(gethcommon.Hash{}, keystore.ErrDecrypt) + s.setupStatusBackend(account, password, keystore.ErrDecrypt) txQueueManager := NewManager(s.nodeManagerMock, s.accountManagerMock) @@ -304,9 +307,11 @@ func (s *TxQueueTestSuite) TestDiscardTransaction() { err := txQueueManager.QueueTransaction(tx) s.NoError(err) + w := make(chan struct{}) go func() { - discardErr := txQueueManager.DiscardTransaction(tx.ID) - s.NoError(discardErr) + err := txQueueManager.DiscardTransaction(tx.ID) + s.NoError(err) + close(w) }() err = txQueueManager.WaitForTransaction(tx) @@ -315,4 +320,5 @@ func (s *TxQueueTestSuite) TestDiscardTransaction() { s.Equal(ErrQueuedTxDiscarded, tx.Err) // Transaction should be already removed from the queue. s.False(txQueueManager.TransactionQueue().Has(tx.ID)) + s.NoError(WaitClosed(w, time.Second)) } diff --git a/testing/testing.go b/testing/testing.go index 27d51dbd7aa..b85fa93f877 100644 --- a/testing/testing.go +++ b/testing/testing.go @@ -21,6 +21,9 @@ var ( // ErrNoRemoteURL is returned when network id has no associated url. ErrNoRemoteURL = errors.New("network id requires a remote URL") + // ErrTimeout is returned when test times out + ErrTimeout = errors.New("timeout") + // TestConfig defines the default config usable at package-level. TestConfig *common.TestConfig @@ -204,3 +207,17 @@ func GetAccount2PKFile() string { return "test-account2.pk" } } + +// WaitClosed used to wait on a channel in tests +func WaitClosed(c chan struct{}, d time.Duration) error { + timer := time.NewTimer(d) + defer timer.Stop() + for { + select { + case <-c: + return nil + case <-timer.C: + return ErrTimeout + } + } +}