Skip to content

Commit

Permalink
add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
torao committed May 20, 2022
1 parent 5ec9fa7 commit 080b18a
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 1 deletion.
4 changes: 4 additions & 0 deletions cmd/ostracon/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ func initFilesWithConfig(config *cfg.Config) error {
logger.Info("Found genesis file", "path", genFile)
} else {
genDoc := types.GenesisDoc{
// FIXME: It shouldn't be generated automatically, and the config and genDoc chainIDs should be the same.
// However, the chainID generated by DefaultConfig() in init subcommand is an empty string.
// Should we generate random chainIDs in DefaultConfig? Or, should chainID be removed from Config?
// Note that the Config.chainID field is private and cannot be changed (read only) from here.
ChainID: fmt.Sprintf("test-chain-%v", tmrand.Str(6)),
GenesisTime: tmtime.Now(),
ConsensusParams: types.DefaultConsensusParams(),
Expand Down
57 changes: 57 additions & 0 deletions cmd/ostracon/commands/kms_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package commands

import (
"fmt"
"net"
"path"
"testing"
"time"

"github.com/line/ostracon/crypto"
"github.com/line/ostracon/crypto/ed25519"
"github.com/line/ostracon/privval"
)

func WithMockKMS(t *testing.T, dir, chainID string, f func(string, crypto.PrivKey)) {
// This process is based on cmd/priv_validator_server/main.go

// obtain an address using a vacancy port number
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
return
}
addr := listener.Addr().String()
if err = listener.Close(); err != nil {
t.Fatal(err)
return
}

// start mock kms server
privKey := ed25519.GenPrivKeyFromSecret([]byte("🏺"))
shutdown := make(chan string)
go func() {
logger.Info(fmt.Sprintf("MockKMS starting: [%s] %s", chainID, addr))
pv := privval.NewFilePV(privKey, path.Join(dir, "keyfile"), path.Join(dir, "statefile"))
connTimeout := 5 * time.Second
dialer := privval.DialTCPFn(addr, connTimeout, ed25519.GenPrivKeyFromSecret([]byte("🔌")))
sd := privval.NewSignerDialerEndpoint(logger, dialer)
ss := privval.NewSignerServer(sd, chainID, pv)
err := ss.Start()
if err != nil {
panic(err)
}
logger.Info("MockKMS started")
<-shutdown
logger.Info("MockKMS stopping")
if err = ss.Stop(); err != nil {
panic(err)
}
logger.Info("MockKMS stopped")
}()
defer func() {
shutdown <- "SHUTDOWN"
}()

f(addr, privKey)
}
3 changes: 2 additions & 1 deletion cmd/ostracon/commands/reset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ import (
"github.com/line/ostracon/privval"
)

func setupEnv(t *testing.T) {
func setupEnv(t *testing.T) string {
rootDir := t.TempDir()
viper.SetEnvPrefix("OC")
require.NoError(t, viper.BindEnv("HOME"))
require.NoError(t, os.Setenv("OC_HOME", rootDir))
return rootDir
}

func TestResetAllCmd(t *testing.T) {
Expand Down
77 changes: 77 additions & 0 deletions cmd/ostracon/commands/run_node_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package commands

import (
cfg "github.com/line/ostracon/config"
"testing"

"github.com/line/ostracon/crypto"
nm "github.com/line/ostracon/node"
"github.com/line/ostracon/types"
"github.com/stretchr/testify/require"
)

// RunCmd.RunE can only be stopped by a signal for process. For this reason, NewOstraconNode() is called directly
// to test.
func TestNewOstraconNode(t *testing.T) {
original := config
defer func() {
config = original
}()

// setup environment
setupEnv(t)
config = cfg.TestConfig()
err := RootCmd.PersistentPreRunE(RootCmd, nil)
require.NoError(t, err)
init := NewInitCmd()
err = init.RunE(init, nil)
require.NoError(t, err)

// start node
config.ProxyApp = "noop"
node, err := nm.NewOstraconNode(config, logger)
require.NoError(t, err)

// verify the retrieved public key matches the local public key
expected := loadFilePVKey(t, config.PrivValidatorKeyFile()).PubKey
actual, err := node.PrivValidator().GetPubKey()
require.NoError(t, err)
require.Equal(t, expected, actual)
}

func TestNewOstraconNodeWithKMS(t *testing.T) {
original := config
defer func() {
config = original
}()

// setup environment
dir := setupEnv(t)
config = cfg.TestConfig()
err := RootCmd.PersistentPreRunE(RootCmd, nil)
require.NoError(t, err)
config.SetRoot(dir)
cfg.EnsureRoot(dir)
err = initFilesWithConfig(config)
require.NoError(t, err)

// retrieve chainID
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
require.NoError(t, err)
chainID := genDoc.ChainID

WithMockKMS(t, dir, chainID, func(addr string, privKey crypto.PrivKey) {

// start node
config.ProxyApp = "noop"
config.PrivValidatorListenAddr = addr
node, err := nm.NewOstraconNode(config, logger)
require.NoError(t, err, addr)

// verify the retrieved public key matches the remote public key
expected := privKey.PubKey()
actual, err := node.PrivValidator().GetPubKey()
require.NoError(t, err)
require.Equal(t, expected, actual)
})
}
100 changes: 100 additions & 0 deletions cmd/ostracon/commands/show_validator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package commands

import (
"bytes"
"io/ioutil"
"os"
"testing"

cfg "github.com/line/ostracon/config"
"github.com/line/ostracon/crypto"
tmjson "github.com/line/ostracon/libs/json"
tmos "github.com/line/ostracon/libs/os"
"github.com/line/ostracon/privval"
"github.com/stretchr/testify/require"
)

func TestShowValidator(t *testing.T) {
original := config
defer func() {
config = original
}()

setupEnv(t)
config = cfg.DefaultConfig()
err := RootCmd.PersistentPreRunE(RootCmd, nil)
require.NoError(t, err)
init := NewInitCmd()
err = init.RunE(init, nil)
require.NoError(t, err)
output, err := captureStdout(func() {
err = ShowValidatorCmd.RunE(ShowValidatorCmd, nil)
require.NoError(t, err)
})
require.NoError(t, err)

// output must match the locally stored priv_validator key
privKey := loadFilePVKey(t, config.PrivValidatorKeyFile())
bz, err := tmjson.Marshal(privKey.PubKey)
require.NoError(t, err)
require.Equal(t, string(bz), output)
}

func TestShowValidatorWithKMS(t *testing.T) {
original := config
defer func() {
config = original
}()

dir := setupEnv(t)
config = cfg.DefaultConfig()
if tmos.FileExists(config.PrivValidatorKeyFile()) {
err := os.Remove(config.PrivValidatorKeyFile())
require.NoError(t, err)
}
WithMockKMS(t, dir, config.ChainID(), func(addr string, privKey crypto.PrivKey) {
config.PrivValidatorListenAddr = addr
require.NoFileExists(t, config.PrivValidatorKeyFile())
output, err := captureStdout(func() {
err := ShowValidatorCmd.RunE(ShowValidatorCmd, nil)
require.NoError(t, err)
})
require.NoError(t, err)

// output must match the KMS public key
bz, err := tmjson.Marshal(privKey.PubKey())
require.NoError(t, err)
require.Equal(t, string(bz), output)
})
}

func loadFilePVKey(t *testing.T, file string) privval.FilePVKey {
// output must match the locally stored priv_validator key
keyJSONBytes, err := ioutil.ReadFile(file)
require.NoError(t, err)
privKey := privval.FilePVKey{}
err = tmjson.Unmarshal(keyJSONBytes, &privKey)
require.NoError(t, err)
return privKey
}

func captureStdout(f func()) (string, error) {
original := os.Stdout
defer func() {
os.Stdout = original
}()

r, w, err := os.Pipe()
if err != nil {
return "", err
}
os.Stdout = w
f()
_ = w.Close()
var buffer bytes.Buffer
if _, err := buffer.ReadFrom(r); err != nil {
return "", err
}
output := buffer.String()
return output[:len(output)-1], nil
}

0 comments on commit 080b18a

Please sign in to comment.