forked from TrueCloudLab/neoneo-go
Merge pull request #2341 from nspcc-dev/cli/tests
cli: improve coverage
This commit is contained in:
commit
8dcfb19a1c
14 changed files with 901 additions and 57 deletions
6
.github/workflows/run_tests.yml
vendored
6
.github/workflows/run_tests.yml
vendored
|
@ -71,10 +71,10 @@ jobs:
|
||||||
run: go test -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
|
run: go test -v ./... -coverprofile=./coverage.txt -covermode=atomic -coverpkg=./pkg...,./cli/...
|
||||||
|
|
||||||
- name: Upload coverage results to Codecov
|
- name: Upload coverage results to Codecov
|
||||||
uses: codecov/codecov-action@v1
|
uses: codecov/codecov-action@v2
|
||||||
with:
|
with:
|
||||||
fail_ci_if_error: false
|
fail_ci_if_error: true # if something is wrong on uploading codecov results, then this job will fail
|
||||||
path_to_write_report: ./coverage.txt
|
files: ./coverage.txt
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
|
|
|
@ -56,15 +56,24 @@ func TestCalcHash(t *testing.T) {
|
||||||
t.Run("no manifest file", func(t *testing.T) {
|
t.Run("no manifest file", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath)...)
|
||||||
})
|
})
|
||||||
t.Run("invalid path", func(t *testing.T) {
|
t.Run("invalid nef path", func(t *testing.T) {
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
|
||||||
"--in", "./testdata/verify.nef123", "--manifest", manifestPath)...)
|
"--in", "./testdata/verify.nef123", "--manifest", manifestPath)...)
|
||||||
})
|
})
|
||||||
t.Run("invalid file", func(t *testing.T) {
|
t.Run("invalid manifest path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(),
|
||||||
|
"--in", nefPath, "--manifest", "./testdata/verify.manifest123")...)
|
||||||
|
})
|
||||||
|
t.Run("invalid nef file", func(t *testing.T) {
|
||||||
p := filepath.Join(tmpDir, "neogo.calchash.verify.nef")
|
p := filepath.Join(tmpDir, "neogo.calchash.verify.nef")
|
||||||
require.NoError(t, ioutil.WriteFile(p, src[:4], os.ModePerm))
|
require.NoError(t, ioutil.WriteFile(p, src[:4], os.ModePerm))
|
||||||
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", p, "--manifest", manifestPath)...)
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", p, "--manifest", manifestPath)...)
|
||||||
})
|
})
|
||||||
|
t.Run("invalid manifest file", func(t *testing.T) {
|
||||||
|
p := filepath.Join(tmpDir, "neogo.calchash.verify.manifest.json")
|
||||||
|
require.NoError(t, ioutil.WriteFile(p, manifestBytes[:4], os.ModePerm))
|
||||||
|
e.RunWithError(t, append(cmd, "--sender", sender.StringLE(), "--in", nefPath, "--manifest", p)...)
|
||||||
|
})
|
||||||
|
|
||||||
cmd = append(cmd, "--in", nefPath, "--manifest", manifestPath)
|
cmd = append(cmd, "--in", nefPath, "--manifest", manifestPath)
|
||||||
expected := state.CreateContractHash(sender, nefF.Checksum, manif.Name)
|
expected := state.CreateContractHash(sender, nefF.Checksum, manif.Name)
|
||||||
|
@ -123,6 +132,13 @@ func TestContractInitAndCompile(t *testing.T) {
|
||||||
cfgName := filepath.Join(ctrPath, "notexists.yml")
|
cfgName := filepath.Join(ctrPath, "notexists.yml")
|
||||||
e.RunWithError(t, append(cmd, "--config", cfgName)...)
|
e.RunWithError(t, append(cmd, "--config", cfgName)...)
|
||||||
})
|
})
|
||||||
|
t.Run("provided corrupted config", func(t *testing.T) {
|
||||||
|
data, err := ioutil.ReadFile(cfgPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
badCfg := filepath.Join(tmpDir, "bad.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(badCfg, data[:len(data)-5], os.ModePerm))
|
||||||
|
e.RunWithError(t, append(cmd, "--config", badCfg)...)
|
||||||
|
})
|
||||||
|
|
||||||
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
// Replace `pkg/interop` in go.mod to avoid getting an actual module version.
|
||||||
goMod := filepath.Join(ctrPath, "go.mod")
|
goMod := filepath.Join(ctrPath, "go.mod")
|
||||||
|
@ -263,6 +279,45 @@ func TestDeployWithSigners(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
|
t.Run("missing nef", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", "", "--manifest", manifestName)
|
||||||
|
})
|
||||||
|
t.Run("missing manifest", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", "")
|
||||||
|
})
|
||||||
|
t.Run("corrupted data", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", manifestName,
|
||||||
|
"[", "str1")
|
||||||
|
})
|
||||||
|
t.Run("invalid data", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", manifestName,
|
||||||
|
"str1", "str2")
|
||||||
|
})
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", manifestName,
|
||||||
|
"[", "str1", "str2", "]")
|
||||||
|
})
|
||||||
|
t.Run("missing RPC", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "deploy",
|
||||||
|
"--wallet", validatorWallet, "--address", validatorAddr,
|
||||||
|
"--in", nefName, "--manifest", manifestName,
|
||||||
|
"[", "str1", "str2", "]")
|
||||||
|
})
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "contract", "deploy",
|
e.Run(t, "neo-go", "contract", "deploy",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
@ -292,6 +347,54 @@ func TestContractManifestGroups(t *testing.T) {
|
||||||
"--config", "testdata/deploy/neo-go.yml",
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
"--out", nefName, "--manifest", manifestName)
|
"--out", nefName, "--manifest", manifestName)
|
||||||
|
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group")
|
||||||
|
})
|
||||||
|
t.Run("invalid wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", t.TempDir())
|
||||||
|
})
|
||||||
|
t.Run("invalid account", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", "not-an-acc")
|
||||||
|
})
|
||||||
|
t.Run("invalid sender", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", testWalletAccount,
|
||||||
|
"--sender", "not-a-sender")
|
||||||
|
})
|
||||||
|
t.Run("invalid NEF file", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", testWalletAccount,
|
||||||
|
"--sender", testWalletAccount, "--nef", tmpDir)
|
||||||
|
})
|
||||||
|
t.Run("corrupted NEF file", func(t *testing.T) {
|
||||||
|
f := filepath.Join(tmpDir, "invalid.nef")
|
||||||
|
require.NoError(t, ioutil.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", testWalletAccount,
|
||||||
|
"--sender", testWalletAccount, "--nef", f)
|
||||||
|
})
|
||||||
|
t.Run("invalid manifest file", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", testWalletAccount,
|
||||||
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
|
"--manifest", tmpDir)
|
||||||
|
})
|
||||||
|
t.Run("corrupted manifest file", func(t *testing.T) {
|
||||||
|
f := filepath.Join(tmpDir, "invalid.manifest.json")
|
||||||
|
require.NoError(t, ioutil.WriteFile(f, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", testWalletAccount,
|
||||||
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
|
"--manifest", f)
|
||||||
|
})
|
||||||
|
t.Run("unknown account", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "manifest", "add-group",
|
||||||
|
"--wallet", testWalletPath, "--account", util.Uint160{}.StringLE(),
|
||||||
|
"--sender", testWalletAccount, "--nef", nefName,
|
||||||
|
"--manifest", manifestName)
|
||||||
|
})
|
||||||
cmd := []string{"neo-go", "contract", "manifest", "add-group",
|
cmd := []string{"neo-go", "contract", "manifest", "add-group",
|
||||||
"--nef", nefName, "--manifest", manifestName}
|
"--nef", nefName, "--manifest", manifestName}
|
||||||
|
|
||||||
|
@ -338,6 +441,44 @@ func deployContract(t *testing.T, e *executor, inPath, configPath, wallet, addre
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContract_TestInvokeScript(t *testing.T) {
|
||||||
|
e := newExecutor(t, true)
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
badNef := filepath.Join(tmpDir, "invalid.nef")
|
||||||
|
goodNef := filepath.Join(tmpDir, "deploy.nef")
|
||||||
|
manifestName := filepath.Join(tmpDir, "deploy.manifest.json")
|
||||||
|
e.Run(t, "neo-go", "contract", "compile",
|
||||||
|
"--in", "testdata/deploy/main.go", // compile single file
|
||||||
|
"--config", "testdata/deploy/neo-go.yml",
|
||||||
|
"--out", goodNef, "--manifest", manifestName)
|
||||||
|
|
||||||
|
t.Run("missing in", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr)
|
||||||
|
})
|
||||||
|
t.Run("unexisting in", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--in", badNef)
|
||||||
|
})
|
||||||
|
t.Run("invalid nef", func(t *testing.T) {
|
||||||
|
require.NoError(t, ioutil.WriteFile(badNef, []byte("qwer"), os.ModePerm))
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--in", badNef)
|
||||||
|
})
|
||||||
|
t.Run("invalid signers", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--in", goodNef, "--", "not-a-valid-signer")
|
||||||
|
})
|
||||||
|
t.Run("no RPC endpoint", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "contract", "testinvokescript",
|
||||||
|
"--rpc-endpoint", "http://123456789",
|
||||||
|
"--in", goodNef)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestComlileAndInvokeFunction(t *testing.T) {
|
func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
@ -436,6 +577,33 @@ func TestComlileAndInvokeFunction(t *testing.T) {
|
||||||
h.StringLE(), "getValue")
|
h.StringLE(), "getValue")
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
|
t.Run("corrupted wallet", func(t *testing.T) {
|
||||||
|
tmp, err := ioutil.TempDir("", "tmp")
|
||||||
|
require.NoError(t, err)
|
||||||
|
tmpPath := filepath.Join(tmp, "wallet.json")
|
||||||
|
require.NoError(t, ioutil.WriteFile(tmpPath, []byte("{"), os.ModePerm))
|
||||||
|
|
||||||
|
cmd := append(cmd, "--wallet", tmpPath,
|
||||||
|
h.StringLE(), "getValue")
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
|
t.Run("non-existent address", func(t *testing.T) {
|
||||||
|
cmd := append(cmd, "--wallet", validatorWallet,
|
||||||
|
"--address", random.Uint160().StringLE(),
|
||||||
|
h.StringLE(), "getValue")
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid password", func(t *testing.T) {
|
||||||
|
e.In.WriteString("invalid_password\r")
|
||||||
|
cmd := append(cmd, "--wallet", validatorWallet,
|
||||||
|
h.StringLE(), "getValue")
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
|
t.Run("good: default address", func(t *testing.T) {
|
||||||
|
e.In.WriteString("one\r")
|
||||||
|
e.In.WriteString("y\r")
|
||||||
|
e.Run(t, append(cmd, "--wallet", validatorWallet, h.StringLE(), "getValue")...)
|
||||||
|
})
|
||||||
|
|
||||||
cmd = append(cmd, "--wallet", validatorWallet, "--address", validatorAddr)
|
cmd = append(cmd, "--wallet", validatorWallet, "--address", validatorAddr)
|
||||||
t.Run("cancelled", func(t *testing.T) {
|
t.Run("cancelled", func(t *testing.T) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -11,15 +12,19 @@ import (
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDBRestore(t *testing.T) {
|
func TestDBRestoreDump(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
loadConfig := func(t *testing.T) config.Config {
|
||||||
chainPath := filepath.Join(tmpDir, "neogotestchain")
|
chainPath := filepath.Join(tmpDir, "neogotestchain")
|
||||||
cfg, err := config.LoadFile(filepath.Join("..", "config", "protocol.unit_testnet.yml"))
|
cfg, err := config.LoadFile(filepath.Join("..", "config", "protocol.unit_testnet.yml"))
|
||||||
require.NoError(t, err, "could not load config")
|
require.NoError(t, err, "could not load config")
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.Type = "leveldb"
|
cfg.ApplicationConfiguration.DBConfiguration.Type = "leveldb"
|
||||||
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg := loadConfig(t)
|
||||||
out, err := yaml.Marshal(cfg)
|
out, err := yaml.Marshal(cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -29,6 +34,7 @@ func TestDBRestore(t *testing.T) {
|
||||||
// generated via `go run ./scripts/gendump/main.go --out ./cli/testdata/chain50x2.acc --blocks 50 --txs 2`
|
// generated via `go run ./scripts/gendump/main.go --out ./cli/testdata/chain50x2.acc --blocks 50 --txs 2`
|
||||||
const inDump = "./testdata/chain50x2.acc"
|
const inDump = "./testdata/chain50x2.acc"
|
||||||
e := newExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
stateDump := filepath.Join(tmpDir, "neogo.teststate")
|
stateDump := filepath.Join(tmpDir, "neogo.teststate")
|
||||||
baseArgs := []string{"neo-go", "db", "restore", "--unittest",
|
baseArgs := []string{"neo-go", "db", "restore", "--unittest",
|
||||||
"--config-path", tmpDir, "--in", inDump, "--dump", stateDump}
|
"--config-path", tmpDir, "--in", inDump, "--dump", stateDump}
|
||||||
|
@ -47,8 +53,50 @@ func TestDBRestore(t *testing.T) {
|
||||||
|
|
||||||
// Dump and compare.
|
// Dump and compare.
|
||||||
dumpPath := filepath.Join(tmpDir, "testdump.acc")
|
dumpPath := filepath.Join(tmpDir, "testdump.acc")
|
||||||
e.Run(t, "neo-go", "db", "dump", "--unittest",
|
|
||||||
|
t.Run("missing config", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "db", "dump", "--privnet",
|
||||||
"--config-path", tmpDir, "--out", dumpPath)
|
"--config-path", tmpDir, "--out", dumpPath)
|
||||||
|
})
|
||||||
|
t.Run("bad logger config", func(t *testing.T) {
|
||||||
|
badConfigDir := t.TempDir()
|
||||||
|
logfile := filepath.Join(badConfigDir, "logdir")
|
||||||
|
require.NoError(t, ioutil.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
cfg = loadConfig(t)
|
||||||
|
cfg.ApplicationConfiguration.LogPath = filepath.Join(logfile, "file.log")
|
||||||
|
out, err = yaml.Marshal(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfgPath = filepath.Join(badConfigDir, "protocol.unit_testnet.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(cfgPath, out, os.ModePerm))
|
||||||
|
|
||||||
|
e.RunWithError(t, "neo-go", "db", "dump", "--unittest",
|
||||||
|
"--config-path", badConfigDir, "--out", dumpPath)
|
||||||
|
})
|
||||||
|
t.Run("bad storage config", func(t *testing.T) {
|
||||||
|
badConfigDir := t.TempDir()
|
||||||
|
logfile := filepath.Join(badConfigDir, "logdir")
|
||||||
|
require.NoError(t, ioutil.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
cfg = loadConfig(t)
|
||||||
|
cfg.ApplicationConfiguration.DBConfiguration.Type = ""
|
||||||
|
out, err = yaml.Marshal(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfgPath = filepath.Join(badConfigDir, "protocol.unit_testnet.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(cfgPath, out, os.ModePerm))
|
||||||
|
|
||||||
|
e.RunWithError(t, "neo-go", "db", "dump", "--unittest",
|
||||||
|
"--config-path", badConfigDir, "--out", dumpPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
baseCmd := []string{"neo-go", "db", "dump", "--unittest",
|
||||||
|
"--config-path", tmpDir, "--out", dumpPath}
|
||||||
|
|
||||||
|
t.Run("invalid start/count", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(baseCmd, "--start", "5", "--count", strconv.Itoa(50-5+1+1))...)
|
||||||
|
})
|
||||||
|
|
||||||
|
e.Run(t, baseCmd...)
|
||||||
|
|
||||||
d1, err := ioutil.ReadFile(inDump)
|
d1, err := ioutil.ReadFile(inDump)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -58,13 +59,66 @@ type executor struct {
|
||||||
// NetSrv is a network server (can be empty).
|
// NetSrv is a network server (can be empty).
|
||||||
NetSrv *network.Server
|
NetSrv *network.Server
|
||||||
// Out contains command output.
|
// Out contains command output.
|
||||||
Out *bytes.Buffer
|
Out *ConcurrentBuffer
|
||||||
// Err contains command errors.
|
// Err contains command errors.
|
||||||
Err *bytes.Buffer
|
Err *bytes.Buffer
|
||||||
// In contains command input.
|
// In contains command input.
|
||||||
In *bytes.Buffer
|
In *bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConcurrentBuffer is a wrapper over Buffer with mutex.
|
||||||
|
type ConcurrentBuffer struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
buf *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConcurrentBuffer returns new ConcurrentBuffer with underlying buffer initialized.
|
||||||
|
func NewConcurrentBuffer() *ConcurrentBuffer {
|
||||||
|
return &ConcurrentBuffer{
|
||||||
|
buf: bytes.NewBuffer(nil),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is a concurrent wrapper over the corresponding method of bytes.Buffer.
|
||||||
|
func (w *ConcurrentBuffer) Write(p []byte) (int, error) {
|
||||||
|
w.lock.Lock()
|
||||||
|
defer w.lock.Unlock()
|
||||||
|
|
||||||
|
return w.buf.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadString is a concurrent wrapper over the corresponding method of bytes.Buffer.
|
||||||
|
func (w *ConcurrentBuffer) ReadString(delim byte) (string, error) {
|
||||||
|
w.lock.RLock()
|
||||||
|
defer w.lock.RUnlock()
|
||||||
|
|
||||||
|
return w.buf.ReadString(delim)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bytes is a concurrent wrapper over the corresponding method of bytes.Buffer.
|
||||||
|
func (w *ConcurrentBuffer) Bytes() []byte {
|
||||||
|
w.lock.RLock()
|
||||||
|
defer w.lock.RUnlock()
|
||||||
|
|
||||||
|
return w.buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is a concurrent wrapper over the corresponding method of bytes.Buffer.
|
||||||
|
func (w *ConcurrentBuffer) String() string {
|
||||||
|
w.lock.RLock()
|
||||||
|
defer w.lock.RUnlock()
|
||||||
|
|
||||||
|
return w.buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset is a concurrent wrapper over the corresponding method of bytes.Buffer.
|
||||||
|
func (w *ConcurrentBuffer) Reset() {
|
||||||
|
w.lock.Lock()
|
||||||
|
defer w.lock.Unlock()
|
||||||
|
|
||||||
|
w.buf.Reset()
|
||||||
|
}
|
||||||
|
|
||||||
func newTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockchain, *server.Server, *network.Server) {
|
func newTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockchain, *server.Server, *network.Server) {
|
||||||
configPath := "../config/protocol.unit_testnet.single.yml"
|
configPath := "../config/protocol.unit_testnet.single.yml"
|
||||||
cfg, err := config.LoadFile(configPath)
|
cfg, err := config.LoadFile(configPath)
|
||||||
|
@ -115,7 +169,7 @@ func newExecutorSuspended(t *testing.T) *executor {
|
||||||
func newExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*config.Config)) *executor {
|
func newExecutorWithConfig(t *testing.T, needChain, runChain bool, f func(*config.Config)) *executor {
|
||||||
e := &executor{
|
e := &executor{
|
||||||
CLI: newApp(),
|
CLI: newApp(),
|
||||||
Out: bytes.NewBuffer(nil),
|
Out: NewConcurrentBuffer(),
|
||||||
Err: bytes.NewBuffer(nil),
|
Err: bytes.NewBuffer(nil),
|
||||||
In: bytes.NewBuffer(nil),
|
In: bytes.NewBuffer(nil),
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -64,6 +65,51 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("bad cases", func(t *testing.T) {
|
||||||
|
txPath := filepath.Join(tmpDir, "multisigtx.json")
|
||||||
|
t.Cleanup(func() {
|
||||||
|
os.Remove(txPath)
|
||||||
|
})
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "nep17", "transfer",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wallet1Path, "--from", multisigAddr,
|
||||||
|
"--to", priv.Address(), "--token", "NEO", "--amount", "1",
|
||||||
|
"--out", txPath)
|
||||||
|
|
||||||
|
// missing wallet
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign")
|
||||||
|
|
||||||
|
// missing in
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--wallet", wallet2Path)
|
||||||
|
|
||||||
|
// missing address
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--wallet", wallet2Path,
|
||||||
|
"--in", txPath)
|
||||||
|
|
||||||
|
// invalid address
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--wallet", wallet2Path, "--address", util.Uint160{}.StringLE(),
|
||||||
|
"--in", txPath)
|
||||||
|
|
||||||
|
// invalid out
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
|
"--in", txPath, "--out", t.TempDir())
|
||||||
|
|
||||||
|
// invalid RPC endpoint
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--rpc-endpoint", "http://not-an-address",
|
||||||
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
|
"--in", txPath)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create transaction and save it for further multisigning.
|
||||||
txPath := filepath.Join(tmpDir, "multisigtx.json")
|
txPath := filepath.Join(tmpDir, "multisigtx.json")
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
os.Remove(txPath)
|
os.Remove(txPath)
|
||||||
|
@ -90,12 +136,6 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// missing address
|
|
||||||
e.RunWithError(t, "neo-go", "wallet", "sign",
|
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
|
||||||
"--wallet", wallet2Path,
|
|
||||||
"--in", txPath, "--out", txPath)
|
|
||||||
|
|
||||||
t.Run("test invoke", func(t *testing.T) {
|
t.Run("test invoke", func(t *testing.T) {
|
||||||
t.Run("missing file", func(t *testing.T) {
|
t.Run("missing file", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "util", "txdump")
|
e.RunWithError(t, "neo-go", "util", "txdump")
|
||||||
|
@ -124,6 +164,14 @@ func TestSignMultisigTx(t *testing.T) {
|
||||||
"--in", txPath, "--out", txPath)
|
"--in", txPath, "--out", txPath)
|
||||||
e.checkTxPersisted(t)
|
e.checkTxPersisted(t)
|
||||||
|
|
||||||
|
t.Run("double-sign", func(t *testing.T) {
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "sign",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", wallet2Path, "--address", multisigAddr,
|
||||||
|
"--in", txPath, "--out", txPath)
|
||||||
|
})
|
||||||
|
|
||||||
b, _ := e.Chain.GetGoverningTokenBalance(priv.GetScriptHash())
|
b, _ := e.Chain.GetGoverningTokenBalance(priv.GetScriptHash())
|
||||||
require.Equal(t, big.NewInt(1), b)
|
require.Equal(t, big.NewInt(1), b)
|
||||||
b, _ = e.Chain.GetGoverningTokenBalance(multisigHash)
|
b, _ = e.Chain.GetGoverningTokenBalance(multisigHash)
|
||||||
|
|
|
@ -393,11 +393,11 @@ func mkP2PNotary(config network.ServerConfig, chain *core.Blockchain, serv *netw
|
||||||
func startServer(ctx *cli.Context) error {
|
func startServer(ctx *cli.Context) error {
|
||||||
cfg, err := getConfigFromContext(ctx)
|
cfg, err := getConfigFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
log, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
log, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
grace, cancel := context.WithCancel(newGraceContext())
|
grace, cancel := context.WithCancel(newGraceContext())
|
||||||
|
@ -407,7 +407,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
serv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), log)
|
serv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), log)
|
||||||
|
@ -423,15 +423,15 @@ func startServer(ctx *cli.Context) error {
|
||||||
|
|
||||||
oracleSrv, err := mkOracle(serverConfig, chain, serv, log)
|
oracleSrv, err := mkOracle(serverConfig, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
_, err = mkConsensus(serverConfig, chain, serv, log)
|
_, err = mkConsensus(serverConfig, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
_, err = mkP2PNotary(serverConfig, chain, serv, log)
|
_, err = mkP2PNotary(serverConfig, chain, serv, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
rpcServer := server.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log)
|
rpcServer := server.New(chain, cfg.ApplicationConfiguration.RPC, serv, oracleSrv, log)
|
||||||
errChan := make(chan error)
|
errChan := make(chan error)
|
||||||
|
@ -442,7 +442,7 @@ func startServer(ctx *cli.Context) error {
|
||||||
sighupCh := make(chan os.Signal, 1)
|
sighupCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sighupCh, syscall.SIGHUP)
|
signal.Notify(sighupCh, syscall.SIGHUP)
|
||||||
|
|
||||||
fmt.Fprintln(ctx.App.Writer, logo())
|
fmt.Fprintln(ctx.App.Writer, Logo())
|
||||||
fmt.Fprintln(ctx.App.Writer, serv.UserAgent)
|
fmt.Fprintln(ctx.App.Writer, serv.UserAgent)
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
|
|
||||||
|
@ -517,7 +517,8 @@ func initBlockChain(cfg config.Config, log *zap.Logger) (*core.Blockchain, error
|
||||||
return chain, nil
|
return chain, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func logo() string {
|
// Logo returns Neo-Go logo.
|
||||||
|
func Logo() string {
|
||||||
return `
|
return `
|
||||||
_ ____________ __________
|
_ ____________ __________
|
||||||
/ | / / ____/ __ \ / ____/ __ \
|
/ | / / ____/ __ \ / ____/ __ \
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"flag"
|
"flag"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -14,6 +16,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// serverTestWD is the default working directory for server tests.
|
// serverTestWD is the default working directory for server tests.
|
||||||
|
@ -42,6 +45,18 @@ func TestHandleLoggingParams(t *testing.T) {
|
||||||
d := t.TempDir()
|
d := t.TempDir()
|
||||||
testLog := filepath.Join(d, "file.log")
|
testLog := filepath.Join(d, "file.log")
|
||||||
|
|
||||||
|
t.Run("logdir is a file", func(t *testing.T) {
|
||||||
|
logfile := filepath.Join(d, "logdir")
|
||||||
|
require.NoError(t, ioutil.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
cfg := config.ApplicationConfiguration{
|
||||||
|
LogPath: filepath.Join(logfile, "file.log"),
|
||||||
|
}
|
||||||
|
_, err := handleLoggingParams(ctx, cfg)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("default", func(t *testing.T) {
|
t.Run("default", func(t *testing.T) {
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
ctx := cli.NewContext(cli.NewApp(), set, nil)
|
||||||
|
@ -83,6 +98,12 @@ func TestInitBCWithMetrics(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
logger, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
logger, err := handleLoggingParams(ctx, cfg.ApplicationConfiguration)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("bad store", func(t *testing.T) {
|
||||||
|
_, _, _, err = initBCWithMetrics(config.Config{}, logger)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, logger)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, logger)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
|
@ -139,9 +160,10 @@ func TestRestoreDB(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() { require.NoError(t, os.Chdir(serverTestWD)) })
|
t.Cleanup(func() { require.NoError(t, os.Chdir(serverTestWD)) })
|
||||||
|
|
||||||
//dump first
|
// dump first
|
||||||
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
|
||||||
set.String("config-path", filepath.Join(serverTestWD, "..", "..", "config"), "")
|
goodCfg := filepath.Join(serverTestWD, "..", "..", "config")
|
||||||
|
cfgPath := set.String("config-path", goodCfg, "")
|
||||||
set.Bool("privnet", true, "")
|
set.Bool("privnet", true, "")
|
||||||
set.Bool("debug", true, "")
|
set.Bool("debug", true, "")
|
||||||
set.Int("start", 0, "")
|
set.Int("start", 0, "")
|
||||||
|
@ -152,7 +174,101 @@ func TestRestoreDB(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// and then restore
|
// and then restore
|
||||||
set.String("in", testDump, "")
|
t.Run("invalid config", func(t *testing.T) {
|
||||||
|
*cfgPath = filepath.Join(serverTestWD, "..", "..", "config_invalid")
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
})
|
||||||
|
t.Run("invalid logger path", func(t *testing.T) {
|
||||||
|
badCfgDir := t.TempDir()
|
||||||
|
logfile := filepath.Join(badCfgDir, "logdir")
|
||||||
|
require.NoError(t, ioutil.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"))
|
||||||
|
require.NoError(t, err, "could not load config")
|
||||||
|
cfg.ApplicationConfiguration.LogPath = filepath.Join(logfile, "file.log")
|
||||||
|
out, err := yaml.Marshal(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
badCfgPath := filepath.Join(badCfgDir, "protocol.privnet.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(badCfgPath, out, os.ModePerm))
|
||||||
|
|
||||||
|
*cfgPath = badCfgDir
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
|
||||||
|
*cfgPath = goodCfg
|
||||||
|
})
|
||||||
|
t.Run("invalid bc config", func(t *testing.T) {
|
||||||
|
badCfgDir := t.TempDir()
|
||||||
|
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"))
|
||||||
|
require.NoError(t, err, "could not load config")
|
||||||
|
cfg.ApplicationConfiguration.DBConfiguration.Type = ""
|
||||||
|
out, err := yaml.Marshal(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
badCfgPath := filepath.Join(badCfgDir, "protocol.privnet.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(badCfgPath, out, os.ModePerm))
|
||||||
|
|
||||||
|
*cfgPath = badCfgDir
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
|
||||||
|
*cfgPath = goodCfg
|
||||||
|
})
|
||||||
|
|
||||||
|
in := set.String("in", testDump, "")
|
||||||
|
incremental := set.Bool("incremental", false, "")
|
||||||
|
t.Run("invalid in", func(t *testing.T) {
|
||||||
|
*in = "unknown-file"
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
|
||||||
|
*in = testDump
|
||||||
|
})
|
||||||
|
t.Run("corrupted in: invalid block count", func(t *testing.T) {
|
||||||
|
inPath := filepath.Join(t.TempDir(), "file3.acc")
|
||||||
|
require.NoError(t, ioutil.WriteFile(inPath, []byte{1, 2, 3}, // file is expected to start from uint32
|
||||||
|
os.ModePerm))
|
||||||
|
*in = inPath
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
|
||||||
|
*in = testDump
|
||||||
|
})
|
||||||
|
t.Run("corrupted in: corrupted block", func(t *testing.T) {
|
||||||
|
inPath := filepath.Join(t.TempDir(), "file3.acc")
|
||||||
|
b, err := ioutil.ReadFile(testDump)
|
||||||
|
require.NoError(t, err)
|
||||||
|
b[5] = 0xff // file is expected to start from uint32 (4 bytes) followed by the first block, so corrupt the first block bytes
|
||||||
|
require.NoError(t, ioutil.WriteFile(inPath, b, os.ModePerm))
|
||||||
|
*in = inPath
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
|
||||||
|
*in = testDump
|
||||||
|
})
|
||||||
|
t.Run("incremental dump", func(t *testing.T) {
|
||||||
|
inPath := filepath.Join(t.TempDir(), "file1_incremental.acc")
|
||||||
|
b, err := ioutil.ReadFile(testDump)
|
||||||
|
require.NoError(t, err)
|
||||||
|
start := make([]byte, 4)
|
||||||
|
t.Run("good", func(t *testing.T) {
|
||||||
|
binary.LittleEndian.PutUint32(start, 1) // start from the first block
|
||||||
|
require.NoError(t, ioutil.WriteFile(inPath, append(start, b...),
|
||||||
|
os.ModePerm))
|
||||||
|
*in = inPath
|
||||||
|
*incremental = true
|
||||||
|
|
||||||
|
require.NoError(t, restoreDB(ctx))
|
||||||
|
})
|
||||||
|
t.Run("dump is too high", func(t *testing.T) {
|
||||||
|
binary.LittleEndian.PutUint32(start, 2) // start from the second block
|
||||||
|
require.NoError(t, ioutil.WriteFile(inPath, append(start, b...),
|
||||||
|
os.ModePerm))
|
||||||
|
*in = inPath
|
||||||
|
*incremental = true
|
||||||
|
|
||||||
|
require.Error(t, restoreDB(ctx))
|
||||||
|
})
|
||||||
|
|
||||||
|
*in = testDump
|
||||||
|
*incremental = false
|
||||||
|
})
|
||||||
|
|
||||||
set.String("dump", saveDump, "")
|
set.String("dump", saveDump, "")
|
||||||
require.NoError(t, restoreDB(ctx))
|
require.NoError(t, restoreDB(ctx))
|
||||||
}
|
}
|
||||||
|
|
124
cli/server_test.go
Normal file
124
cli/server_test.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/cli/server"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServerStart(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
goodCfg, err := config.LoadFile(filepath.Join("..", "config", "protocol.unit_testnet.yml"))
|
||||||
|
require.NoError(t, err, "could not load config")
|
||||||
|
ptr := &goodCfg
|
||||||
|
saveCfg := func(t *testing.T, f func(cfg *config.Config)) string {
|
||||||
|
cfg := *ptr
|
||||||
|
chainPath := filepath.Join(t.TempDir(), "neogotestchain")
|
||||||
|
cfg.ApplicationConfiguration.DBConfiguration.Type = "leveldb"
|
||||||
|
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
|
||||||
|
f(&cfg)
|
||||||
|
out, err := yaml.Marshal(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cfgPath := filepath.Join(tmpDir, "protocol.unit_testnet.yml")
|
||||||
|
require.NoError(t, ioutil.WriteFile(cfgPath, out, os.ModePerm))
|
||||||
|
t.Cleanup(func() {
|
||||||
|
require.NoError(t, os.Remove(cfgPath))
|
||||||
|
})
|
||||||
|
return cfgPath
|
||||||
|
}
|
||||||
|
|
||||||
|
baseCmd := []string{"neo-go", "node", "--unittest", "--config-path", tmpDir}
|
||||||
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
t.Run("invalid config path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("bad logger config", func(t *testing.T) {
|
||||||
|
badConfigDir := t.TempDir()
|
||||||
|
logfile := filepath.Join(badConfigDir, "logdir")
|
||||||
|
require.NoError(t, ioutil.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ApplicationConfiguration.LogPath = filepath.Join(logfile, "file.log")
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid storage", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ApplicationConfiguration.DBConfiguration.Type = ""
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("stateroot service is on && StateRootInHeader=true", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ApplicationConfiguration.StateRoot.Enabled = true
|
||||||
|
cfg.ProtocolConfiguration.StateRootInHeader = true
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid Oracle config", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ApplicationConfiguration.Oracle.Enabled = true
|
||||||
|
cfg.ApplicationConfiguration.Oracle.UnlockWallet.Path = "bad_orc_wallet.json"
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid consensus config", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ApplicationConfiguration.UnlockWallet.Path = "bad_consensus_wallet.json"
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid Notary config", func(t *testing.T) {
|
||||||
|
t.Run("malformed config", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ProtocolConfiguration.P2PSigExtensions = false
|
||||||
|
cfg.ApplicationConfiguration.P2PNotary.Enabled = true
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid wallet", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {
|
||||||
|
cfg.ProtocolConfiguration.P2PSigExtensions = true
|
||||||
|
cfg.ApplicationConfiguration.P2PNotary.Enabled = true
|
||||||
|
cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path = "bad_notary_wallet.json"
|
||||||
|
})
|
||||||
|
e.RunWithError(t, baseCmd...)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("good", func(t *testing.T) {
|
||||||
|
saveCfg(t, func(cfg *config.Config) {})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
e.Run(t, baseCmd...)
|
||||||
|
}()
|
||||||
|
|
||||||
|
var line string
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
line, err = e.Out.ReadString('\n')
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
t.Fatalf(fmt.Sprintf("unexpected error while reading CLI output: %s", err))
|
||||||
|
}
|
||||||
|
return err == nil
|
||||||
|
}, 2*time.Second, 100*time.Millisecond)
|
||||||
|
lines := strings.Split(server.Logo(), "\n")
|
||||||
|
for _, expected := range lines {
|
||||||
|
// It should be regexp, so escape all backslashes.
|
||||||
|
expected = strings.ReplaceAll(expected, `\`, `\\`)
|
||||||
|
e.checkLine(t, line, expected)
|
||||||
|
line = e.getNextLine(t)
|
||||||
|
}
|
||||||
|
e.checkNextLine(t, "")
|
||||||
|
e.checkEOF(t)
|
||||||
|
})
|
||||||
|
}
|
|
@ -29,12 +29,12 @@ func manifestAddGroup(ctx *cli.Context) error {
|
||||||
|
|
||||||
addr, err := flags.ParseAddress(ctx.String("account"))
|
addr, err := flags.ParseAddress(ctx.String("account"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(errors.New("address is missing"), 1)
|
return cli.NewExitError(fmt.Errorf("account is invalid or missing: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
sender, err := flags.ParseAddress(ctx.String("sender"))
|
sender, err := flags.ParseAddress(ctx.String("sender"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError("invalid sender", 1)
|
return cli.NewExitError(fmt.Errorf("invalid sender: %w", err), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
nf, _, err := readNEFFile(ctx.String("nef"))
|
nf, _, err := readNEFFile(ctx.String("nef"))
|
||||||
|
|
|
@ -653,18 +653,30 @@ func invokeWithArgs(ctx *cli.Context, acc *wallet.Account, wall *wallet.Wallet,
|
||||||
return sender, err
|
return sender, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out := ctx.String("out")
|
||||||
resp, err = c.InvokeFunction(script, operation, params, cosigners)
|
resp, err = c.InvokeFunction(script, operation, params, cosigners)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sender, cli.NewExitError(err, 1)
|
return sender, cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
if signAndPush && resp.State != "HALT" {
|
if resp.State != "HALT" {
|
||||||
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s\n", resp.State, resp.FaultException)
|
errText := fmt.Sprintf("Warning: %s VM state returned from the RPC node: %s\n", resp.State, resp.FaultException)
|
||||||
|
action := "save"
|
||||||
|
process := "Saving"
|
||||||
|
if signAndPush {
|
||||||
|
if out != "" {
|
||||||
|
action += "and send"
|
||||||
|
process += "and sending"
|
||||||
|
} else {
|
||||||
|
action = "send"
|
||||||
|
process = "Sending"
|
||||||
|
}
|
||||||
|
}
|
||||||
if !ctx.Bool("force") {
|
if !ctx.Bool("force") {
|
||||||
return sender, cli.NewExitError(errText+". Use --force flag to send the transaction anyway.", 1)
|
return sender, cli.NewExitError(errText+". Use --force flag to "+action+" the transaction anyway.", 1)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, errText+". Sending transaction...")
|
fmt.Fprintln(ctx.App.Writer, errText+". "+process+" transaction...")
|
||||||
}
|
}
|
||||||
if out := ctx.String("out"); out != "" {
|
if out != "" {
|
||||||
tx, err := c.CreateTxFromScript(resp.Script, acc, resp.GasConsumed+int64(sysgas), int64(gas), cosignersAccounts)
|
tx, err := c.CreateTxFromScript(resp.Script, acc, resp.GasConsumed+int64(sysgas), int64(gas), cosignersAccounts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sender, cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
return sender, cli.NewExitError(fmt.Errorf("failed to create tx: %w", err), 1)
|
||||||
|
|
25
cli/util_test.go
Normal file
25
cli/util_test.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUtilConvert(t *testing.T) {
|
||||||
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
e.Run(t, "neo-go", "util", "convert", util.Uint160{1, 2, 3}.StringLE())
|
||||||
|
e.checkNextLine(t, "f975") // int to hex
|
||||||
|
e.checkNextLine(t, "\\+XU=") // int to base64
|
||||||
|
e.checkNextLine(t, "NKuyBkoGdZZSLyPbJEetheRhMrGSCQx7YL") // BE to address
|
||||||
|
e.checkNextLine(t, "NL1JGiyJXdTkvFksXbFxgLJcWLj8Ewe7HW") // LE to address
|
||||||
|
e.checkNextLine(t, "Hex to String") // hex to string
|
||||||
|
e.checkNextLine(t, "5753853598078696051256155186041784866529345536") // hex to int
|
||||||
|
e.checkNextLine(t, "0102030000000000000000000000000000000000") // swap endianness
|
||||||
|
e.checkNextLine(t, "Base64 to String") // base64 to string
|
||||||
|
e.checkNextLine(t, "368753434210909009569191652203865891677393101439813372294890211308228051") // base64 to bigint
|
||||||
|
e.checkNextLine(t, "30303030303030303030303030303030303030303030303030303030303030303030303330323031") // string to hex
|
||||||
|
e.checkNextLine(t, "MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAzMDIwMQ==") // string to base64
|
||||||
|
e.checkEOF(t)
|
||||||
|
}
|
|
@ -356,7 +356,11 @@ func convertWallet(ctx *cli.Context) error {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
newWallet, err := wallet.NewWallet(ctx.String("out"))
|
out := ctx.String("out")
|
||||||
|
if len(out) == 0 {
|
||||||
|
return cli.NewExitError("missing out path", 1)
|
||||||
|
}
|
||||||
|
newWallet, err := wallet.NewWallet(out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cli.NewExitError(err, 1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
|
@ -375,7 +379,7 @@ func convertWallet(ctx *cli.Context) error {
|
||||||
newWallet.AddAccount(newAcc)
|
newWallet.AddAccount(newAcc)
|
||||||
}
|
}
|
||||||
if err := newWallet.Save(); err != nil {
|
if err := newWallet.Save(); err != nil {
|
||||||
return cli.NewExitError(err, -1)
|
return cli.NewExitError(err, 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -605,7 +609,8 @@ func removeAccount(ctx *cli.Context) error {
|
||||||
|
|
||||||
if err := wall.RemoveAccount(acc.Address); err != nil {
|
if err := wall.RemoveAccount(acc.Address); err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("error on remove: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("error on remove: %w", err), 1)
|
||||||
} else if err := wall.Save(); err != nil {
|
}
|
||||||
|
if err := wall.Save(); err != nil {
|
||||||
return cli.NewExitError(fmt.Errorf("error while saving wallet: %w", err), 1)
|
return cli.NewExitError(fmt.Errorf("error while saving wallet: %w", err), 1)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -3,7 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -14,6 +13,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -36,13 +36,34 @@ func TestWalletAccountRemove(t *testing.T) {
|
||||||
w, err := wallet.NewWalletFromFile(walletPath)
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "remove")
|
||||||
|
})
|
||||||
|
t.Run("missing address", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath)
|
||||||
|
})
|
||||||
|
t.Run("invalid address", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
||||||
|
"--address", util.Uint160{}.StringLE())
|
||||||
|
})
|
||||||
|
|
||||||
addr := w.Accounts[0].Address
|
addr := w.Accounts[0].Address
|
||||||
|
t.Run("askForConsent > no", func(t *testing.T) {
|
||||||
|
e.In.WriteString("no")
|
||||||
|
e.Run(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
||||||
|
"--address", addr)
|
||||||
|
actual, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, w, actual)
|
||||||
|
})
|
||||||
|
|
||||||
e.Run(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
e.Run(t, "neo-go", "wallet", "remove", "--wallet", walletPath,
|
||||||
"--address", addr, "--force")
|
"--address", addr, "--force")
|
||||||
|
|
||||||
rawWallet, err := ioutil.ReadFile(walletPath)
|
actual, err := wallet.NewWalletFromFile(walletPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, json.Unmarshal(rawWallet, new(wallet.Wallet)))
|
require.Equal(t, 1, len(actual.Accounts))
|
||||||
|
require.Equal(t, w.Accounts[1], actual.Accounts[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWalletChangePassword(t *testing.T) {
|
func TestWalletChangePassword(t *testing.T) {
|
||||||
|
@ -65,6 +86,12 @@ func TestWalletChangePassword(t *testing.T) {
|
||||||
|
|
||||||
addr1 := w.Accounts[0].Address
|
addr1 := w.Accounts[0].Address
|
||||||
addr2 := w.Accounts[1].Address
|
addr2 := w.Accounts[1].Address
|
||||||
|
t.Run("missing wallet path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "change-password")
|
||||||
|
})
|
||||||
|
t.Run("EOF reading old password", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "change-password", "--wallet", walletPath)
|
||||||
|
})
|
||||||
t.Run("bad old password", func(t *testing.T) {
|
t.Run("bad old password", func(t *testing.T) {
|
||||||
e.In.WriteString("ssap\r")
|
e.In.WriteString("ssap\r")
|
||||||
e.In.WriteString("aaa\r") // Pretend for the password to be fine.
|
e.In.WriteString("aaa\r") // Pretend for the password to be fine.
|
||||||
|
@ -112,9 +139,46 @@ func TestWalletChangePassword(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWalletInit(t *testing.T) {
|
func TestWalletInit(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
|
||||||
e := newExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
t.Run("missing path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "init")
|
||||||
|
})
|
||||||
|
t.Run("invalid path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "init", "--wallet", t.TempDir())
|
||||||
|
})
|
||||||
|
t.Run("good: no account", func(t *testing.T) {
|
||||||
|
walletPath := filepath.Join(t.TempDir(), "wallet.json")
|
||||||
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
||||||
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 0, len(w.Accounts))
|
||||||
|
})
|
||||||
|
t.Run("with account", func(t *testing.T) {
|
||||||
|
walletPath := filepath.Join(t.TempDir(), "wallet.json")
|
||||||
|
t.Run("missing acc name", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "init", "--wallet", walletPath, "--account")
|
||||||
|
})
|
||||||
|
t.Run("missing pass", func(t *testing.T) {
|
||||||
|
e.In.WriteString("acc\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "init", "--wallet", walletPath, "--account")
|
||||||
|
})
|
||||||
|
t.Run("missing second pass", func(t *testing.T) {
|
||||||
|
e.In.WriteString("acc\r")
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "init", "--wallet", walletPath, "--account")
|
||||||
|
})
|
||||||
|
e.In.WriteString("acc\r")
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.In.WriteString("pass\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath, "--account")
|
||||||
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(w.Accounts))
|
||||||
|
require.Equal(t, "acc", w.Accounts[0].Label)
|
||||||
|
})
|
||||||
|
|
||||||
|
tmpDir := t.TempDir()
|
||||||
walletPath := filepath.Join(tmpDir, "wallet.json")
|
walletPath := filepath.Join(tmpDir, "wallet.json")
|
||||||
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
e.Run(t, "neo-go", "wallet", "init", "--wallet", walletPath)
|
||||||
|
|
||||||
|
@ -144,6 +208,12 @@ func TestWalletInit(t *testing.T) {
|
||||||
t.Run("stdin", func(t *testing.T) {
|
t.Run("stdin", func(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "create", "--wallet", "-")
|
e.RunWithError(t, "neo-go", "wallet", "create", "--wallet", "-")
|
||||||
})
|
})
|
||||||
|
t.Run("passwords mismatch", func(t *testing.T) {
|
||||||
|
e.In.WriteString("testname\r")
|
||||||
|
e.In.WriteString("testpass\r")
|
||||||
|
e.In.WriteString("badpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "create", "--wallet", walletPath)
|
||||||
|
})
|
||||||
e.In.WriteString("testname\r")
|
e.In.WriteString("testname\r")
|
||||||
e.In.WriteString("testpass\r")
|
e.In.WriteString("testpass\r")
|
||||||
e.In.WriteString("testpass\r")
|
e.In.WriteString("testpass\r")
|
||||||
|
@ -171,6 +241,9 @@ func TestWalletInit(t *testing.T) {
|
||||||
|
|
||||||
t.Run("Import", func(t *testing.T) {
|
t.Run("Import", func(t *testing.T) {
|
||||||
t.Run("WIF", func(t *testing.T) {
|
t.Run("WIF", func(t *testing.T) {
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import")
|
||||||
|
})
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
e.In.WriteString("test_account\r")
|
e.In.WriteString("test_account\r")
|
||||||
|
@ -194,6 +267,33 @@ func TestWalletInit(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import",
|
e.RunWithError(t, "neo-go", "wallet", "import",
|
||||||
"--wallet", walletPath, "--wif", priv.WIF())
|
"--wallet", walletPath, "--wif", priv.WIF())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("contract", func(t *testing.T) {
|
||||||
|
priv, err = keys.NewPrivateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("invalid script", func(t *testing.T) {
|
||||||
|
e.In.WriteString("test_account_3\r")
|
||||||
|
e.In.WriteString("qwerty\r")
|
||||||
|
e.In.WriteString("qwerty\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import",
|
||||||
|
"--wallet", walletPath, "--wif", priv.WIF(), "--contract", "not-a-hex")
|
||||||
|
})
|
||||||
|
|
||||||
|
e.In.WriteString("test_account_3\r")
|
||||||
|
e.In.WriteString("qwerty\r")
|
||||||
|
e.In.WriteString("qwerty\r")
|
||||||
|
e.Run(t, "neo-go", "wallet", "import",
|
||||||
|
"--wallet", walletPath, "--wif", priv.WIF(), "--contract", "0a0b0c")
|
||||||
|
|
||||||
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(w.Close)
|
||||||
|
acc := w.GetAccount(priv.GetScriptHash())
|
||||||
|
require.NotNil(t, acc)
|
||||||
|
require.Equal(t, "test_account_3", acc.Label)
|
||||||
|
require.NoError(t, acc.Decrypt("qwerty", w.Scrypt))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
t.Run("EncryptedWIF", func(t *testing.T) {
|
t.Run("EncryptedWIF", func(t *testing.T) {
|
||||||
acc, err := wallet.NewAccount()
|
acc, err := wallet.NewAccount()
|
||||||
|
@ -218,12 +318,31 @@ func TestWalletInit(t *testing.T) {
|
||||||
require.NoError(t, actual.Decrypt("somepass", w.Scrypt))
|
require.NoError(t, actual.Decrypt("somepass", w.Scrypt))
|
||||||
})
|
})
|
||||||
t.Run("Multisig", func(t *testing.T) {
|
t.Run("Multisig", func(t *testing.T) {
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-multisig")
|
||||||
|
})
|
||||||
|
t.Run("insufficient pubs", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-multisig",
|
||||||
|
"--wallet", walletPath,
|
||||||
|
"--min", "2")
|
||||||
|
})
|
||||||
privs, pubs := generateKeys(t, 4)
|
privs, pubs := generateKeys(t, 4)
|
||||||
|
|
||||||
cmd := []string{"neo-go", "wallet", "import-multisig",
|
cmd := []string{"neo-go", "wallet", "import-multisig",
|
||||||
"--wallet", walletPath,
|
"--wallet", walletPath,
|
||||||
"--wif", privs[0].WIF(),
|
|
||||||
"--min", "2"}
|
"--min", "2"}
|
||||||
|
t.Run("invalid pub encoding", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[1].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[1].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[2].Bytes()),
|
||||||
|
"not-a-pub")...)
|
||||||
|
})
|
||||||
|
t.Run("missing WIF", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[1].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[2].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||||
|
})
|
||||||
|
cmd = append(cmd, "--wif", privs[0].WIF())
|
||||||
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
t.Run("InvalidPublicKeys", func(t *testing.T) {
|
||||||
e.In.WriteString("multiacc\r")
|
e.In.WriteString("multiacc\r")
|
||||||
e.In.WriteString("multipass\r")
|
e.In.WriteString("multipass\r")
|
||||||
|
@ -253,6 +372,16 @@ func TestWalletInit(t *testing.T) {
|
||||||
require.NotNil(t, actual)
|
require.NotNil(t, actual)
|
||||||
require.NoError(t, actual.Decrypt("multipass", w.Scrypt))
|
require.NoError(t, actual.Decrypt("multipass", w.Scrypt))
|
||||||
require.Equal(t, script, actual.Contract.Script)
|
require.Equal(t, script, actual.Contract.Script)
|
||||||
|
|
||||||
|
t.Run("double-import", func(t *testing.T) {
|
||||||
|
e.In.WriteString("multiacc\r")
|
||||||
|
e.In.WriteString("multipass\r")
|
||||||
|
e.In.WriteString("multipass\r")
|
||||||
|
e.RunWithError(t, append(cmd, hex.EncodeToString(pubs[0].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[1].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[2].Bytes()),
|
||||||
|
hex.EncodeToString(pubs[3].Bytes()))...)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -260,6 +389,13 @@ func TestWalletInit(t *testing.T) {
|
||||||
func TestWalletExport(t *testing.T) {
|
func TestWalletExport(t *testing.T) {
|
||||||
e := newExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "export")
|
||||||
|
})
|
||||||
|
t.Run("invalid address", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "export",
|
||||||
|
"--wallet", validatorWallet, "not-an-address")
|
||||||
|
})
|
||||||
t.Run("Encrypted", func(t *testing.T) {
|
t.Run("Encrypted", func(t *testing.T) {
|
||||||
e.Run(t, "neo-go", "wallet", "export",
|
e.Run(t, "neo-go", "wallet", "export",
|
||||||
"--wallet", validatorWallet, validatorAddr)
|
"--wallet", validatorWallet, validatorAddr)
|
||||||
|
@ -274,6 +410,15 @@ func TestWalletExport(t *testing.T) {
|
||||||
e.RunWithError(t, "neo-go", "wallet", "export",
|
e.RunWithError(t, "neo-go", "wallet", "export",
|
||||||
"--wallet", validatorWallet, "--decrypt")
|
"--wallet", validatorWallet, "--decrypt")
|
||||||
})
|
})
|
||||||
|
t.Run("EOF reading password", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "export",
|
||||||
|
"--wallet", validatorWallet, "--decrypt", validatorAddr)
|
||||||
|
})
|
||||||
|
t.Run("invalid password", func(t *testing.T) {
|
||||||
|
e.In.WriteString("invalid_pass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "export",
|
||||||
|
"--wallet", validatorWallet, "--decrypt", validatorAddr)
|
||||||
|
})
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "export",
|
e.Run(t, "neo-go", "wallet", "export",
|
||||||
"--wallet", validatorWallet, "--decrypt", validatorAddr)
|
"--wallet", validatorWallet, "--decrypt", validatorAddr)
|
||||||
|
@ -283,9 +428,39 @@ func TestWalletExport(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClaimGas(t *testing.T) {
|
func TestWalletClaimGas(t *testing.T) {
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
|
|
||||||
|
t.Run("missing wallet path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "claim",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--address", testWalletAccount)
|
||||||
|
})
|
||||||
|
t.Run("missing address", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "claim",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", testWalletPath)
|
||||||
|
})
|
||||||
|
t.Run("invalid address", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "claim",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", testWalletPath,
|
||||||
|
"--address", util.Uint160{}.StringLE())
|
||||||
|
})
|
||||||
|
t.Run("missing endpoint", func(t *testing.T) {
|
||||||
|
e.In.WriteString("testpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "claim",
|
||||||
|
"--wallet", testWalletPath,
|
||||||
|
"--address", testWalletAccount)
|
||||||
|
})
|
||||||
|
t.Run("insufficient funds", func(t *testing.T) {
|
||||||
|
e.In.WriteString("testpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "claim",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", testWalletPath,
|
||||||
|
"--address", testWalletAccount)
|
||||||
|
})
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"neo-go", "wallet", "nep17", "multitransfer",
|
"neo-go", "wallet", "nep17", "multitransfer",
|
||||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||||
|
@ -326,7 +501,7 @@ func TestClaimGas(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImportDeployed(t *testing.T) {
|
func TestWalletImportDeployed(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
e := newExecutor(t, true)
|
e := newExecutor(t, true)
|
||||||
h := deployVerifyContract(t, e)
|
h := deployVerifyContract(t, e)
|
||||||
|
@ -337,15 +512,43 @@ func TestImportDeployed(t *testing.T) {
|
||||||
priv, err := keys.NewPrivateKey()
|
priv, err := keys.NewPrivateKey()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// missing contract sh
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed")
|
||||||
|
})
|
||||||
|
t.Run("missing contract sh", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
|
"--wallet", walletPath)
|
||||||
|
})
|
||||||
|
t.Run("missing WIF", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
|
"--wallet", walletPath, "--contract", h.StringLE())
|
||||||
|
})
|
||||||
|
t.Run("missing endpoint", func(t *testing.T) {
|
||||||
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
|
"--wallet", walletPath, "--contract", h.StringLE(),
|
||||||
|
"--wif", priv.WIF())
|
||||||
|
})
|
||||||
|
t.Run("unknown contract", func(t *testing.T) {
|
||||||
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath, "--wif", priv.WIF())
|
"--wallet", walletPath, "--contract", util.Uint160{}.StringLE(),
|
||||||
|
"--wif", priv.WIF())
|
||||||
|
})
|
||||||
|
t.Run("no `verify` method", func(t *testing.T) {
|
||||||
|
badH := deployNNSContract(t, e) // wrong contract with no `verify` method
|
||||||
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", walletPath, "--contract", badH.StringLE(),
|
||||||
|
"--wif", priv.WIF())
|
||||||
|
})
|
||||||
|
|
||||||
e.In.WriteString("acc\rpass\rpass\r")
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
e.Run(t, "neo-go", "wallet", "import-deployed",
|
e.Run(t, "neo-go", "wallet", "import-deployed",
|
||||||
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
"--wallet", walletPath, "--wif", priv.WIF(),
|
"--wallet", walletPath, "--wif", priv.WIF(), "--name", "my_acc",
|
||||||
"--contract", h.StringLE())
|
"--contract", h.StringLE())
|
||||||
|
|
||||||
w, err := wallet.NewWalletFromFile(walletPath)
|
w, err := wallet.NewWalletFromFile(walletPath)
|
||||||
|
@ -358,6 +561,14 @@ func TestImportDeployed(t *testing.T) {
|
||||||
require.Equal(t, address.Uint160ToString(h), contractAddr)
|
require.Equal(t, address.Uint160ToString(h), contractAddr)
|
||||||
require.True(t, w.Accounts[0].Contract.Deployed)
|
require.True(t, w.Accounts[0].Contract.Deployed)
|
||||||
|
|
||||||
|
t.Run("re-importing", func(t *testing.T) {
|
||||||
|
e.In.WriteString("acc\rpass\rpass\r")
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "import-deployed",
|
||||||
|
"--rpc-endpoint", "http://"+e.RPC.Addr,
|
||||||
|
"--wallet", walletPath, "--wif", priv.WIF(), "--name", "my_acc",
|
||||||
|
"--contract", h.StringLE())
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Sign", func(t *testing.T) {
|
t.Run("Sign", func(t *testing.T) {
|
||||||
e.In.WriteString("one\r")
|
e.In.WriteString("one\r")
|
||||||
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
e.Run(t, "neo-go", "wallet", "nep17", "multitransfer",
|
||||||
|
@ -389,6 +600,9 @@ func TestImportDeployed(t *testing.T) {
|
||||||
func TestWalletDump(t *testing.T) {
|
func TestWalletDump(t *testing.T) {
|
||||||
e := newExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "dump")
|
||||||
|
})
|
||||||
cmd := []string{"neo-go", "wallet", "dump", "--wallet", testWalletPath}
|
cmd := []string{"neo-go", "wallet", "dump", "--wallet", testWalletPath}
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
rawStr := strings.TrimSpace(e.Out.String())
|
rawStr := strings.TrimSpace(e.Out.String())
|
||||||
|
@ -399,6 +613,9 @@ func TestWalletDump(t *testing.T) {
|
||||||
|
|
||||||
t.Run("with decrypt", func(t *testing.T) {
|
t.Run("with decrypt", func(t *testing.T) {
|
||||||
cmd = append(cmd, "--decrypt")
|
cmd = append(cmd, "--decrypt")
|
||||||
|
t.Run("EOF reading password", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
t.Run("invalid password", func(t *testing.T) {
|
t.Run("invalid password", func(t *testing.T) {
|
||||||
e.In.WriteString("invalidpass\r")
|
e.In.WriteString("invalidpass\r")
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
|
@ -414,8 +631,11 @@ func TestWalletDump(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDumpKeys(t *testing.T) {
|
func TestWalletDumpKeys(t *testing.T) {
|
||||||
e := newExecutor(t, false)
|
e := newExecutor(t, false)
|
||||||
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, "neo-go", "wallet", "dump-keys")
|
||||||
|
})
|
||||||
cmd := []string{"neo-go", "wallet", "dump-keys", "--wallet", validatorWallet}
|
cmd := []string{"neo-go", "wallet", "dump-keys", "--wallet", validatorWallet}
|
||||||
pubRegex := "^0[23][a-hA-H0-9]{64}$"
|
pubRegex := "^0[23][a-hA-H0-9]{64}$"
|
||||||
t.Run("all", func(t *testing.T) {
|
t.Run("all", func(t *testing.T) {
|
||||||
|
@ -432,6 +652,10 @@ func TestDumpKeys(t *testing.T) {
|
||||||
e.checkNextLine(t, pubRegex)
|
e.checkNextLine(t, pubRegex)
|
||||||
e.checkEOF(t)
|
e.checkEOF(t)
|
||||||
})
|
})
|
||||||
|
t.Run("unknown address", func(t *testing.T) {
|
||||||
|
cmd := append(cmd, "--address", util.Uint160{}.StringLE())
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
t.Run("simple signature", func(t *testing.T) {
|
t.Run("simple signature", func(t *testing.T) {
|
||||||
cmd := append(cmd, "--address", "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
|
cmd := append(cmd, "--address", "Nhfg3TbpwogLvDGVvAvqyThbsHgoSUKwtn")
|
||||||
e.Run(t, cmd...)
|
e.Run(t, cmd...)
|
||||||
|
@ -467,8 +691,16 @@ func TestWalletConvert(t *testing.T) {
|
||||||
t.Run("missing wallet", func(t *testing.T) {
|
t.Run("missing wallet", func(t *testing.T) {
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
})
|
})
|
||||||
|
cmd = append(cmd, "--wallet", "testdata/wallets/testwallet_NEO2.json")
|
||||||
|
t.Run("missing out path", func(t *testing.T) {
|
||||||
|
e.RunWithError(t, cmd...)
|
||||||
|
})
|
||||||
|
t.Run("invalid out path", func(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
e.RunWithError(t, append(cmd, "--out", dir)...)
|
||||||
|
})
|
||||||
|
|
||||||
cmd = append(cmd, "--wallet", "testdata/wallets/testwallet_NEO2.json", "--out", outPath)
|
cmd = append(cmd, "--out", outPath)
|
||||||
t.Run("invalid password", func(t *testing.T) {
|
t.Run("invalid password", func(t *testing.T) {
|
||||||
// missing password
|
// missing password
|
||||||
e.RunWithError(t, cmd...)
|
e.RunWithError(t, cmd...)
|
||||||
|
|
11
codecov.yml
Normal file
11
codecov.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
codecov:
|
||||||
|
require_ci_to_pass: no # We have several CI jobs that upload codecov results,
|
||||||
|
# and sometimes some of them may fail, it's OK.
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default: # This can be anything, but it needs to exist as the name
|
||||||
|
if_ci_failed: error #success, failure, error, ignore
|
||||||
|
only_pulls: false
|
||||||
|
comment:
|
||||||
|
after_n_builds: 1
|
Loading…
Reference in a new issue