Ensuring node synchronisation to avoid "no suitable peers available" errors (#410)

During CI tests non-deterministic failures with "no suitable peers available" happened. Reason is a not finished synchronisation after starting of node.

Added and integrated an EnsureSychronization() almost solved it, but overlapped with new added EnsureNodeSync() in merged develop. Failure stayed, so exchange new algorithm in EsureNodeSync() with former one.
This commit is contained in:
Frank Mueller 2017-10-21 19:04:07 +02:00 committed by Ivan Tomilov
parent e911666b5d
commit 1c8d32c451
11 changed files with 79 additions and 91 deletions

1
.gitignore vendored
View File

@ -17,6 +17,7 @@
*/**/*dapps*
vendor/github.com/ethereum/go-ethereum/vendor
/node_modules/
tags
#*
.#*

View File

@ -11,7 +11,7 @@ install:
- go get golang.org/x/tools/cmd/cover
script:
- travis_wait make ci
- make ci
cache:
directories:

View File

@ -149,9 +149,9 @@ test-e2e: ##@tests Run e2e tests
build/env.sh go test -timeout 5m ./e2e/node/...
build/env.sh go test -timeout 15m ./e2e/jail/...
build/env.sh go test -timeout 20m ./e2e/rpc/...
build/env.sh go test -timeout 10m ./e2e/whisper/...
build/env.sh go test -timeout 20m ./e2e/whisper/...
build/env.sh go test -timeout 10m ./e2e/transactions/...
build/env.sh go test -timeout 10m ./cmd/statusd
build/env.sh go test -timeout 40m ./cmd/statusd
ci: mock-install mock test-coverage test-e2e ##@tests Run all tests in CI

View File

@ -2,6 +2,7 @@ package main
import "C"
import (
"context"
"encoding/json"
"io/ioutil"
"math/big"
@ -216,8 +217,10 @@ func testResetChainData(t *testing.T) bool {
return false
}
// FIXME(tiabc): EnsureNodeSync the same way as in e2e tests.
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // allow to re-sync blockchain
if err := EnsureNodeSync(statusAPI.NodeManager()); err != nil {
t.Errorf("cannot ensure node synchronization: %v", err)
return false
}
testCompleteTransaction(t)
@ -728,7 +731,10 @@ func testCompleteTransaction(t *testing.T) bool {
txQueue.Reset()
time.Sleep(5 * time.Second) // allow to sync
if err := EnsureNodeSync(statusAPI.NodeManager()); err != nil {
t.Errorf("cannot ensure node synchronization: %v", err)
return false
}
// log into account from which transactions will be sent
if err := statusAPI.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password); err != nil {
@ -1256,7 +1262,8 @@ func testJailParseInvalid(t *testing.T) bool {
response := C.GoString(Parse(C.CString("CHAT_ID_INIT_TEST"), C.CString(extraInvalidCode)))
// Assert.
expectedResponse := `{"error":"(anonymous): Line 16331:50 Unexpected end of input (and 1 more errors)"}`
// expectedResponse := `{"error":"(anonymous): Line 16331:50 Unexpected end of input (and 1 more errors)"}`
expectedResponse := `{"error":"(anonymous): Line 16354:50 Unexpected end of input (and 1 more errors)"}`
if expectedResponse != response {
t.Errorf("unexpected response, expected: %v, got: %v", expectedResponse, response)
return false
@ -1305,7 +1312,7 @@ func testJailFunctionCall(t *testing.T) bool {
// call with wrong chat id
rawResponse := Call(C.CString("CHAT_IDNON_EXISTENT"), C.CString(""), C.CString(""))
parsedResponse := C.GoString(rawResponse)
expectedError := `{"error":"Cell[CHAT_IDNON_EXISTENT] doesn't exist."}`
expectedError := `{"error":"cell[CHAT_IDNON_EXISTENT] doesn't exist"}`
if parsedResponse != expectedError {
t.Errorf("expected error is not returned: expected %s, got %s", expectedError, parsedResponse)
return false
@ -1360,9 +1367,11 @@ func startTestNode(t *testing.T) <-chan struct{} {
if envelope.Type == signal.EventNodeReady {
// sync
if syncRequired {
t.Logf("Sync is required, it will take %d seconds", TestConfig.Node.SyncSeconds)
// FIXME(tiabc): EnsureNodeSync the same way as in e2e tests.
time.Sleep(TestConfig.Node.SyncSeconds * time.Second) // LES syncs headers, so that we are up do date when it is done
t.Logf("Sync is required")
if err := EnsureNodeSync(statusAPI.NodeManager()); err != nil {
t.Errorf("cannot ensure node synchronization: %v", err)
return
}
} else {
time.Sleep(5 * time.Second)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/status-im/status-go/geth/log"
"github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params"
. "github.com/status-im/status-go/testing"
"github.com/stretchr/testify/suite"
)
@ -241,8 +242,7 @@ func (s *APIBackendTestSuite) TestResetChainData() {
s.StartTestBackend(params.RinkebyNetworkID)
defer s.StopTestBackend()
// allow to sync for some time
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
s.True(s.Backend.IsNodeRunning())
nodeReady, err := s.Backend.ResetChainData()

View File

@ -39,6 +39,8 @@ func (s *JailRPCTestSuite) TestJailRPCSend() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
// load Status JS and add test command to it
s.jail.BaseJS(baseStatusJSCode)
s.jail.Parse(testChatID, ``)
@ -110,8 +112,7 @@ func (s *JailRPCTestSuite) TestContractDeployment() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
// Allow to sync, otherwise you'll get "Nonce too low."
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
// obtain VM for a given chat (to send custom JS to jailed version of Send())
s.jail.Parse(testChatID, "")
@ -197,7 +198,7 @@ func (s *JailRPCTestSuite) TestJailVMPersistence() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
// log into account from which transactions will be sent
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)

View File

@ -17,6 +17,7 @@ import (
"github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/params"
"github.com/status-im/status-go/geth/signal"
. "github.com/status-im/status-go/testing"
"github.com/stretchr/testify/suite"
)
@ -295,8 +296,7 @@ func (s *ManagerTestSuite) TestResetChainData() {
s.StartTestNode(params.RinkebyNetworkID)
defer s.StopTestNode()
// allow to sync for some time
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.NodeManager), "cannot ensure node synchronization")
// reset chain data
nodeReady, err := s.NodeManager.ResetChainData()

View File

@ -1,14 +1,10 @@
package e2e
import (
"context"
"time"
"github.com/ethereum/go-ethereum/les"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
"github.com/status-im/status-go/geth/api"
"github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/node"
"github.com/status-im/status-go/geth/signal"
"github.com/stretchr/testify/suite"
)
@ -20,35 +16,6 @@ type NodeManagerTestSuite struct {
nodeSyncCompleted bool
}
// EnsureNodeSync ensures that synchronization of the node is done once and that it
// is done properly else, the call will fail.
// FIXME(tiabc): BackendTestSuite contains the same method, let's sort it out?
func (s *NodeManagerTestSuite) EnsureNodeSync(forceResync ...bool) {
if len(forceResync) > 0 && forceResync[0] {
s.nodeSyncCompleted = false
}
if s.nodeSyncCompleted {
return
}
require := s.Require()
ethClient, err := s.NodeManager.LightEthereumService()
require.NoError(err)
require.NotNil(ethClient)
sync := node.NewSyncPoll(ethClient)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
// Validate that synchronization failed because of time.
syncError := sync.Poll(ctx)
require.NoError(syncError)
s.nodeSyncCompleted = true
}
// StartTestNode initiazes a NodeManager instances with configuration retrieved
// from the test config.
func (s *NodeManagerTestSuite) StartTestNode(networkID int, opts ...TestNodeOption) {
@ -162,32 +129,6 @@ func (s *BackendTestSuite) TxQueueManager() common.TxQueueManager {
return s.Backend.TxQueueManager()
}
// EnsureNodeSync ensures that synchronization of the node is done once and that it
// is done properly else, the call will fail.
// FIXME(tiabc): NodeManagerTestSuite contains the same method, let's sort it out?
func (s *BackendTestSuite) EnsureNodeSync(forceResync ...bool) {
if len(forceResync) > 0 && forceResync[0] {
s.nodeSyncCompleted = false
}
if s.nodeSyncCompleted {
return
}
require := s.Require()
ethClient := s.LightEthereumService()
sync := node.NewSyncPoll(ethClient)
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
// Validate that synchronization failed because of time.
syncError := sync.Poll(ctx)
require.NoError(syncError)
s.nodeSyncCompleted = true
}
func importTestAccouns(keyStoreDir string) (err error) {
err = common.ImportTestAccount(keyStoreDir, "test-account1.pk")
if err != nil {

View File

@ -1,6 +1,7 @@
package transactions
import (
"context"
"encoding/json"
"fmt"
"math/big"
@ -36,8 +37,7 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransaction() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
// allow to sync for some time
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
s.NoError(err)
@ -88,9 +88,6 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransactionUpstream() {
)
defer s.StopTestBackend()
// Allow to sync the blockchain.
s.EnsureNodeSync()
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account2.Address, TestConfig.Account2.Password)
s.NoError(err)
@ -144,7 +141,7 @@ func (s *TransactionsTestSuite) TestSendContractTx() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
sampleAddress, _, _, err := s.Backend.AccountManager().CreateAccount(TestConfig.Account1.Password)
s.NoError(err)
@ -231,7 +228,7 @@ func (s *TransactionsTestSuite) TestSendEtherTx() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
backend := s.LightEthereumService().StatusBackend
s.NotNil(backend)
@ -399,8 +396,6 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() {
)
defer s.StopTestBackend()
s.EnsureNodeSync()
err := s.Backend.AccountManager().SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password)
s.NoError(err)
@ -452,7 +447,7 @@ func (s *TransactionsTestSuite) TestDoubleCompleteQueuedTransactions() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
backend := s.LightEthereumService().StatusBackend
s.NotNil(backend)
@ -529,7 +524,7 @@ func (s *TransactionsTestSuite) TestDiscardQueuedTransaction() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
backend := s.LightEthereumService().StatusBackend
s.NotNil(backend)
@ -609,7 +604,7 @@ func (s *TransactionsTestSuite) TestCompleteMultipleQueuedTransactions() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
s.TxQueueManager().TransactionQueue().Reset()
@ -703,7 +698,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
s.EnsureNodeSync()
s.NoError(EnsureNodeSync(s.Backend.NodeManager()), "cannot ensure node synchronization")
backend := s.LightEthereumService().StatusBackend
s.NotNil(backend)

View File

@ -78,7 +78,9 @@ func (s *WhisperJailTestSuite) GetAccountKey(account struct {
return accountKey1, accountKey1Hex, nil
}
func (s *WhisperJailTestSuite) TestJailWhisper() {
// TODO(adamb) Uncomment when issue #336 is fixed.
/*
func (s *WhisperJailTestSuite) DontTestJailWhisper() {
s.StartTestBackend(params.RopstenNetworkID)
defer s.StopTestBackend()
@ -370,6 +372,7 @@ func (s *WhisperJailTestSuite) TestJailWhisper() {
}
}
}
*/
func (s *WhisperJailTestSuite) TestEncryptedAnonymousMessage() {
s.StartTestBackend(params.RopstenNetworkID)

View File

@ -2,10 +2,12 @@ package integration
import (
"bytes"
"errors"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/status-im/status-go/geth/common"
"github.com/status-im/status-go/geth/params"
@ -65,3 +67,39 @@ func LoadFromFile(filename string) string {
return string(buf.Bytes())
}
// EnsureNodeSync waits until node synchronzation is done to continue
// with tests afterwards. Returns an error in case of a timeout.
func EnsureNodeSync(nodeManager common.NodeManager) error {
les, err := nodeManager.LightEthereumService()
if err != nil {
return err
}
if les == nil {
return errors.New("LightEthereumService is nil")
}
timeouter := time.NewTimer(20 * time.Minute)
defer timeouter.Stop()
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-timeouter.C:
return errors.New("timout during node synchronization")
case <-ticker.C:
downloader := les.Downloader()
if downloader != nil {
isSyncing := downloader.Synchronising()
progress := downloader.Progress()
if !isSyncing && progress.HighestBlock > 0 && progress.CurrentBlock >= progress.HighestBlock {
return nil
}
}
}
}
}