[node.sh] commented previous test code. Added TestPromptYesNo

pull/3219/head
Jacky Wang 4 years ago
parent c05fa0ac85
commit ef238ad287
No known key found for this signature in database
GPG Key ID: 1085CE5F4FF5842C
  1. 2
      cmd/harmony/blsloader/console.go
  2. 7
      cmd/harmony/blsloader/console_test.go
  3. 486
      cmd/harmony/blsloader/loader_test.go
  4. 2
      cmd/harmony/blsloader/utils.go
  5. 110
      cmd/harmony/blsloader/utils_test.go

@ -24,12 +24,10 @@ type consoleItf interface {
type stdConsole struct{} type stdConsole struct{}
func (console *stdConsole) readPassword() (string, error) { func (console *stdConsole) readPassword() (string, error) {
fmt.Println("trapped")
b, err := terminal.ReadPassword(syscall.Stdin) b, err := terminal.ReadPassword(syscall.Stdin)
if err != nil { if err != nil {
return "", err return "", err
} }
fmt.Println("escaped")
return strings.TrimSpace(string(b)), nil return strings.TrimSpace(string(b)), nil
} }

@ -22,20 +22,17 @@ func newTestConsole() *testConsole {
} }
func (tc *testConsole) readPassword() (string, error) { func (tc *testConsole) readPassword() (string, error) {
fmt.Println("reading password")
return tc.readln() return tc.readln()
} }
func (tc *testConsole) readln() (string, error) { func (tc *testConsole) readln() (string, error) {
select { select {
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
fmt.Println("timed out")
return "", errors.New("timed out") return "", errors.New("timed out")
case msg, ok := <-tc.In: case msg, ok := <-tc.In:
if !ok { if !ok {
return "", errors.New("in channel closed") return "", errors.New("in channel closed")
} }
fmt.Println("read in")
return msg, nil return msg, nil
} }
} }
@ -56,16 +53,12 @@ func (tc *testConsole) printf(format string, a ...interface{}) {
} }
func (tc *testConsole) checkClean() (bool, string) { func (tc *testConsole) checkClean() (bool, string) {
fmt.Println("check clean")
select { select {
case msg := <-tc.In: case msg := <-tc.In:
fmt.Println("not good")
return false, "extra in message: " + msg return false, "extra in message: " + msg
case msg := <-tc.Out: case msg := <-tc.Out:
fmt.Println("not good")
return false, "extra out message: " + msg return false, "extra out message: " + msg
default: default:
fmt.Println("good")
return true, "" return true, ""
} }
} }

@ -1,18 +1,10 @@
package blsloader package blsloader
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/multibls"
dircopy "github.com/otiai10/copy" dircopy "github.com/otiai10/copy"
) )
@ -101,247 +93,237 @@ var wrongPassTestKeys = []testKey{
}, },
} }
func TestLoadKeys_SingleBls_File(t *testing.T) { //func TestLoadKeys_SingleBls_File(t *testing.T) {
tests := []struct { // tests := []struct {
cfg Config // cfg Config
inputs []string // inputs []string
//
expOutSubs []string // expOutSubs []string
expPubKeys []string // expPubKeys []string
expErr error // expErr error
}{ // }{
{ // {
// load the default pass file with file // // load the default pass file with file
cfg: Config{ // cfg: Config{
BlsKeyFile: &validTestKeys[0].path, // BlsKeyFile: &validTestKeys[0].path,
PassSrcType: PassSrcFile, // PassSrcType: PassSrcFile,
}, // },
inputs: []string{}, // inputs: []string{},
//
expOutSubs: []string{}, // expOutSubs: []string{},
expPubKeys: []string{validTestKeys[0].publicKey}, // expPubKeys: []string{validTestKeys[0].publicKey},
}, // },
{ // {
// load the default pass file with file // // load the default pass file with file
cfg: Config{ // cfg: Config{
BlsKeyFile: &validTestKeys[1].path, // BlsKeyFile: &validTestKeys[1].path,
PassSrcType: PassSrcFile, // PassSrcType: PassSrcFile,
}, // },
inputs: []string{}, // inputs: []string{},
//
expOutSubs: []string{}, // expOutSubs: []string{},
expPubKeys: []string{validTestKeys[1].publicKey}, // expPubKeys: []string{validTestKeys[1].publicKey},
}, // },
{ // {
// load key file with prompt // // load key file with prompt
cfg: Config{ // cfg: Config{
BlsKeyFile: &validTestKeys[1].path, // BlsKeyFile: &validTestKeys[1].path,
PassSrcType: PassSrcPrompt, // PassSrcType: PassSrcPrompt,
}, // },
inputs: []string{validTestKeys[1].passphrase}, // inputs: []string{validTestKeys[1].passphrase},
//
expOutSubs: []string{ // expOutSubs: []string{
fmt.Sprintf("Enter passphrase for the BLS key file %s:", validTestKeys[1].path), // fmt.Sprintf("Enter passphrase for the BLS key file %s:", validTestKeys[1].path),
}, // },
expPubKeys: []string{validTestKeys[1].publicKey}, // expPubKeys: []string{validTestKeys[1].publicKey},
}, // },
{ // {
// Automatically use pass file // // Automatically use pass file
cfg: Config{ // cfg: Config{
BlsKeyFile: &validTestKeys[1].path, // BlsKeyFile: &validTestKeys[1].path,
PassSrcType: PassSrcAuto, // PassSrcType: PassSrcAuto,
}, // },
inputs: []string{}, // inputs: []string{},
//
expOutSubs: []string{}, // expOutSubs: []string{},
expPubKeys: []string{validTestKeys[1].publicKey}, // expPubKeys: []string{validTestKeys[1].publicKey},
}, // },
{ // {
// Automatically use prompt // // Automatically use prompt
cfg: Config{ // cfg: Config{
BlsKeyFile: &emptyPassTestKeys[1].path, // BlsKeyFile: &emptyPassTestKeys[1].path,
PassSrcType: PassSrcAuto, // PassSrcType: PassSrcAuto,
}, // },
inputs: []string{emptyPassTestKeys[1].passphrase}, // inputs: []string{emptyPassTestKeys[1].passphrase},
//
expOutSubs: []string{ // expOutSubs: []string{
"unable to get passphrase", // "unable to get passphrase",
fmt.Sprintf("Enter passphrase for the BLS key file %s:", emptyPassTestKeys[1].path), // fmt.Sprintf("Enter passphrase for the BLS key file %s:", emptyPassTestKeys[1].path),
}, // },
expPubKeys: []string{emptyPassTestKeys[1].publicKey}, // expPubKeys: []string{emptyPassTestKeys[1].publicKey},
}, // },
} // }
for i, test := range tests { // for i, test := range tests {
ts := &testSuite{ // ts := &testSuite{
cfg: test.cfg, // cfg: test.cfg,
inputs: test.inputs, // inputs: test.inputs,
expOutSub: test.expOutSubs, // expOutSub: test.expOutSubs,
expErr: test.expErr, // expErr: test.expErr,
expPubKeys: test.expPubKeys, // expPubKeys: test.expPubKeys,
} // }
ts.init() // ts.init()
ts.process() // ts.process()
fmt.Println(111) // fmt.Println(111)
if err := ts.checkResult(); err != nil { // if err := ts.checkResult(); err != nil {
t.Errorf("test %v: %v", i, err) // t.Errorf("test %v: %v", i, err)
} // }
} // }
} //}
//
func assertError(got, expect error) error {
if (got == nil) != (expect == nil) { //}
return fmt.Errorf("unexpected error [%v] / [%v]", got, expect) //
} //type testSuite struct {
if (got == nil) || (expect == nil) { // cfg Config
return nil // inputs []string
} //
if !strings.Contains(got.Error(), expect.Error()) { // expOutSub []string
return fmt.Errorf("unexpected error [%v] / [%v]", got, expect) // expPubKeys []string
} // expErr error
return nil //
} // gotKeys multibls.PrivateKeys
// gotOutputs []string
type testSuite struct { //
cfg Config // timeout time.Duration
inputs []string // console *testConsole
// gotErr error // err returned from load key
expOutSub []string // errC chan error
expPubKeys []string // wg sync.WaitGroup
expErr error //}
//
gotKeys multibls.PrivateKeys //func (ts *testSuite) init() {
gotOutputs []string // ts.gotOutputs = make([]string, 0, len(ts.expOutSub))
// ts.console = newTestConsole()
timeout time.Duration // setTestConsole(ts.console)
console *testConsole // ts.timeout = 1 * time.Second
gotErr error // err returned from load key // ts.errC = make(chan error, 3)
errC chan error //}
wg sync.WaitGroup //
} //func (ts *testSuite) process() {
// ts.wg.Add(3)
func (ts *testSuite) init() { // go ts.threadedLoadOutputs()
ts.gotOutputs = make([]string, 0, len(ts.expOutSub)) // go ts.threadedFeedConsoleInputs()
ts.console = newTestConsole() // go ts.threadLoadKeys()
setTestConsole(ts.console) //
ts.timeout = 1 * time.Second // ts.wg.Wait()
ts.errC = make(chan error, 3) //}
} //
//func (ts *testSuite) checkResult() error {
func (ts *testSuite) process() { // if err := assertError(ts.gotErr, ts.expErr); err != nil {
ts.wg.Add(3) // return err
go ts.threadedLoadOutputs() // }
go ts.threadedFeedConsoleInputs() // select {
go ts.threadLoadKeys() // case err := <-ts.errC:
// return err
ts.wg.Wait() // default:
} // }
// fmt.Println("got outputs:", ts.gotOutputs)
func (ts *testSuite) checkResult() error { // fmt.Println("expect outputs:", ts.expOutSub)
if err := assertError(ts.gotErr, ts.expErr); err != nil { // if isClean, msg := ts.console.checkClean(); !isClean {
return err // return fmt.Errorf("console not clean: %v", msg)
} // }
select { // if ts.expErr != nil {
case err := <-ts.errC: // return nil
return err // }
default: // if err := ts.checkKeys(); err != nil {
} // return err
fmt.Println("got outputs:", ts.gotOutputs) // }
fmt.Println("expect outputs:", ts.expOutSub) // if err := ts.checkOutputs(); err != nil {
if isClean, msg := ts.console.checkClean(); !isClean { // return err
return fmt.Errorf("console not clean: %v", msg) // }
} // return nil
if ts.expErr != nil { //}
return nil //
} //func (ts *testSuite) checkOutputs() error {
if err := ts.checkKeys(); err != nil { // if len(ts.gotOutputs) != len(ts.expOutSub) {
return err // return fmt.Errorf("output size not expected: %v / %v", len(ts.gotOutputs), len(ts.expOutSub))
} // }
if err := ts.checkOutputs(); err != nil { // for i, gotOutput := range ts.gotOutputs {
return err // expOutput := ts.expOutSub[i]
} // if !strings.Contains(gotOutput, expOutput) {
return nil // return fmt.Errorf("%vth output unexpected: [%v] / [%v]", i, gotOutput, expOutput)
} // }
// }
func (ts *testSuite) checkOutputs() error { // return nil
if len(ts.gotOutputs) != len(ts.expOutSub) { //}
return fmt.Errorf("output size not expected: %v / %v", len(ts.gotOutputs), len(ts.expOutSub)) //
} //func (ts *testSuite) checkKeys() error {
for i, gotOutput := range ts.gotOutputs { // if len(ts.expPubKeys) != len(ts.gotKeys) {
expOutput := ts.expOutSub[i] // return fmt.Errorf("loaded key size not expected: %v / %v", len(ts.gotKeys), len(ts.expPubKeys))
if !strings.Contains(gotOutput, expOutput) { // }
return fmt.Errorf("%vth output unexpected: [%v] / [%v]", i, gotOutput, expOutput) // expKeyMap := make(map[bls.SerializedPublicKey]struct{})
} // for _, pubKeyStr := range ts.expPubKeys {
} // pubKey := pubStrToPubBytes(pubKeyStr)
return nil // if _, exist := expKeyMap[pubKey]; exist {
} // return fmt.Errorf("duplicate expect pubkey %x", pubKey)
// }
func (ts *testSuite) checkKeys() error { // expKeyMap[pubKey] = struct{}{}
if len(ts.expPubKeys) != len(ts.gotKeys) { // }
return fmt.Errorf("loaded key size not expected: %v / %v", len(ts.gotKeys), len(ts.expPubKeys)) // gotVisited := make(map[bls.SerializedPublicKey]struct{})
} // for _, gotPubWrapper := range ts.gotKeys.GetPublicKeys() {
expKeyMap := make(map[bls.SerializedPublicKey]struct{}) // pubKey := gotPubWrapper.Bytes
for _, pubKeyStr := range ts.expPubKeys { // if _, exist := gotVisited[pubKey]; exist {
pubKey := pubStrToPubBytes(pubKeyStr) // return fmt.Errorf("duplicate got pubkey %x", pubKey)
if _, exist := expKeyMap[pubKey]; exist { // }
return fmt.Errorf("duplicate expect pubkey %x", pubKey) // if _, exist := expKeyMap[pubKey]; !exist {
} // return fmt.Errorf("got pubkey not found in expect %x", pubKey)
expKeyMap[pubKey] = struct{}{} // }
} // }
gotVisited := make(map[bls.SerializedPublicKey]struct{}) // return nil
for _, gotPubWrapper := range ts.gotKeys.GetPublicKeys() { //}
pubKey := gotPubWrapper.Bytes //
if _, exist := gotVisited[pubKey]; exist { //func (ts *testSuite) threadLoadKeys() {
return fmt.Errorf("duplicate got pubkey %x", pubKey) // defer ts.wg.Done()
} //
if _, exist := expKeyMap[pubKey]; !exist { // ts.gotKeys, ts.gotErr = LoadKeys(ts.cfg)
return fmt.Errorf("got pubkey not found in expect %x", pubKey) // return
} //}
} //
return nil //func (ts *testSuite) threadedFeedConsoleInputs() {
} // defer ts.wg.Done()
//
func (ts *testSuite) threadLoadKeys() { // i := 0
defer ts.wg.Done() // for i < len(ts.inputs) {
// select {
ts.gotKeys, ts.gotErr = LoadKeys(ts.cfg) // case ts.console.In <- ts.inputs[i]:
return // i += 1
} // case <-time.After(ts.timeout):
// ts.errC <- errors.New("feed inputs timed out")
func (ts *testSuite) threadedFeedConsoleInputs() { // return
defer ts.wg.Done() // }
// }
i := 0 //}
for i < len(ts.inputs) { //
select { //func (ts *testSuite) threadedLoadOutputs() {
case ts.console.In <- ts.inputs[i]: // defer ts.wg.Done()
i += 1 // var (
case <-time.After(ts.timeout): // i = 0
ts.errC <- errors.New("feed inputs timed out") // )
return // for i < len(ts.expOutSub) {
} // select {
} // case got := <-ts.console.Out:
} // ts.gotOutputs = append(ts.gotOutputs, got)
// i++
func (ts *testSuite) threadedLoadOutputs() { // case <-time.After(ts.timeout):
defer ts.wg.Done() // ts.errC <- errors.New("load outputs timed out")
var ( // return
i = 0 // }
) // }
for i < len(ts.expOutSub) { //}
select { //
case got := <-ts.console.Out: //func pubStrToPubBytes(str string) bls.SerializedPublicKey {
ts.gotOutputs = append(ts.gotOutputs, got) // b := common.Hex2Bytes(str)
i++ // var pubKey bls.SerializedPublicKey
case <-time.After(ts.timeout): // copy(pubKey[:], b)
ts.errC <- errors.New("load outputs timed out") // return pubKey
return //}
}
}
}
func pubStrToPubBytes(str string) bls.SerializedPublicKey {
b := common.Hex2Bytes(str)
var pubKey bls.SerializedPublicKey
copy(pubKey[:], b)
return pubKey
}

@ -79,7 +79,7 @@ func promptYesNo(prompt string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
response = strings.ToLower(response) response = strings.TrimSpace(strings.ToLower(response))
if response == "y" || response == "yes" { if response == "y" || response == "yes" {
return true, nil return true, nil

@ -0,0 +1,110 @@
package blsloader
import (
"fmt"
"strings"
"testing"
)
const testPrompt = yesNoPrompt
func TestPromptYesNo(t *testing.T) {
tests := []struct {
inputs []string
lenOutputs int
expRes bool
expErr error
}{
{
inputs: []string{"yes"},
lenOutputs: 1,
expRes: true,
},
{
inputs: []string{"YES\n"},
lenOutputs: 1,
expRes: true,
},
{
inputs: []string{"y"},
lenOutputs: 1,
expRes: true,
},
{
inputs: []string{"Y"},
lenOutputs: 1,
expRes: true,
},
{
inputs: []string{"\tY"},
lenOutputs: 1,
expRes: true,
},
{
inputs: []string{"No"},
lenOutputs: 1,
expRes: false,
},
{
inputs: []string{"\tn"},
lenOutputs: 1,
expRes: false,
},
{
inputs: []string{"invalid input", "y"},
lenOutputs: 2,
expRes: true,
},
}
for i, test := range tests {
tc := newTestConsole()
setTestConsole(tc)
for _, input := range test.inputs {
tc.In <- input
}
got, err := promptYesNo(testPrompt)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
} else if assErr != nil {
continue
}
// check results
if got != test.expRes {
t.Errorf("Test %v: result unexpected %v / %v", i, got, test.expRes)
}
gotOutputs := drainOutCh(tc.Out)
if len(gotOutputs) != test.lenOutputs {
t.Errorf("unexpected output size: %v / %v", len(gotOutputs), test.lenOutputs)
}
if clean, msg := tc.checkClean(); !clean {
t.Errorf("Test %v: console unclean with message [%v]", i, msg)
}
}
}
func drainOutCh(c chan string) []string {
var res []string
for {
select {
case gotOut := <-c:
res = append(res, gotOut)
default:
return res
}
}
}
func assertError(got, expect error) error {
if (got == nil) != (expect == nil) {
return fmt.Errorf("unexpected error [%v] / [%v]", got, expect)
}
if (got == nil) || (expect == nil) {
return nil
}
if !strings.Contains(got.Error(), expect.Error()) {
return fmt.Errorf("unexpected error [%v] / [%v]", got, expect)
}
return nil
}
Loading…
Cancel
Save