mirror of
https://github.com/status-im/status-go.git
synced 2025-02-18 01:37:22 +00:00
The main goal of this change is to remove async operations from node manager. Additionally all of the signals from node manager are moved to status backend. All of the async operation now will have the following behaviour: - If node in the correct state exit immediatly without error - If node not in the correct state exit immediatly with error - In all other cases spawn a goroutine with wanted operation - All the progress regarding that operation will be reported by using signals - Signals should be handled in once place, which is StatusBackend There are 2 potentially breaking changes: - Empty event field will be ommited when Envelope is sent to a client - All errors will be delivered to a client as an Envelope, previously some errors (NodeExists, NoRunningNode) were delivered synchronously Signed-off-by: Dmitry Shulyak <yashulyak@gmail.com>
234 lines
6.1 KiB
Go
234 lines
6.1 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/status-im/status-go/geth/common"
|
|
"github.com/status-im/status-go/geth/log"
|
|
"github.com/status-im/status-go/geth/params"
|
|
|
|
_ "github.com/stretchr/testify/suite" // required to register testify flags
|
|
)
|
|
|
|
var (
|
|
networkSelected = flag.String("network", "statuschain", "-network=NETWORKID or -network=NETWORKNAME to select network used for tests")
|
|
|
|
// 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
|
|
|
|
// RootDir is the main application directory
|
|
RootDir string
|
|
|
|
// TestDataDir is data directory used for tests
|
|
TestDataDir string
|
|
|
|
// TestNetworkNames network ID to name mapping
|
|
TestNetworkNames = map[int]string{
|
|
params.MainNetworkID: "Mainnet",
|
|
params.RopstenNetworkID: "Ropsten",
|
|
params.RinkebyNetworkID: "Rinkeby",
|
|
params.StatusChainNetworkID: "StatusChain",
|
|
}
|
|
)
|
|
|
|
func init() {
|
|
pwd, err := os.Getwd()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
flag.Parse()
|
|
|
|
// setup root directory
|
|
const pathSeparator = string(os.PathSeparator)
|
|
RootDir = filepath.Dir(pwd)
|
|
pathDirs := strings.Split(RootDir, pathSeparator)
|
|
for i := range pathDirs {
|
|
if pathDirs[i] == "status-go" {
|
|
RootDir = filepath.Join(pathDirs[:i+1]...)
|
|
RootDir = filepath.Join(pathSeparator, RootDir)
|
|
break
|
|
}
|
|
}
|
|
|
|
// setup auxiliary directories
|
|
TestDataDir = filepath.Join(RootDir, ".ethereumtest")
|
|
|
|
TestConfig, err = common.LoadTestConfig(GetNetworkID())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// LoadFromFile is useful for loading test data, from testdata/filename into a variable
|
|
// nolint: errcheck
|
|
func LoadFromFile(filename string) string {
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
io.Copy(buf, f) // nolint: gas
|
|
f.Close() // nolint: gas
|
|
|
|
return buf.String()
|
|
}
|
|
|
|
// EnsureNodeSync waits until node synchronzation is done to continue
|
|
// with tests afterwards. Panics in case of an error or a timeout.
|
|
func EnsureNodeSync(nodeManager common.NodeManager) {
|
|
nc, err := nodeManager.NodeConfig()
|
|
if err != nil {
|
|
panic("can't retrieve NodeConfig")
|
|
}
|
|
// Don't wait for any blockchain sync for the local private chain as blocks are never mined.
|
|
if nc.NetworkID == params.StatusChainNetworkID {
|
|
return
|
|
}
|
|
|
|
les, err := nodeManager.LightEthereumService()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if les == nil {
|
|
panic("LightEthereumService is nil")
|
|
}
|
|
|
|
// todo(@jeka): we should extract it into config
|
|
timeout := time.NewTimer(50 * time.Minute)
|
|
defer timeout.Stop()
|
|
ticker := time.NewTicker(1 * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-timeout.C:
|
|
panic("timeout during node synchronization")
|
|
case <-ticker.C:
|
|
downloader := les.Downloader()
|
|
if downloader == nil {
|
|
continue
|
|
}
|
|
if nodeManager.PeerCount() == 0 {
|
|
log.Debug("No establishished connections with a 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 {
|
|
return
|
|
}
|
|
log.Debug(
|
|
fmt.Sprintf("synchronization is not finished yet: current block %d < highest block %d",
|
|
progress.CurrentBlock, progress.HighestBlock),
|
|
)
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetRemoteURLFromNetworkID returns associated network url for giving network id.
|
|
func GetRemoteURLFromNetworkID(id int) (url string, err error) {
|
|
switch id {
|
|
case params.MainNetworkID:
|
|
url = params.MainnetEthereumNetworkURL
|
|
case params.RinkebyNetworkID:
|
|
url = params.RinkebyEthereumNetworkURL
|
|
case params.RopstenNetworkID:
|
|
url = params.RopstenEthereumNetworkURL
|
|
default:
|
|
err = ErrNoRemoteURL
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// GetHeadHashFromNetworkID returns the hash associated with a given network id.
|
|
func GetHeadHashFromNetworkID(id int) string {
|
|
switch id {
|
|
case params.RinkebyNetworkID:
|
|
return "0x6341fd3daf94b748c72ced5a5b26028f2474f5f00d824504e4fa37a75767e177"
|
|
case params.RopstenNetworkID:
|
|
return "0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"
|
|
case params.StatusChainNetworkID:
|
|
return "0xe9d8920a99dc66a9557a87d51f9d14a34ec50aae04298e0f142187427d3c832e"
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// GetRemoteURL returns the url associated with a given network id.
|
|
func GetRemoteURL() (string, error) {
|
|
return GetRemoteURLFromNetworkID(GetNetworkID())
|
|
}
|
|
|
|
// GetHeadHash returns the hash associated with a given network id.
|
|
func GetHeadHash() string {
|
|
return GetHeadHashFromNetworkID(GetNetworkID())
|
|
}
|
|
|
|
// GetNetworkID returns appropriate network id for test based on
|
|
// default or provided -network flag.
|
|
func GetNetworkID() int {
|
|
switch strings.ToLower(*networkSelected) {
|
|
case fmt.Sprintf("%d", params.RinkebyNetworkID), "rinkeby":
|
|
return params.RinkebyNetworkID
|
|
case fmt.Sprintf("%d", params.RopstenNetworkID), "ropsten", "testnet":
|
|
return params.RopstenNetworkID
|
|
case fmt.Sprintf("%d", params.StatusChainNetworkID), "statuschain":
|
|
return params.StatusChainNetworkID
|
|
}
|
|
|
|
return params.StatusChainNetworkID
|
|
}
|
|
|
|
// GetAccount1PKFile returns the filename for Account1 keystore based
|
|
// on the current network. This allows running the e2e tests on the
|
|
// private network w/o access to the ACCOUNT_PASSWORD env variable
|
|
func GetAccount1PKFile() string {
|
|
if GetNetworkID() == params.StatusChainNetworkID {
|
|
return "test-account1-status-chain.pk"
|
|
}
|
|
return "test-account1.pk"
|
|
}
|
|
|
|
// GetAccount2PKFile returns the filename for Account2 keystore based
|
|
// on the current network. This allows running the e2e tests on the
|
|
// private network w/o access to the ACCOUNT_PASSWORD env variable
|
|
func GetAccount2PKFile() string {
|
|
if GetNetworkID() == params.StatusChainNetworkID {
|
|
return "test-account2-status-chain.pk"
|
|
}
|
|
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()
|
|
select {
|
|
case <-c:
|
|
return nil
|
|
case <-timer.C:
|
|
return ErrTimeout
|
|
}
|
|
|
|
}
|