"os"
)
-const removeLongHelp = "Remove key(s) under given namespace from SDL DB.\n" +
- "Multiple keys to remove can be given in a single command,\n" +
- "each key is separated from the one next to it by a space."
+const removeLongHelp = "Remove key(s) under given namespace from SDL DB. A key to remove\n" +
+ "can be an exact key name or a key search pattern. Multiple key names\n" +
+ "or search patterns can be given in a single command, each of which\n" +
+ "is separated from the one next to it by a space. If no key or\n" +
+ "search pattern is given, command removes all the keys under given\n" +
+ "namespace."
+
+const removeExample = " # Remove all keys in the given namespace.\n" +
+ " sdlcli remove sdlns\n" +
+ " # Remove keys 'key1' and 'key2' in the given namespace.\n" +
+ " sdlcli remove sdlns key1 key2\n" +
+ " # Remove keys in the given namespace matching given key search pattern.\n" +
+ " sdlcli remove sdlns 'he*'\n\n" +
+
+ " Supported search glob-style patterns:\n" +
+ " h?llo matches hello, hallo and hxllo\n" +
+ " h*llo matches hllo and heeeello\n" +
+ " h[ae]llo matches hello and hallo, but not hillo\n" +
+ " h[^e]llo matches hallo, hbllo, ... but not hello\n" +
+ " h[a-b]llo matches hallo and hbllo\n\n" +
+ " The \\ escapes character in key search pattern and those will be\n" +
+ " treated as a normal character:\n" +
+ " h\\[?llo\\* matches h[ello* and h[allo"
func init() {
rootCmd.AddCommand(newRemoveCmd(func() ISyncStorage {
func newRemoveCmd(sdlCreateCb SyncStorageCreateCb) *cobra.Command {
cmd := &cobra.Command{
- Use: "remove <namespace> <key> [<key2>... <keyN>]",
- Short: "Remove key(s) under given namespace from SDL DB",
- Long: removeLongHelp,
- Args: cobra.MinimumNArgs(2),
+ Use: "remove <namespace> [<key|pattern>... <keyN|patternN>]",
+ Short: "Remove key(s) under given namespace from SDL DB",
+ Long: removeLongHelp,
+ Example: removeExample,
+ Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
var buf bytes.Buffer
sdlgoredis.SetDbLogger(&buf)
func runRemove(sdlCreateCb SyncStorageCreateCb, args []string) error {
sdl := sdlCreateCb()
- if err := sdl.Remove(args[0], args[1:]); err != nil {
- return err
+ ns := args[0]
+ keyPatterns := []string{"*"}
+ if len(args) > 1 {
+ keyPatterns = args[1:]
+ }
+ for _, keyPattern := range keyPatterns {
+ keys, err := sdl.ListKeys(ns, keyPattern)
+ if err != nil {
+ return err
+ }
+ if err := sdl.Remove(ns, keys); err != nil {
+ return err
+ }
}
return nil
}
var removeMocks *RemoveMocks
type RemoveMocks struct {
- sdlIface *mocks.MockSdlApi
- ns string
- keys []string
- ret error
+ sdlIface *mocks.MockSdlApi
+ ns string
+ kps []string
+ keys []string
+ retList error
+ retRemove error
}
-func setupRemoveCliMock(ns string, keys []string, ret error) {
+func setupRemoveCliMock(ns string, keyPattern, keys []string, retList, retRemove error) {
removeMocks = new(RemoveMocks)
removeMocks.ns = ns
+ removeMocks.kps = keyPattern
removeMocks.keys = keys
- removeMocks.ret = ret
+ removeMocks.retList = retList
+ removeMocks.retRemove = retRemove
}
func newMockSdlRemoveApi() cli.ISyncStorage {
removeMocks.sdlIface = new(mocks.MockSdlApi)
- removeMocks.sdlIface.On("Remove", removeMocks.ns, removeMocks.keys).Return(removeMocks.ret)
+ if len(removeMocks.kps) == 0 {
+ removeMocks.kps = append(removeMocks.kps, "*")
+ }
+ for _, kp := range removeMocks.kps {
+ removeMocks.sdlIface.On("ListKeys", removeMocks.ns, kp).Return(removeMocks.keys, removeMocks.retList)
+ }
+ removeMocks.sdlIface.On("Remove", removeMocks.ns, removeMocks.keys).Return(removeMocks.retRemove).Maybe()
return removeMocks.sdlIface
}
cmd.SetOut(bufStdout)
cmd.SetErr(bufStderr)
args := []string{removeMocks.ns}
- args = append(args, removeMocks.keys...)
+ args = append(args, removeMocks.kps...)
cmd.SetArgs(args)
err := cmd.Execute()
func TestCliRemoveCanShowHelp(t *testing.T) {
var expOkErr error
- expHelp := "Usage:\n " + "remove <namespace> <key> [<key2>... <keyN>] [flags]"
+ expHelp := "remove <namespace> [<key|pattern>... <keyN|patternN>] [flags]"
expFlagErr := fmt.Errorf("unknown flag: --some-unknown-flag")
- expArgCntLtErr := fmt.Errorf("requires at least 2 arg(s), only received 1")
+ expArgCntLtErr := fmt.Errorf("requires at least 1 arg(s), only received 0")
tests := []struct {
args []string
expErr error
{args: []string{"-h"}, expErr: expOkErr, expOutput: expHelp},
{args: []string{"--help"}, expErr: expOkErr, expOutput: expHelp},
{args: []string{"--some-unknown-flag"}, expErr: expFlagErr, expOutput: expHelp},
- {args: []string{"some-ns"}, expErr: expArgCntLtErr, expOutput: expHelp},
+ {args: nil, expErr: expArgCntLtErr, expOutput: expHelp},
}
for _, test := range tests {
}
func TestCliRemoveCommandWithOneKeySuccess(t *testing.T) {
- setupRemoveCliMock("some-ns", []string{"some-key"}, nil)
+ setupRemoveCliMock("some-ns", []string{"some-key"}, []string{"some-key"}, nil, nil)
stdout, stderr, err := runRemoveCli()
removeMocks.sdlIface.AssertExpectations(t)
}
-func TestCliRemoveCommandWithMultipleKeysSuccess(t *testing.T) {
- setupRemoveCliMock("some-ns", []string{"some-key-1", "some-key-1", "some-key-3"}, nil)
+func TestCliRemoveCommandWithOneKeyPatternSuccess(t *testing.T) {
+ setupRemoveCliMock("some-ns", []string{"some-key*"}, []string{"some-key-1", "some-key-1", "some-key-3"}, nil, nil)
stdout, stderr, err := runRemoveCli()
removeMocks.sdlIface.AssertExpectations(t)
}
-func TestCliRemoveCommandFailure(t *testing.T) {
+func TestCliRemoveCommandWithMultipleKeyPatternsSuccess(t *testing.T) {
+ setupRemoveCliMock("some-ns", []string{"some-key*", "other-key*"}, []string{"other-key2"}, nil, nil)
+
+ stdout, stderr, err := runRemoveCli()
+
+ assert.Nil(t, err)
+ assert.Equal(t, "", stdout)
+ assert.Equal(t, "", stderr)
+ removeMocks.sdlIface.AssertExpectations(t)
+}
+
+func TestCliRemoveCommandWithOutKeyOrPatternSuccess(t *testing.T) {
+ setupRemoveCliMock("some-ns", []string{}, []string{"some-key-1", "some-key-1", "some-key-3"}, nil, nil)
+
+ stdout, stderr, err := runRemoveCli()
+
+ assert.Nil(t, err)
+ assert.Equal(t, "", stdout)
+ assert.Equal(t, "", stderr)
+ removeMocks.sdlIface.AssertExpectations(t)
+}
+
+func TestCliRemoveCommandErrorInSdlApiListKeysFailure(t *testing.T) {
+ expErr := fmt.Errorf("some-error")
+ setupRemoveCliMock("some-ns", []string{"*"}, []string{"some-key"}, expErr, nil)
+
+ _, stderr, err := runRemoveCli()
+
+ assert.Equal(t, expErr, err)
+ assert.Contains(t, stderr, expErr.Error())
+ removeMocks.sdlIface.AssertExpectations(t)
+}
+
+func TestCliRemoveCommandErrorInSdlApiRemoveFailure(t *testing.T) {
expErr := fmt.Errorf("some-error")
- setupRemoveCliMock("some-ns", []string{"some-key"}, expErr)
+ setupRemoveCliMock("some-ns", []string{"*"}, []string{"some-key"}, nil, expErr)
_, stderr, err := runRemoveCli()