Skip to content

Commit 7ac5c39

Browse files
author
Andrew Mason
authored
Fix vtctldclient's Root command to return an error on unknown command (vitessio#12481) (vitessio#12531)
* Add a Run func to `vtctldclient`'s Root command to return an error on unknown command Closes vitessio#12480. * Add test * flags test data --------- Signed-off-by: Andrew Mason <andrew@planetscale.com>
1 parent 5701a05 commit 7ac5c39

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

go/cmd/vtctldclient/command/root.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package command
1919
import (
2020
"context"
2121
"errors"
22+
"fmt"
2223
"io"
2324
"time"
2425

@@ -82,6 +83,26 @@ var (
8283
// propagated).
8384
SilenceErrors: true,
8485
Version: servenv.AppVersion.String(),
86+
// If we've reached this function, it means that:
87+
//
88+
// (1) The user specified some positional arguments, which, for the way
89+
// we've structured things can only be a subcommand name, **and**
90+
//
91+
// (2) Cobra was unable to find a subcommand with that name for which to
92+
// call a Run or RunE function.
93+
//
94+
// From this we conclude that the user was trying to either run a
95+
// command that doesn't exist (e.g. "vtctldclient delete-my-data") or
96+
// has misspelled a legitimate command (e.g. "vtctldclient StapReplication").
97+
// If we think this has happened, return an error, which will get
98+
// displayed to the user in main.go along with the usage.
99+
RunE: func(cmd *cobra.Command, args []string) error {
100+
if cmd.Flags().NArg() > 0 {
101+
return fmt.Errorf("unknown command: %s", cmd.Flags().Arg(0))
102+
}
103+
104+
return nil
105+
},
85106
}
86107
)
87108

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2023 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package command_test
18+
19+
import (
20+
"os"
21+
"testing"
22+
23+
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
25+
26+
"vitess.io/vitess/go/cmd/vtctldclient/command"
27+
"vitess.io/vitess/go/vt/vtctl/localvtctldclient"
28+
29+
vtctlservicepb "vitess.io/vitess/go/vt/proto/vtctlservice"
30+
)
31+
32+
type emptyLocalServer struct {
33+
vtctlservicepb.UnimplementedVtctldServer
34+
}
35+
36+
func TestRoot(t *testing.T) {
37+
t.Run("error on unknown subcommand", func(t *testing.T) {
38+
args := append([]string{}, os.Args...)
39+
protocol := command.VtctldClientProtocol
40+
localvtctldclient.SetServer(&emptyLocalServer{})
41+
42+
t.Cleanup(func() {
43+
os.Args = append([]string{}, args...)
44+
command.VtctldClientProtocol = protocol
45+
})
46+
47+
os.Args = []string{"vtctldclient", "this-is-bunk"}
48+
command.VtctldClientProtocol = "local"
49+
50+
err := command.Root.Execute()
51+
require.Error(t, err, "root command should error on unknown command")
52+
assert.Contains(t, err.Error(), "unknown command")
53+
})
54+
}

go/flags/endtoend/vtctldclient.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Executes a cluster management command on the remote vtctld server.
22

33
Usage:
4+
vtctldclient [flags]
45
vtctldclient [command]
56

67
Available Commands:

0 commit comments

Comments
 (0)