fix(cli): tighten chain command validation
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
41f2d52979
commit
d6f31dbe57
4 changed files with 91 additions and 0 deletions
|
|
@ -6,6 +6,8 @@
|
|||
package blockchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
|
|
@ -75,3 +77,16 @@ func ensureChainDataDirExists(dataDir string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateChainOptions(dataDir, seed string) error {
|
||||
if dataDir == "" {
|
||||
return coreerr.E("validateChainOptions", "data dir is required", nil)
|
||||
}
|
||||
if seed == "" {
|
||||
return coreerr.E("validateChainOptions", "seed is required", nil)
|
||||
}
|
||||
if _, _, err := net.SplitHostPort(seed); err != nil {
|
||||
return coreerr.E("validateChainOptions", fmt.Sprintf("seed %q must be host:port", seed), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,3 +46,68 @@ func TestAddChainCommands_Good_PersistentFlags(t *testing.T) {
|
|||
assert.NotNil(t, chainCmd.PersistentFlags().Lookup("seed"))
|
||||
assert.NotNil(t, chainCmd.PersistentFlags().Lookup("testnet"))
|
||||
}
|
||||
|
||||
func TestValidateChainOptions_Good(t *testing.T) {
|
||||
err := validateChainOptions("/tmp/lethean", "seed.example:36942")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestValidateChainOptions_Bad(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
dataDir string
|
||||
seed string
|
||||
want string
|
||||
}{
|
||||
{name: "missing data dir", dataDir: "", seed: "seed.example:36942", want: "data dir is required"},
|
||||
{name: "missing seed", dataDir: "/tmp/lethean", seed: "", want: "seed is required"},
|
||||
{name: "malformed seed", dataDir: "/tmp/lethean", seed: "seed.example", want: "must be host:port"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateChainOptions(tt.dataDir, tt.seed)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainSyncCommand_BadMutuallyExclusiveFlags(t *testing.T) {
|
||||
dataDir := t.TempDir()
|
||||
seed := "seed.example:36942"
|
||||
testnet := false
|
||||
|
||||
cmd := newChainSyncCommand(&dataDir, &seed, &testnet)
|
||||
cmd.SetArgs([]string{"--daemon", "--stop"})
|
||||
|
||||
err := cmd.Execute()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "cannot be combined")
|
||||
}
|
||||
|
||||
func TestChainSyncCommand_BadArgsRejected(t *testing.T) {
|
||||
dataDir := t.TempDir()
|
||||
seed := "seed.example:36942"
|
||||
testnet := false
|
||||
|
||||
cmd := newChainSyncCommand(&dataDir, &seed, &testnet)
|
||||
cmd.SetArgs([]string{"extra"})
|
||||
|
||||
err := cmd.Execute()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "unknown command")
|
||||
}
|
||||
|
||||
func TestChainExplorerCommand_BadSeedRejected(t *testing.T) {
|
||||
dataDir := t.TempDir()
|
||||
seed := "bad-seed"
|
||||
testnet := false
|
||||
|
||||
cmd := newChainExplorerCommand(&dataDir, &seed, &testnet)
|
||||
cmd.SetArgs(nil)
|
||||
|
||||
err := cmd.Execute()
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "must be host:port")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ func newChainExplorerCommand(dataDir, seed *string, testnet *bool) *cobra.Comman
|
|||
Use: "explorer",
|
||||
Short: "TUI block explorer",
|
||||
Long: "Interactive terminal block explorer with live sync status.",
|
||||
Args: cobra.NoArgs,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
return validateChainOptions(*dataDir, *seed)
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return runChainExplorer(*dataDir, *seed, *testnet)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -42,6 +42,13 @@ func newChainSyncCommand(dataDir, seed *string, testnet *bool) *cobra.Command {
|
|||
Use: "sync",
|
||||
Short: "Headless P2P chain sync",
|
||||
Long: "Sync the blockchain from P2P peers without the TUI explorer.",
|
||||
Args: cobra.NoArgs,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if daemon && stop {
|
||||
return coreerr.E("newChainSyncCommand", "flags --daemon and --stop cannot be combined", nil)
|
||||
}
|
||||
return validateChainOptions(*dataDir, *seed)
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if stop {
|
||||
return stopChainSyncDaemon(*dataDir)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue