From 44cda79105d0c7ffa2df7eab6581b78353c635b4 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Thu, 3 May 2018 13:25:37 -0700 Subject: [PATCH 1/4] etcdctl/ctlv3: fix watch with exec commands Following command was failing because the parser incorrectly picks up the second "watch" string in exec command, thus passing wrong exec commands. ``` ETCDCTL_API=3 ./bin/etcdctl watch aaa -- echo watch event received panic: runtime error: slice bounds out of range goroutine 1 [running]: github.com/coreos/etcd/etcdctl/ctlv3/command.parseWatchArgs(0xc42002e080, 0x8, 0x8, 0xc420206a20, 0x5, 0x6, 0x0, 0x0, 0x0, 0x0, ...) /home/gyuho/go/src/github.com/coreos/etcd/etcdctl/ctlv3/command/watch_command.go:303 +0xbed github.com/coreos/etcd/etcdctl/ctlv3/command.watchCommandFunc(0xc4202a7180, 0xc420206a20, 0x5, 0x6) /home/gyuho/go/src/github.com/coreos/etcd/etcdctl/ctlv3/command/watch_command.go:73 +0x11d github.com/coreos/etcd/vendor/github.com/spf13/cobra.(*Command).execute(0xc4202a7180, 0xc420206960, 0x6, 0x6, 0xc4202a7180, 0xc420206960) /home/gyuho/go/src/github.com/coreos/etcd/vendor/github.com/spf13/cobra/command.go:766 +0x2c1 github.com/coreos/etcd/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0x1363de0, 0xc420128638, 0xc420185e01, 0xc420185ee8) /home/gyuho/go/src/github.com/coreos/etcd/vendor/github.com/spf13/cobra/command.go:852 +0x30a github.com/coreos/etcd/vendor/github.com/spf13/cobra.(*Command).Execute(0x1363de0, 0x0, 0x0) /home/gyuho/go/src/github.com/coreos/etcd/vendor/github.com/spf13/cobra/command.go:800 +0x2b github.com/coreos/etcd/etcdctl/ctlv3.Start() /home/gyuho/go/src/github.com/coreos/etcd/etcdctl/ctlv3/ctl_nocov.go:25 +0x8e main.main() /home/gyuho/go/src/github.com/coreos/etcd/etcdctl/main.go:40 +0x17b ``` Signed-off-by: Gyuho Lee --- etcdctl/ctlv3/command/watch_command.go | 171 +++++--- etcdctl/ctlv3/command/watch_command_test.go | 445 ++++++++++++++------ 2 files changed, 428 insertions(+), 188 deletions(-) diff --git a/etcdctl/ctlv3/command/watch_command.go b/etcdctl/ctlv3/command/watch_command.go index 33447f649ee..1a2cc4213f5 100644 --- a/etcdctl/ctlv3/command/watch_command.go +++ b/etcdctl/ctlv3/command/watch_command.go @@ -179,118 +179,159 @@ func printWatchCh(c *clientv3.Client, ch clientv3.WatchChan, execArgs []string) // "--" characters are invalid arguments for "spf13/cobra" library, // so no need to handle such cases. func parseWatchArgs(osArgs, commandArgs []string, envKey, envRange string, interactive bool) (watchArgs []string, execArgs []string, err error) { - watchArgs = commandArgs + rawArgs := make([]string, len(osArgs)) + copy(rawArgs, osArgs) + watchArgs = make([]string, len(commandArgs)) + copy(watchArgs, commandArgs) - // remove preceding commands (e.g. "watch foo bar" in interactive mode) - idx := 0 - for idx = range watchArgs { - if watchArgs[idx] == "watch" { + // remove preceding commands (e.g. ./bin/etcdctl watch) + // handle "./bin/etcdctl watch foo -- echo watch event" + for idx := range rawArgs { + if rawArgs[idx] == "watch" { + rawArgs = rawArgs[idx+1:] break } } - if idx < len(watchArgs)-1 || envKey != "" { - if idx < len(watchArgs)-1 { - watchArgs = watchArgs[idx+1:] + + // remove preceding commands (e.g. "watch foo bar" in interactive mode) + // handle "./bin/etcdctl watch foo -- echo watch event" + if interactive { + if watchArgs[0] != "watch" { + // "watch" not found + watchPrefix, watchRev, watchPrevKey = false, 0, false + return nil, nil, errBadArgsInteractiveWatch } + watchArgs = watchArgs[1:] + } - execIdx, execExist := 0, false - for execIdx = range osArgs { - v := osArgs[execIdx] - if v == "--" && execIdx != len(osArgs)-1 { + execIdx, execExist := 0, false + if !interactive { + for execIdx = range rawArgs { + if rawArgs[execIdx] == "--" { execExist = true break } } - - if idx == len(watchArgs)-1 && envKey != "" { - if len(watchArgs) > 0 && !interactive { - // "watch --rev 1 -- echo Hello World" has no conflict - if !execExist { - // "watch foo" with ETCDCTL_WATCH_KEY=foo - // (watchArgs==["foo"]) - return nil, nil, errBadArgsNumConflictEnv - } - } - // otherwise, watch with no argument and environment key is set - // if interactive, first "watch" command string should be removed - if interactive { - watchArgs = []string{} - } + if execExist && execIdx == len(rawArgs)-1 { + // "watch foo bar --" should error + return nil, nil, errBadArgsNumSeparator } - - // "watch foo -- echo hello" with ETCDCTL_WATCH_KEY=foo - // (watchArgs==["foo","echo","hello"]) - if envKey != "" && execExist { - widx, oidx := 0, len(osArgs)-1 - for widx = len(watchArgs) - 1; widx >= 0; widx-- { - if watchArgs[widx] == osArgs[oidx] { - oidx-- + // "watch" with no argument should error + if !execExist && len(rawArgs) < 1 && envKey == "" { + return nil, nil, errBadArgsNum + } + if execExist && envKey != "" { + // "ETCDCTL_WATCH_KEY=foo watch foo -- echo 1" should error + // (watchArgs==["foo","echo","1"]) + widx, ridx := len(watchArgs)-1, len(rawArgs)-1 + for ; widx >= 0; widx-- { + if watchArgs[widx] == rawArgs[ridx] { + ridx-- continue } - if oidx == execIdx { // watchArgs has extra + // watchArgs has extra: + // ETCDCTL_WATCH_KEY=foo watch foo -- echo 1 + // watchArgs: foo echo 1 + if ridx == execIdx { return nil, nil, errBadArgsNumConflictEnv } } } - } else if interactive { // "watch" not found - return nil, nil, errBadArgsInteractiveWatch - } - if len(watchArgs) < 1 && envKey == "" { - return nil, nil, errBadArgsNum - } + // check conflicting arguments + // e.g. "watch --rev 1 -- echo Hello World" has no conflict + if !execExist && len(watchArgs) > 0 && envKey != "" { + // "ETCDCTL_WATCH_KEY=foo watch foo" should error + // (watchArgs==["foo"]) + return nil, nil, errBadArgsNumConflictEnv + } + } else { + for execIdx = range watchArgs { + if watchArgs[execIdx] == "--" { + execExist = true + break + } + } + if execExist && execIdx == len(watchArgs)-1 { + // "watch foo bar --" should error + watchPrefix, watchRev, watchPrevKey = false, 0, false + return nil, nil, errBadArgsNumSeparator + } - // remove preceding commands (e.g. ./bin/etcdctl watch) - for idx = range osArgs { - if osArgs[idx] == "watch" { - break + flagset := NewWatchCommand().Flags() + if err := flagset.Parse(watchArgs); err != nil { + watchPrefix, watchRev, watchPrevKey = false, 0, false + return nil, nil, err + } + pArgs := flagset.Args() + + // "watch" with no argument should error + if !execExist && envKey == "" && len(pArgs) < 1 { + watchPrefix, watchRev, watchPrevKey = false, 0, false + return nil, nil, errBadArgsNum + } + // check conflicting arguments + // e.g. "watch --rev 1 -- echo Hello World" has no conflict + if !execExist && len(pArgs) > 0 && envKey != "" { + // "ETCDCTL_WATCH_KEY=foo watch foo" should error + // (watchArgs==["foo"]) + watchPrefix, watchRev, watchPrevKey = false, 0, false + return nil, nil, errBadArgsNumConflictEnv } - } - if idx < len(osArgs)-1 { - osArgs = osArgs[idx+1:] - } else if envKey == "" { - return nil, nil, errBadArgsNum } - argsWithSep := osArgs - if interactive { // interactive mode pass "--" to the command args + argsWithSep := rawArgs + if interactive { + // interactive mode directly passes "--" to the command args argsWithSep = watchArgs } - foundSep := false + + idx, foundSep := 0, false for idx = range argsWithSep { if argsWithSep[idx] == "--" { foundSep = true break } } + if foundSep { + execArgs = argsWithSep[idx+1:] + } + if interactive { flagset := NewWatchCommand().Flags() if err := flagset.Parse(argsWithSep); err != nil { return nil, nil, err } watchArgs = flagset.Args() + + watchPrefix, err = flagset.GetBool("prefix") + if err != nil { + return nil, nil, err + } + watchRev, err = flagset.GetInt64("rev") + if err != nil { + return nil, nil, err + } + watchPrevKey, err = flagset.GetBool("prev-kv") + if err != nil { + return nil, nil, err + } } - // "watch -- echo hello" with ETCDCTL_WATCH_KEY=foo - // should be translated to "watch foo -- echo hello" + // "ETCDCTL_WATCH_KEY=foo watch -- echo hello" + // should translate "watch foo -- echo hello" // (watchArgs=["echo","hello"] should be ["foo","echo","hello"]) if envKey != "" { - tmp := []string{envKey} + ranges := []string{envKey} if envRange != "" { - tmp = append(tmp, envRange) + ranges = append(ranges, envRange) } - watchArgs = append(tmp, watchArgs...) + watchArgs = append(ranges, watchArgs...) } if !foundSep { return watchArgs, nil, nil } - if idx == len(argsWithSep)-1 { - // "watch foo bar --" should error - return nil, nil, errBadArgsNumSeparator - } - execArgs = argsWithSep[idx+1:] - // "watch foo bar --rev 1 -- echo hello" or "watch foo --rev 1 bar -- echo hello", // then "watchArgs" is "foo bar echo hello" // so need ignore args after "argsWithSep[idx]", which is "--" diff --git a/etcdctl/ctlv3/command/watch_command_test.go b/etcdctl/ctlv3/command/watch_command_test.go index 1456c971f0c..2292deadcbb 100644 --- a/etcdctl/ctlv3/command/watch_command_test.go +++ b/etcdctl/ctlv3/command/watch_command_test.go @@ -26,6 +26,10 @@ func Test_parseWatchArgs(t *testing.T) { envKey, envRange string interactive bool + interactiveWatchPrefix bool + interactiveWatchRev int64 + interactiveWatchPrevKey bool + watchArgs []string execArgs []string err error @@ -145,6 +149,14 @@ func Test_parseWatchArgs(t *testing.T) { execArgs: []string{"echo", "Hello", "World"}, err: nil, }, + { + osArgs: []string{"./bin/etcdctl", "watch", "foo", "--", "echo", "watch", "event", "received"}, + commandArgs: []string{"foo", "echo", "watch", "event", "received"}, + interactive: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "watch", "event", "received"}, + err: nil, + }, { osArgs: []string{"./bin/etcdctl", "watch", "foo", "--rev", "1", "--", "echo", "Hello", "World"}, commandArgs: []string{"foo", "echo", "Hello", "World"}, @@ -153,6 +165,22 @@ func Test_parseWatchArgs(t *testing.T) { execArgs: []string{"echo", "Hello", "World"}, err: nil, }, + { + osArgs: []string{"./bin/etcdctl", "watch", "foo", "--rev", "1", "--", "echo", "watch", "event", "received"}, + commandArgs: []string{"foo", "echo", "watch", "event", "received"}, + interactive: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "watch", "event", "received"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "foo", "--", "echo", "watch", "event", "received"}, + commandArgs: []string{"foo", "echo", "watch", "event", "received"}, + interactive: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "watch", "event", "received"}, + err: nil, + }, { osArgs: []string{"./bin/etcdctl", "watch", "foo", "bar", "--", "echo", "Hello", "World"}, commandArgs: []string{"foo", "bar", "echo", "Hello", "World"}, @@ -186,162 +214,322 @@ func Test_parseWatchArgs(t *testing.T) { err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "--", "echo", "Hello", "World"}, - commandArgs: []string{"echo", "Hello", "World"}, - envKey: "foo", - envRange: "", + osArgs: []string{"./bin/etcdctl", "watch", "foo", "bar", "--rev", "1", "--", "echo", "watch", "event", "received"}, + commandArgs: []string{"foo", "bar", "echo", "watch", "event", "received"}, interactive: false, - watchArgs: []string{"foo"}, - execArgs: []string{"echo", "Hello", "World"}, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "watch", "event", "received"}, err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "--", "echo", "Hello", "World"}, - commandArgs: []string{"echo", "Hello", "World"}, - envKey: "foo", - envRange: "bar", + osArgs: []string{"./bin/etcdctl", "watch", "foo", "--rev", "1", "bar", "--", "echo", "Hello", "World"}, + commandArgs: []string{"foo", "bar", "echo", "Hello", "World"}, interactive: false, watchArgs: []string{"foo", "bar"}, execArgs: []string{"echo", "Hello", "World"}, err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "foo", "bar", "--rev", "1", "--", "echo", "Hello", "World"}, + osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "foo", "bar", "--", "echo", "Hello", "World"}, commandArgs: []string{"foo", "bar", "echo", "Hello", "World"}, - envKey: "foo", interactive: false, - watchArgs: nil, - execArgs: nil, - err: errBadArgsNumConflictEnv, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"foo", "bar", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: nil, - execArgs: nil, - err: errBadArgsInteractiveWatch, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo"}, - interactive: true, - watchArgs: []string{"foo"}, - execArgs: nil, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "bar"}, - interactive: true, watchArgs: []string{"foo", "bar"}, - execArgs: nil, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch"}, - envKey: "foo", - envRange: "bar", - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: nil, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch"}, - envKey: "hello world!", - envRange: "bar", - interactive: true, - watchArgs: []string{"hello world!", "bar"}, - execArgs: nil, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "--rev", "1"}, - interactive: true, - watchArgs: []string{"foo"}, - execArgs: nil, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "--rev", "1", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: []string{"foo"}, execArgs: []string{"echo", "Hello", "World"}, err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "--rev", "1", "foo", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: []string{"foo"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "--", "echo", "Hello", "World"}, + osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "--", "echo", "Hello", "World"}, + commandArgs: []string{"echo", "Hello", "World"}, envKey: "foo", - interactive: true, + envRange: "", + interactive: false, watchArgs: []string{"foo"}, execArgs: []string{"echo", "Hello", "World"}, err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "--", "echo", "Hello", "World"}, + osArgs: []string{"./bin/etcdctl", "watch", "--rev", "1", "--", "echo", "Hello", "World"}, + commandArgs: []string{"echo", "Hello", "World"}, envKey: "foo", envRange: "bar", - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "bar", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "--rev", "1", "foo", "bar", "--", "echo", "Hello", "World"}, - interactive: true, + interactive: false, watchArgs: []string{"foo", "bar"}, execArgs: []string{"echo", "Hello", "World"}, err: nil, }, { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "--rev", "1", "--", "echo", "Hello", "World"}, + osArgs: []string{"./bin/etcdctl", "watch", "foo", "bar", "--rev", "1", "--", "echo", "Hello", "World"}, + commandArgs: []string{"foo", "bar", "echo", "Hello", "World"}, envKey: "foo", - envRange: "bar", - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, - }, - { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "--rev", "1", "bar", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, + interactive: false, + watchArgs: nil, + execArgs: nil, + err: errBadArgsNumConflictEnv, }, { - osArgs: []string{"./bin/etcdctl", "watch", "-i"}, - commandArgs: []string{"watch", "foo", "bar", "--rev", "1", "--", "echo", "Hello", "World"}, - interactive: true, - watchArgs: []string{"foo", "bar"}, - execArgs: []string{"echo", "Hello", "World"}, - err: nil, + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"foo", "bar", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: nil, + execArgs: nil, + err: errBadArgsInteractiveWatch, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "bar"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch"}, + envKey: "foo", + envRange: "bar", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch"}, + envKey: "hello world!", + envRange: "bar", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"hello world!", "bar"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "--rev", "1"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "--rev", "1", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1", "foo", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "5", "--prev-kv", "foo", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 5, + interactiveWatchPrevKey: true, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1"}, + envKey: "foo", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: nil, + execArgs: nil, + err: errBadArgsNum, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1", "--prefix"}, + envKey: "foo", + interactive: true, + interactiveWatchPrefix: true, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "100", "--prefix", "--prev-kv"}, + envKey: "foo", + interactive: true, + interactiveWatchPrefix: true, + interactiveWatchRev: 100, + interactiveWatchPrevKey: true, + watchArgs: []string{"foo"}, + execArgs: nil, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1", "--prefix"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: nil, + execArgs: nil, + err: errBadArgsNum, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--", "echo", "Hello", "World"}, + envKey: "foo", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--", "echo", "Hello", "World"}, + envKey: "foo", + envRange: "bar", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "bar", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 0, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1", "foo", "bar", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "--rev", "1", "--", "echo", "Hello", "World"}, + envKey: "foo", + envRange: "bar", + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "--rev", "1", "bar", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "bar", "--rev", "1", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: false, + interactiveWatchRev: 1, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "bar", "--rev", "7", "--prefix", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: true, + interactiveWatchRev: 7, + interactiveWatchPrevKey: false, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, + }, + { + osArgs: []string{"./bin/etcdctl", "watch", "-i"}, + commandArgs: []string{"watch", "foo", "bar", "--rev", "7", "--prefix", "--prev-kv", "--", "echo", "Hello", "World"}, + interactive: true, + interactiveWatchPrefix: true, + interactiveWatchRev: 7, + interactiveWatchPrevKey: true, + watchArgs: []string{"foo", "bar"}, + execArgs: []string{"echo", "Hello", "World"}, + err: nil, }, } for i, ts := range tt { @@ -355,5 +543,16 @@ func Test_parseWatchArgs(t *testing.T) { if !reflect.DeepEqual(execArgs, ts.execArgs) { t.Fatalf("#%d: execArgs expected %q, got %v", i, ts.execArgs, execArgs) } + if ts.interactive { + if ts.interactiveWatchPrefix != watchPrefix { + t.Fatalf("#%d: interactive watchPrefix expected %v, got %v", i, ts.interactiveWatchPrefix, watchPrefix) + } + if ts.interactiveWatchRev != watchRev { + t.Fatalf("#%d: interactive watchRev expected %d, got %d", i, ts.interactiveWatchRev, watchRev) + } + if ts.interactiveWatchPrevKey != watchPrevKey { + t.Fatalf("#%d: interactive watchPrevKey expected %v, got %v", i, ts.interactiveWatchPrevKey, watchPrevKey) + } + } } } From acf671a94c020e3f57e2791556d9812d88ce51a4 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Thu, 3 May 2018 17:21:48 -0700 Subject: [PATCH 2/4] tests/e2e: separate coverage tests for exec commands Signed-off-by: Gyuho Lee --- tests/e2e/ctl_v3_watch_cov_test.go | 134 +++++++++++++++++++++ tests/e2e/ctl_v3_watch_no_cov_test.go | 167 ++++++++++++++++++++++++++ tests/e2e/ctl_v3_watch_test.go | 158 +----------------------- 3 files changed, 303 insertions(+), 156 deletions(-) create mode 100644 tests/e2e/ctl_v3_watch_cov_test.go create mode 100644 tests/e2e/ctl_v3_watch_no_cov_test.go diff --git a/tests/e2e/ctl_v3_watch_cov_test.go b/tests/e2e/ctl_v3_watch_cov_test.go new file mode 100644 index 00000000000..77f04506338 --- /dev/null +++ b/tests/e2e/ctl_v3_watch_cov_test.go @@ -0,0 +1,134 @@ +// Copyright 2018 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build cov + +package e2e + +import ( + "os" + "testing" +) + +func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) } +func TestCtlV3WatchNoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configNoTLS)) } +func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) } +func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) } +func TestCtlV3WatchTimeout(t *testing.T) { testCtl(t, watchTest, withDialTimeout(0)) } + +func TestCtlV3WatchInteractive(t *testing.T) { + testCtl(t, watchTest, withInteractive()) +} +func TestCtlV3WatchInteractiveNoTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS)) +} +func TestCtlV3WatchInteractiveClientTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS)) +} +func TestCtlV3WatchInteractivePeerTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS)) +} + +func watchTest(cx ctlCtx) { + tests := []struct { + puts []kv + envKey string + envRange string + args []string + + wkv []kvExec + }{ + { // watch 1 key + puts: []kv{{"sample", "value"}}, + args: []string{"sample", "--rev", "1"}, + wkv: []kvExec{{key: "sample", val: "value"}}, + }, + { // watch 1 key with env + puts: []kv{{"sample", "value"}}, + envKey: "sample", + args: []string{"--rev", "1"}, + wkv: []kvExec{{key: "sample", val: "value"}}, + }, + + // coverage tests get extra arguments: + // ./bin/etcdctl_test -test.coverprofile=e2e.1525392462795198897.coverprofile -test.outputdir=../.. + // do not test watch exec commands + + { // watch 3 keys by prefix + puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, + args: []string{"key", "--rev", "1", "--prefix"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, + }, + { // watch 3 keys by prefix, with env + puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, + envKey: "key", + args: []string{"--rev", "1", "--prefix"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, + }, + { // watch by revision + puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}}, + args: []string{"etcd", "--rev", "2"}, + wkv: []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}}, + }, + { // watch 3 keys by range + puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, + args: []string{"key", "key3", "--rev", "1"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, + }, + { // watch 3 keys by range, with env + puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, + envKey: "key", + envRange: "key3", + args: []string{"--rev", "1"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, + }, + } + + for i, tt := range tests { + donec := make(chan struct{}) + go func(i int, puts []kv) { + for j := range puts { + if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil { + cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err) + } + } + close(donec) + }(i, tt.puts) + + unsetEnv := func() {} + if tt.envKey != "" || tt.envRange != "" { + if tt.envKey != "" { + os.Setenv("ETCDCTL_WATCH_KEY", tt.envKey) + unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_KEY") } + } + if tt.envRange != "" { + os.Setenv("ETCDCTL_WATCH_RANGE_END", tt.envRange) + unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_RANGE_END") } + } + if tt.envKey != "" && tt.envRange != "" { + unsetEnv = func() { + os.Unsetenv("ETCDCTL_WATCH_KEY") + os.Unsetenv("ETCDCTL_WATCH_RANGE_END") + } + } + } + if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil { + if cx.dialTimeout > 0 && !isGRPCTimedout(err) { + cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err) + } + } + unsetEnv() + <-donec + } +} diff --git a/tests/e2e/ctl_v3_watch_no_cov_test.go b/tests/e2e/ctl_v3_watch_no_cov_test.go new file mode 100644 index 00000000000..6dffeee3f14 --- /dev/null +++ b/tests/e2e/ctl_v3_watch_no_cov_test.go @@ -0,0 +1,167 @@ +// Copyright 2018 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !cov + +package e2e + +import ( + "os" + "testing" +) + +func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) } +func TestCtlV3WatchNoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configNoTLS)) } +func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) } +func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) } +func TestCtlV3WatchTimeout(t *testing.T) { testCtl(t, watchTest, withDialTimeout(0)) } + +func TestCtlV3WatchInteractive(t *testing.T) { + testCtl(t, watchTest, withInteractive()) +} +func TestCtlV3WatchInteractiveNoTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS)) +} +func TestCtlV3WatchInteractiveClientTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS)) +} +func TestCtlV3WatchInteractivePeerTLS(t *testing.T) { + testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS)) +} + +func watchTest(cx ctlCtx) { + tests := []struct { + puts []kv + envKey string + envRange string + args []string + + wkv []kvExec + }{ + { // watch 1 key + puts: []kv{{"sample", "value"}}, + args: []string{"sample", "--rev", "1"}, + wkv: []kvExec{{key: "sample", val: "value"}}, + }, + { // watch 1 key with env + puts: []kv{{"sample", "value"}}, + envKey: "sample", + args: []string{"--rev", "1"}, + wkv: []kvExec{{key: "sample", val: "value"}}, + }, + { // watch 1 key with ${ETCD_WATCH_VALUE} + puts: []kv{{"sample", "value"}}, + args: []string{"sample", "--rev", "1", "--", "env"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: `ETCD_WATCH_VALUE="value"`}}, + }, + { // watch 1 key with "echo watch event received", with env + puts: []kv{{"sample", "value"}}, + envKey: "sample", + args: []string{"--rev", "1", "--", "echo", "watch event received"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, + }, + { // watch 1 key with "echo watch event received" + puts: []kv{{"sample", "value"}}, + args: []string{"--rev", "1", "sample", "--", "echo", "watch event received"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, + }, + { // watch 1 key with "echo \"Hello World!\"" + puts: []kv{{"sample", "value"}}, + args: []string{"--rev", "1", "sample", "--", "echo", "\"Hello World!\""}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "Hello World!"}}, + }, + { // watch 1 key with "echo watch event received" + puts: []kv{{"sample", "value"}}, + args: []string{"sample", "samplx", "--rev", "1", "--", "echo", "watch event received"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, + }, + { // watch 1 key with "echo watch event received" + puts: []kv{{"sample", "value"}}, + envKey: "sample", + envRange: "samplx", + args: []string{"--rev", "1", "--", "echo", "watch event received"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, + }, + { // watch 1 key with "echo watch event received" + puts: []kv{{"sample", "value"}}, + args: []string{"sample", "--rev", "1", "samplx", "--", "echo", "watch event received"}, + wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, + }, + { // watch 3 keys by prefix + puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, + args: []string{"key", "--rev", "1", "--prefix"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, + }, + { // watch 3 keys by prefix, with env + puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, + envKey: "key", + args: []string{"--rev", "1", "--prefix"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, + }, + { // watch by revision + puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}}, + args: []string{"etcd", "--rev", "2"}, + wkv: []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}}, + }, + { // watch 3 keys by range + puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, + args: []string{"key", "key3", "--rev", "1"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, + }, + { // watch 3 keys by range, with env + puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, + envKey: "key", + envRange: "key3", + args: []string{"--rev", "1"}, + wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, + }, + } + + for i, tt := range tests { + donec := make(chan struct{}) + go func(i int, puts []kv) { + for j := range puts { + if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil { + cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err) + } + } + close(donec) + }(i, tt.puts) + + unsetEnv := func() {} + if tt.envKey != "" || tt.envRange != "" { + if tt.envKey != "" { + os.Setenv("ETCDCTL_WATCH_KEY", tt.envKey) + unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_KEY") } + } + if tt.envRange != "" { + os.Setenv("ETCDCTL_WATCH_RANGE_END", tt.envRange) + unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_RANGE_END") } + } + if tt.envKey != "" && tt.envRange != "" { + unsetEnv = func() { + os.Unsetenv("ETCDCTL_WATCH_KEY") + os.Unsetenv("ETCDCTL_WATCH_RANGE_END") + } + } + } + if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil { + if cx.dialTimeout > 0 && !isGRPCTimedout(err) { + cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err) + } + } + unsetEnv() + <-donec + } +} diff --git a/tests/e2e/ctl_v3_watch_test.go b/tests/e2e/ctl_v3_watch_test.go index dbc2f081c7d..fe25da1b765 100644 --- a/tests/e2e/ctl_v3_watch_test.go +++ b/tests/e2e/ctl_v3_watch_test.go @@ -1,4 +1,4 @@ -// Copyright 2016 The etcd Authors +// Copyright 2018 The etcd Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,167 +14,13 @@ package e2e -import ( - "os" - "strings" - "testing" -) - -func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) } -func TestCtlV3WatchNoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configNoTLS)) } -func TestCtlV3WatchClientTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configClientTLS)) } -func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) } -func TestCtlV3WatchTimeout(t *testing.T) { testCtl(t, watchTest, withDialTimeout(0)) } - -func TestCtlV3WatchInteractive(t *testing.T) { - testCtl(t, watchTest, withInteractive()) -} -func TestCtlV3WatchInteractiveNoTLS(t *testing.T) { - testCtl(t, watchTest, withInteractive(), withCfg(configNoTLS)) -} -func TestCtlV3WatchInteractiveClientTLS(t *testing.T) { - testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS)) -} -func TestCtlV3WatchInteractivePeerTLS(t *testing.T) { - testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS)) -} +import "strings" type kvExec struct { key, val string execOutput string } -func watchTest(cx ctlCtx) { - tests := []struct { - puts []kv - envKey string - envRange string - args []string - - wkv []kvExec - }{ - { // watch 1 key - puts: []kv{{"sample", "value"}}, - args: []string{"sample", "--rev", "1"}, - wkv: []kvExec{{key: "sample", val: "value"}}, - }, - { // watch 1 key with env - puts: []kv{{"sample", "value"}}, - envKey: "sample", - args: []string{"--rev", "1"}, - wkv: []kvExec{{key: "sample", val: "value"}}, - }, - { // watch 1 key with "echo watch event received" - puts: []kv{{"sample", "value"}}, - args: []string{"sample", "--rev", "1", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 1 key with ${ETCD_WATCH_VALUE} - puts: []kv{{"sample", "value"}}, - args: []string{"sample", "--rev", "1", "--", "env"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: `ETCD_WATCH_VALUE="value"`}}, - }, - { // watch 1 key with "echo watch event received", with env - puts: []kv{{"sample", "value"}}, - envKey: "sample", - args: []string{"--rev", "1", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 1 key with "echo watch event received" - puts: []kv{{"sample", "value"}}, - args: []string{"--rev", "1", "sample", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 1 key with "echo \"Hello World!\"" - puts: []kv{{"sample", "value"}}, - args: []string{"--rev", "1", "sample", "--", "echo", "\"Hello World!\""}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "Hello World!"}}, - }, - { // watch 1 key with "echo watch event received" - puts: []kv{{"sample", "value"}}, - args: []string{"sample", "samplx", "--rev", "1", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 1 key with "echo watch event received" - puts: []kv{{"sample", "value"}}, - envKey: "sample", - envRange: "samplx", - args: []string{"--rev", "1", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 1 key with "echo watch event received" - puts: []kv{{"sample", "value"}}, - args: []string{"sample", "--rev", "1", "samplx", "--", "echo", "watch event received"}, - wkv: []kvExec{{key: "sample", val: "value", execOutput: "watch event received"}}, - }, - { // watch 3 keys by prefix - puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, - args: []string{"key", "--rev", "1", "--prefix"}, - wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, - }, - { // watch 3 keys by prefix, with env - puts: []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}}, - envKey: "key", - args: []string{"--rev", "1", "--prefix"}, - wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}, {key: "key3", val: "val3"}}, - }, - { // watch by revision - puts: []kv{{"etcd", "revision_1"}, {"etcd", "revision_2"}, {"etcd", "revision_3"}}, - args: []string{"etcd", "--rev", "2"}, - wkv: []kvExec{{key: "etcd", val: "revision_2"}, {key: "etcd", val: "revision_3"}}, - }, - { // watch 3 keys by range - puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, - args: []string{"key", "key3", "--rev", "1"}, - wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, - }, - { // watch 3 keys by range, with env - puts: []kv{{"key1", "val1"}, {"key3", "val3"}, {"key2", "val2"}}, - envKey: "key", - envRange: "key3", - args: []string{"--rev", "1"}, - wkv: []kvExec{{key: "key1", val: "val1"}, {key: "key2", val: "val2"}}, - }, - } - - for i, tt := range tests { - donec := make(chan struct{}) - go func(i int, puts []kv) { - for j := range puts { - if err := ctlV3Put(cx, puts[j].key, puts[j].val, ""); err != nil { - cx.t.Fatalf("watchTest #%d-%d: ctlV3Put error (%v)", i, j, err) - } - } - close(donec) - }(i, tt.puts) - - unsetEnv := func() {} - if tt.envKey != "" || tt.envRange != "" { - if tt.envKey != "" { - os.Setenv("ETCDCTL_WATCH_KEY", tt.envKey) - unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_KEY") } - } - if tt.envRange != "" { - os.Setenv("ETCDCTL_WATCH_RANGE_END", tt.envRange) - unsetEnv = func() { os.Unsetenv("ETCDCTL_WATCH_RANGE_END") } - } - if tt.envKey != "" && tt.envRange != "" { - unsetEnv = func() { - os.Unsetenv("ETCDCTL_WATCH_KEY") - os.Unsetenv("ETCDCTL_WATCH_RANGE_END") - } - } - } - if err := ctlV3Watch(cx, tt.args, tt.wkv...); err != nil { - if cx.dialTimeout > 0 && !isGRPCTimedout(err) { - cx.t.Errorf("watchTest #%d: ctlV3Watch error (%v)", i, err) - } - } - unsetEnv() - <-donec - } -} - func setupWatchArgs(cx ctlCtx, args []string) []string { cmdArgs := append(cx.PrefixArgs(), "watch") if cx.interactive { From 11028331e6c1c0b0d0aa50b51a4eed135478cf88 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Thu, 3 May 2018 17:22:09 -0700 Subject: [PATCH 3/4] gitignore: add "*.coverprofile" Signed-off-by: Gyuho Lee --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d3b248f1ed5..e1a16f353e0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.log /etcd /hack/insta-discovery/.env +*.coverprofile *.test hack/tls-setup/certs .idea From 38fcfb63b44b187ac45c41ec10d12ee2a74ae184 Mon Sep 17 00:00:00 2001 From: Gyuho Lee Date: Thu, 3 May 2018 17:22:17 -0700 Subject: [PATCH 4/4] Makefile: add ".coverprofile" to "make clean" Signed-off-by: Gyuho Lee --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index e4d1c730b12..dcb4b6835ed 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,12 @@ clean: rm -f ./codecov rm -rf ./agent-* rm -rf ./covdir + rm -f ./*.coverprofile rm -f ./*.log rm -f ./bin/Dockerfile-release rm -rf ./bin/*.etcd + rm -rf ./default.etcd + rm -rf ./tests/e2e/default.etcd rm -rf ./gopath rm -rf ./gopath.proto rm -rf ./release