diff --git a/command/key_status.go b/command/key_status.go index ff1b0860c..b870035b7 100644 --- a/command/key_status.go +++ b/command/key_status.go @@ -4,38 +4,17 @@ import ( "fmt" "strings" - "github.com/hashicorp/vault/meta" + "github.com/mitchellh/cli" + "github.com/posener/complete" ) +// Ensure we are implementing the right interfaces. +var _ cli.Command = (*KeyStatusCommand)(nil) +var _ cli.CommandAutocomplete = (*KeyStatusCommand)(nil) + // KeyStatusCommand is a Command that provides information about the key status type KeyStatusCommand struct { - meta.Meta -} - -func (c *KeyStatusCommand) Run(args []string) int { - flags := c.Meta.FlagSet("key-status", meta.FlagSetDefault) - flags.Usage = func() { c.Ui.Error(c.Help()) } - if err := flags.Parse(args); err != nil { - return 1 - } - - client, err := c.Client() - if err != nil { - c.Ui.Error(fmt.Sprintf( - "Error initializing client: %s", err)) - return 2 - } - - status, err := client.Sys().KeyStatus() - if err != nil { - c.Ui.Error(fmt.Sprintf( - "Error reading audits: %s", err)) - return 2 - } - - c.Ui.Output(fmt.Sprintf("Key Term: %d", status.Term)) - c.Ui.Output(fmt.Sprintf("Installation Time: %v", status.InstallTime)) - return 0 + *BaseCommand } func (c *KeyStatusCommand) Synopsis() string { @@ -49,7 +28,49 @@ Usage: vault key-status [options] Provides information about the active encryption key. Specifically, the current key term and the key installation time. -General Options: -` + meta.GeneralOptionsUsage() +` + c.Flags().Help() + return strings.TrimSpace(helpText) } + +func (c *KeyStatusCommand) Flags() *FlagSets { + return c.flagSet(FlagSetHTTP) +} + +func (c *KeyStatusCommand) AutocompleteArgs() complete.Predictor { + return nil +} + +func (c *KeyStatusCommand) AutocompleteFlags() complete.Flags { + return c.Flags().Completions() +} + +func (c *KeyStatusCommand) Run(args []string) int { + f := c.Flags() + + if err := f.Parse(args); err != nil { + c.UI.Error(err.Error()) + return 1 + } + + args = f.Args() + if len(args) > 0 { + c.UI.Error(fmt.Sprintf("Too many arguments (expected 0, got %d)", len(args))) + return 1 + } + + client, err := c.Client() + if err != nil { + c.UI.Error(err.Error()) + return 2 + } + + status, err := client.Sys().KeyStatus() + if err != nil { + c.UI.Error(fmt.Sprintf("Error reading key status: %s", err)) + return 2 + } + + c.UI.Output(printKeyStatus(status)) + return 0 +} diff --git a/command/key_status_test.go b/command/key_status_test.go index 0adcefa7f..640cef7bb 100644 --- a/command/key_status_test.go +++ b/command/key_status_test.go @@ -1,31 +1,110 @@ package command import ( + "strings" "testing" - "github.com/hashicorp/vault/http" - "github.com/hashicorp/vault/meta" - "github.com/hashicorp/vault/vault" "github.com/mitchellh/cli" ) -func TestKeyStatus(t *testing.T) { - core, _, token := vault.TestCoreUnsealed(t) - ln, addr := http.TestServer(t, core) - defer ln.Close() +func testKeyStatusCommand(tb testing.TB) (*cli.MockUi, *KeyStatusCommand) { + tb.Helper() - ui := new(cli.MockUi) - c := &KeyStatusCommand{ - Meta: meta.Meta{ - ClientToken: token, - Ui: ui, + ui := cli.NewMockUi() + return ui, &KeyStatusCommand{ + BaseCommand: &BaseCommand{ + UI: ui, + }, + } +} + +func TestKeyStatusCommand_Run(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + args []string + out string + code int + }{ + { + "too_many_args", + []string{"foo", "bar"}, + "Too many arguments", + 1, }, } - args := []string{ - "-address", addr, - } - if code := c.Run(args); code != 0 { - t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) - } + t.Run("validations", func(t *testing.T) { + t.Parallel() + + for _, tc := range cases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + ui, cmd := testKeyStatusCommand(t) + + code := cmd.Run(tc.args) + if code != tc.code { + t.Errorf("expected %d to be %d", code, tc.code) + } + + combined := ui.OutputWriter.String() + ui.ErrorWriter.String() + if !strings.Contains(combined, tc.out) { + t.Errorf("expected %q to contain %q", combined, tc.out) + } + }) + } + }) + + t.Run("integration", func(t *testing.T) { + t.Parallel() + + client, closer := testVaultServer(t) + defer closer() + + ui, cmd := testKeyStatusCommand(t) + cmd.client = client + + code := cmd.Run([]string{}) + if exp := 0; code != exp { + t.Errorf("expected %d to be %d", code, exp) + } + + expected := "Key Term" + combined := ui.OutputWriter.String() + ui.ErrorWriter.String() + if !strings.Contains(combined, expected) { + t.Errorf("expected %q to contain %q", combined, expected) + } + }) + + t.Run("communication_failure", func(t *testing.T) { + t.Parallel() + + client, closer := testVaultServerBad(t) + defer closer() + + ui, cmd := testKeyStatusCommand(t) + cmd.client = client + + code := cmd.Run([]string{}) + if exp := 2; code != exp { + t.Errorf("expected %d to be %d", code, exp) + } + + expected := "Error reading key status: " + combined := ui.OutputWriter.String() + ui.ErrorWriter.String() + if !strings.Contains(combined, expected) { + t.Errorf("expected %q to contain %q", combined, expected) + } + }) + + t.Run("no_tabs", func(t *testing.T) { + t.Parallel() + + _, cmd := testKeyStatusCommand(t) + assertNoTabs(t, cmd) + }) }