Improve geth/api tests (#328)

The goal of this PR is to make geth/api tests to finally pass from the beginning to the end. I tried to achieve it here by:

Removing calls to common.PanicAfter so that we know which tests fail the most,
Better sync of some tests using channels,
Small test improvements.
This commit is contained in:
Adam Babik 2017-09-15 12:35:31 +02:00 committed by Ivan Tomilov
parent 1c9c0f08f4
commit 8153d935d2
6 changed files with 81 additions and 55 deletions

View File

@ -47,7 +47,7 @@ statusgo-ios-simulator-mainnet: xgo
@echo "iOS framework cross compilation done (mainnet)." @echo "iOS framework cross compilation done (mainnet)."
ci: mock ci: mock
build/env.sh go test -timeout 40m -v ./geth/api build/env.sh go test -timeout 10m -v ./geth/api/...
build/env.sh go test -timeout 40m -v ./geth/common build/env.sh go test -timeout 40m -v ./geth/common
build/env.sh go test -timeout 40m -v ./geth/jail build/env.sh go test -timeout 40m -v ./geth/jail
build/env.sh go test -timeout 40m -v ./geth/node build/env.sh go test -timeout 40m -v ./geth/node

View File

@ -51,7 +51,6 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
"value": "0.000001" "value": "0.000001"
}` }`
txCompletedSuccessfully := make(chan struct{})
txHashes := make(chan gethcommon.Hash, 1) txHashes := make(chan gethcommon.Hash, 1)
// replace transaction notification handler // replace transaction notification handler
@ -77,7 +76,6 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
log.Info("Transaction complete", "URL", "https://ropsten.etherscan.io/tx/%s"+txHash.Hex()) log.Info("Transaction complete", "URL", "https://ropsten.etherscan.io/tx/%s"+txHash.Hex())
txCompletedSuccessfully <- struct{}{} // so that timeout is aborted
txHashes <- txHash txHashes <- txHash
} }
}) })
@ -172,18 +170,24 @@ func (s *BackendTestSuite) TestJailSendQueuedTransaction() {
jailInstance := s.backend.JailManager() jailInstance := s.backend.JailManager()
for _, test := range tests { for _, test := range tests {
jailInstance.BaseJS(string(static.MustAsset(txSendFolder + test.file))) jailInstance.BaseJS(string(static.MustAsset(txSendFolder + test.file)))
common.PanicAfter(1*time.Minute, txCompletedSuccessfully, test.name)
jailInstance.Parse(testChatID, ``) jailInstance.Parse(testChatID, ``)
// used by notification handler
requireMessageId = test.requireMessageId requireMessageId = test.requireMessageId
for _, command := range test.commands { for _, command := range test.commands {
s.T().Logf("%s: %s", test.name, command.command) s.T().Logf("%s: %s", test.name, command.command)
response := jailInstance.Call(testChatID, command.command, command.params) response := jailInstance.Call(testChatID, command.command, command.params)
var txHash gethcommon.Hash var txHash gethcommon.Hash
if command.command == `["commands", "send"]` { if command.command == `["commands", "send"]` {
txHash = <-txHashes select {
case txHash = <-txHashes:
case <-time.After(time.Minute):
s.FailNow("test timed out: %s", test.name)
} }
}
expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1) expectedResponse := strings.Replace(command.expectedResponse, "TX_HASH", txHash.Hex(), 1)
require.Equal(expectedResponse, response) require.Equal(expectedResponse, response)
} }
@ -206,9 +210,7 @@ func (s *BackendTestSuite) TestContractDeployment() {
cell, err := jailInstance.Cell(testChatID) cell, err := jailInstance.Cell(testChatID)
require.NoError(err) require.NoError(err)
// make sure you panic if transaction complete doesn't return completeQueuedTransaction := make(chan struct{})
completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash gethcommon.Hash var txHash gethcommon.Hash
@ -256,7 +258,11 @@ func (s *BackendTestSuite) TestContractDeployment() {
`) `)
require.NoError(err) require.NoError(err)
<-completeQueuedTransaction select {
case <-completeQueuedTransaction:
case <-time.After(time.Minute):
s.FailNow("test timed out")
}
responseValue, err := cell.Get("responseValue") responseValue, err := cell.Get("responseValue")
require.NoError(err) require.NoError(err)
@ -749,8 +755,17 @@ func (s *BackendTestSuite) TestJailVMPersistence() {
}(tc) }(tc)
} }
common.PanicAfter(60*time.Second, nil, "test timed out") finishTestCases := make(chan struct{})
go func() {
wg.Wait() wg.Wait()
close(finishTestCases)
}()
select {
case <-finishTestCases:
case <-time.After(time.Minute):
s.FailNow("some tests failed to finish in time")
}
// Validate total. // Validate total.
cell, err := jailInstance.Cell(testChatID) cell, err := jailInstance.Cell(testChatID)

View File

@ -157,11 +157,10 @@ func (s *BackendTestSuite) TestNodeStartStop() {
require.True(s.backend.IsNodeRunning()) require.True(s.backend.IsNodeRunning())
} }
func (s *BackendTestSuite) TestStartNodeWithUpstreamEnabled(t *testing.T) { func (s *BackendTestSuite) TestStartNodeWithUpstreamEnabled() {
require := s.Require() require := s.Require()
backend := api.NewStatusBackend() backend := api.NewStatusBackend()
require.NotNil(t, backend)
nodeConfig, err := MakeTestNodeConfig(params.RopstenNetworkID) nodeConfig, err := MakeTestNodeConfig(params.RopstenNetworkID)
require.NoError(err) require.NoError(err)

View File

@ -27,13 +27,10 @@ func (s *BackendTestSuite) TestSendContractTx() {
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to sync time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to sync
// create an account
sampleAddress, _, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password) sampleAddress, _, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err) require.NoError(err)
// make sure you panic if transaction complete doesn't return completeQueuedTransaction := make(chan struct{})
completeQueuedTransaction := make(chan struct{}, 10)
common.PanicAfter(2*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash gethcommon.Hash var txHash gethcommon.Hash
@ -81,7 +78,7 @@ func (s *BackendTestSuite) TestSendContractTx() {
) )
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"])) s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
log.Info("contract transaction complete", "URL", "https://rinkeby.etherscan.io/tx/"+txHash.Hex()) log.Info("contract transaction complete", "URL", "https://ropsten.etherscan.io/tx/"+txHash.Hex())
close(completeQueuedTransaction) close(completeQueuedTransaction)
return return
} }
@ -100,7 +97,12 @@ func (s *BackendTestSuite) TestSendContractTx() {
}) })
s.NoError(err, "cannot send transaction") s.NoError(err, "cannot send transaction")
<-completeQueuedTransaction select {
case <-completeQueuedTransaction:
case <-time.After(2 * time.Minute):
s.FailNow("completing transaction timed out")
}
s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid") s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid")
s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed") s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed")
s.Zero(s.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point") s.Zero(s.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point")
@ -122,9 +124,7 @@ func (s *BackendTestSuite) TestSendEtherTx() {
sampleAddress, _, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password) sampleAddress, _, _, err := s.backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
require.NoError(err) require.NoError(err)
// make sure you panic if transaction complete doesn't return completeQueuedTransaction := make(chan struct{})
completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
var txHash = gethcommon.Hash{} var txHash = gethcommon.Hash{}
@ -170,7 +170,7 @@ func (s *BackendTestSuite) TestSendEtherTx() {
) )
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"])) s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
log.Info("contract transaction complete", "URL", "https://rinkeby.etherscan.io/tx/"+txHash.Hex()) log.Info("contract transaction complete", "URL", "https://ropsten.etherscan.io/tx/"+txHash.Hex())
close(completeQueuedTransaction) close(completeQueuedTransaction)
return return
} }
@ -184,7 +184,12 @@ func (s *BackendTestSuite) TestSendEtherTx() {
}) })
s.NoError(err, "cannot send transaction") s.NoError(err, "cannot send transaction")
<-completeQueuedTransaction select {
case <-completeQueuedTransaction:
case <-time.After(2 * time.Minute):
s.FailNow("completing transaction timed out")
}
s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid") s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid")
s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed") s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed")
s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point") s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point")
@ -205,9 +210,7 @@ func (s *BackendTestSuite) TestDoubleCompleteQueuedTransactions() {
// log into account from which transactions will be sent // log into account from which transactions will be sent
require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)) require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
// make sure you panic if transaction complete doesn't return completeQueuedTransaction := make(chan struct{})
completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
txFailedEventCalled := false txFailedEventCalled := false
@ -260,7 +263,12 @@ func (s *BackendTestSuite) TestDoubleCompleteQueuedTransactions() {
}) })
s.NoError(err, "cannot send transaction") s.NoError(err, "cannot send transaction")
<-completeQueuedTransaction select {
case <-completeQueuedTransaction:
case <-time.After(time.Minute):
s.FailNow("test timed out")
}
s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid") s.Equal(txHashCheck.Hex(), txHash.Hex(), "transaction hash returned from SendTransaction is invalid")
s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed") s.False(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction was never queued or completed")
s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point") s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point")
@ -285,9 +293,7 @@ func (s *BackendTestSuite) TestDiscardQueuedTransaction() {
// log into account from which transactions will be sent // log into account from which transactions will be sent
require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)) require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
// make sure you panic if transaction complete doesn't return completeQueuedTransaction := make(chan struct{})
completeQueuedTransaction := make(chan struct{}, 1)
common.PanicAfter(1*time.Minute, completeQueuedTransaction, s.T().Name())
// replace transaction notification handler // replace transaction notification handler
txFailedEventCalled := false txFailedEventCalled := false
@ -341,7 +347,12 @@ func (s *BackendTestSuite) TestDiscardQueuedTransaction() {
}) })
s.EqualError(err, node.ErrQueuedTxDiscarded.Error(), "transaction is expected to be discarded") s.EqualError(err, node.ErrQueuedTxDiscarded.Error(), "transaction is expected to be discarded")
<-completeQueuedTransaction select {
case <-completeQueuedTransaction:
case <-time.After(time.Minute):
s.FailNow("test timed out")
}
s.True(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction returned hash, while it shouldn't") s.True(reflect.DeepEqual(txHashCheck, gethcommon.Hash{}), "transaction returned hash, while it shouldn't")
s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point") s.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point")
s.True(txFailedEventCalled, "expected tx failure signal is not received") s.True(txFailedEventCalled, "expected tx failure signal is not received")
@ -363,10 +374,9 @@ func (s *BackendTestSuite) TestCompleteMultipleQueuedTransactions() {
err := s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password) err := s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
require.NoError(err) require.NoError(err)
// make sure you panic if transaction complete doesn't return
testTxCount := 3 testTxCount := 3
txIDs := make(chan common.QueuedTxID, testTxCount) txIDs := make(chan common.QueuedTxID, testTxCount)
allTestTxCompleted := make(chan struct{}, 1) allTestTxCompleted := make(chan struct{})
// replace transaction notification handler // replace transaction notification handler
node.SetDefaultNodeNotificationHandler(func(jsonEvent string) { node.SetDefaultNodeNotificationHandler(func(jsonEvent string) {
@ -410,7 +420,7 @@ func (s *BackendTestSuite) TestCompleteMultipleQueuedTransactions() {
txResult.Hash == (gethcommon.Hash{}) && txID != "invalid-tx-id", txResult.Hash == (gethcommon.Hash{}) && txID != "invalid-tx-id",
"invalid hash (expected non empty hash): %s", txID, "invalid hash (expected non empty hash): %s", txID,
) )
log.Info("transaction complete", "URL", "https://rinkeby.etherscan.io/tx/"+txResult.Hash.Hex()) log.Info("transaction complete", "URL", "https://ropsten.etherscan.io/tx/"+txResult.Hash.Hex())
} }
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
@ -429,7 +439,7 @@ func (s *BackendTestSuite) TestCompleteMultipleQueuedTransactions() {
} }
completeTxs(ids) completeTxs(ids)
allTestTxCompleted <- struct{}{} close(allTestTxCompleted)
}() }()
// send multiple transactions // send multiple transactions
@ -439,9 +449,8 @@ func (s *BackendTestSuite) TestCompleteMultipleQueuedTransactions() {
select { select {
case <-allTestTxCompleted: case <-allTestTxCompleted:
// pass
case <-time.After(30 * time.Second): case <-time.After(30 * time.Second):
require.Fail("test timed out") s.FailNow("test timed out")
} }
require.Zero(s.TxQueueManager().TransactionQueue().Count(), "queue should be empty") require.Zero(s.TxQueueManager().TransactionQueue().Count(), "queue should be empty")
@ -465,10 +474,9 @@ func (s *BackendTestSuite) TestDiscardMultipleQueuedTransactions() {
// log into account from which transactions will be sent // log into account from which transactions will be sent
require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)) require.NoError(s.backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
// make sure you panic if transaction complete doesn't return
testTxCount := 3 testTxCount := 3
txIDs := make(chan common.QueuedTxID, testTxCount) txIDs := make(chan common.QueuedTxID, testTxCount)
allTestTxDiscarded := make(chan struct{}, 1) allTestTxDiscarded := make(chan struct{})
// replace transaction notification handler // replace transaction notification handler
txFailedEventCallCount := 0 txFailedEventCallCount := 0
@ -499,7 +507,7 @@ func (s *BackendTestSuite) TestDiscardMultipleQueuedTransactions() {
txFailedEventCallCount++ txFailedEventCallCount++
if txFailedEventCallCount == testTxCount { if txFailedEventCallCount == testTxCount {
allTestTxDiscarded <- struct{}{} close(allTestTxDiscarded)
} }
} }
}) })
@ -560,9 +568,8 @@ func (s *BackendTestSuite) TestDiscardMultipleQueuedTransactions() {
select { select {
case <-allTestTxDiscarded: case <-allTestTxDiscarded:
// pass
case <-time.After(1 * time.Minute): case <-time.After(1 * time.Minute):
require.Fail("test timed out") require.FailNow("test timed out")
} }
require.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point") require.Zero(s.backend.TxQueueManager().TransactionQueue().Count(), "tx queue must be empty at this point")

View File

@ -99,6 +99,9 @@ func (ep *ExecutionPolicy) executeWithClient(client *rpc.Client, req common.RPCC
return nil, common.StopRPCCallError{Err: err} return nil, common.StopRPCCallError{Err: err}
} }
if client == nil {
resp = newErrorResponse(call.Otto, -32603, "RPC client is not available. Node is stopped?", &req.ID).Object()
} else {
err = client.Call(&result, req.Method, req.Params...) err = client.Call(&result, req.Method, req.Params...)
if err != nil { if err != nil {
if err2, ok := err.(gethrpc.Error); ok { if err2, ok := err.(gethrpc.Error); ok {
@ -110,6 +113,7 @@ func (ep *ExecutionPolicy) executeWithClient(client *rpc.Client, req common.RPCC
resp = newErrorResponse(call.Otto, -32603, err.Error(), &req.ID).Object() resp = newErrorResponse(call.Otto, -32603, err.Error(), &req.ID).Object()
} }
} }
}
if result == nil { if result == nil {
// Special case null because it is decoded as an empty // Special case null because it is decoded as an empty

View File

@ -176,9 +176,10 @@ func (jail *Jail) Send(call otto.FunctionCall) (response otto.Value) {
// Execute the requests. // Execute the requests.
for _, req := range reqs { for _, req := range reqs {
log.Info("execute request", "method", req.Method)
res, err := jail.policy.Execute(req, call) res, err := jail.policy.Execute(req, call)
if err != nil { if err != nil {
log.Info("request errored", "error", err.Error())
switch err.(type) { switch err.(type) {
case common.StopRPCCallError: case common.StopRPCCallError:
return newErrorResponse(call.Otto, -32603, err.Error(), nil) return newErrorResponse(call.Otto, -32603, err.Error(), nil)