Sync blockchain before running e2e tests on public testnet #568 (#612)

This commit is contained in:
Caner Çıdam 2018-02-07 13:48:03 +03:00 committed by Igor Mandrigin
parent c00e5c9c58
commit ca719af71c
6 changed files with 114 additions and 2 deletions

View File

@ -24,5 +24,5 @@
"vet"
],
"Cyclo": 16,
"Deadline": "100s"
"Deadline": "200s"
}

View File

@ -26,7 +26,9 @@ jobs:
# using fork == false may be preferred as it would allow PRs from the origin
# to still run, but currently does not work due to a bug
if: type != pull_request
script: make test-e2e networkid=4
script:
- ./build/bin/statusd -les -networkid 4 -sync-and-exit
- make test-e2e networkid=4
cache:
directories:
- ".ethereumtest/Mainnet"

View File

@ -66,6 +66,8 @@ var (
// Push Notification
enablePN = flag.Bool("shh.notify", false, "Node is capable of sending Push Notifications")
firebaseAuth = flag.String("shh.firebaseauth", "", "FCM Authorization Key used for sending Push Notifications")
syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished")
)
func main() {
@ -110,6 +112,12 @@ func main() {
go startCollectingStats(interruptCh, backend.NodeManager())
}
// Sync blockchain and stop.
if *syncAndExit >= 0 {
exitCode := syncAndStopNode(backend.NodeManager(), *syncAndExit)
os.Exit(exitCode)
}
// wait till node has been stopped
node, err := backend.NodeManager().Node()
if err != nil {
@ -162,6 +170,34 @@ func startCollectingStats(interruptCh <-chan struct{}, nodeManager common.NodeMa
}
}
func syncAndStopNode(nodeManager common.NodeManager, timeout int) (exitCode int) {
log.Println("Node will synchronize and exit")
if timeout < 0 {
log.Println("Sync and stop error: negative timeout value")
return 1
}
var err error
if timeout == 0 {
err = nodeManager.EnsureSync(context.Background())
} else {
ctx, cancel := context.WithTimeout(context.Background(), (time.Duration)(timeout)*time.Minute)
err = nodeManager.EnsureSync(ctx)
defer cancel()
}
if err != nil {
log.Printf("Sync error: %v", err)
exitCode = 1
}
var done <-chan struct{}
done, err = nodeManager.StopNode()
if err != nil {
log.Printf("Stop node err: %v", err)
return 1
}
<-done
return
}
// makeNodeConfig parses incoming CLI options and returns node configuration object
func makeNodeConfig() (*params.NodeConfig, error) {
devMode := !*prodMode

View File

@ -53,6 +53,9 @@ type NodeManager interface {
// Stopped node cannot be resumed, one starts a new node instead.
StopNode() (<-chan struct{}, error)
// EnsureSync waits until blockchain is synchronized.
EnsureSync(ctx context.Context) error
// RestartNode restart running Status node, fails if node is not running
RestartNode() (<-chan struct{}, error)

View File

@ -5,6 +5,7 @@
package common
import (
context "context"
accounts "github.com/ethereum/go-ethereum/accounts"
keystore "github.com/ethereum/go-ethereum/accounts/keystore"
common "github.com/ethereum/go-ethereum/common"
@ -67,6 +68,18 @@ func (mr *MockNodeManagerMockRecorder) StopNode() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopNode", reflect.TypeOf((*MockNodeManager)(nil).StopNode))
}
// EnsureSync mocks base method
func (m *MockNodeManager) EnsureSync(ctx context.Context) error {
ret := m.ctrl.Call(m, "EnsureSync", ctx)
ret0, _ := ret[0].(error)
return ret0
}
// EnsureSync indicates an expected call of EnsureSync
func (mr *MockNodeManagerMockRecorder) EnsureSync(ctx interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnsureSync", reflect.TypeOf((*MockNodeManager)(nil).EnsureSync), ctx)
}
// RestartNode mocks base method
func (m *MockNodeManager) RestartNode() (<-chan struct{}, error) {
ret := m.ctrl.Call(m, "RestartNode")

View File

@ -1,11 +1,13 @@
package node
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
@ -518,3 +520,59 @@ func (m *NodeManager) isNodeAvailable() error {
return nil
}
// tickerResolution is the delta to check blockchain sync progress.
const tickerResolution = time.Second
// EnsureSync waits until blockchain synchronization
// is complete and returns.
func (m *NodeManager) EnsureSync(ctx context.Context) error {
// Don't wait for any blockchain sync for the
// local private chain as blocks are never mined.
if m.config.NetworkID == params.StatusChainNetworkID {
return nil
}
if m.lesService == nil {
return errors.New("LightEthereumService is nil")
}
return m.ensureSync(ctx)
}
func (m *NodeManager) ensureSync(ctx context.Context) error {
downloader := m.lesService.Downloader()
if downloader == nil {
return errors.New("LightEthereumService downloader is nil")
}
progress := downloader.Progress()
if progress.CurrentBlock >= progress.HighestBlock {
log.Debug("Synchronization completed")
return nil
}
ticker := time.NewTicker(tickerResolution)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return errors.New("timeout during node synchronization")
case <-ticker.C:
if m.PeerCount() == 0 {
log.Debug("No established connections with any peers, continue waiting for a sync")
continue
}
if downloader.Synchronising() {
log.Debug("Synchronization is in progress")
continue
}
progress = downloader.Progress()
if progress.CurrentBlock >= progress.HighestBlock {
log.Debug("Synchronization completed")
return nil
}
log.Debug(
fmt.Sprintf("Synchronization is not finished yet: current block %d < highest block %d",
progress.CurrentBlock, progress.HighestBlock),
)
}
}
}