diff --git a/e2e/etcdctlv3_test.go b/e2e/etcdctlv3_test.go index 959f0ec94..f44e20e8a 100644 --- a/e2e/etcdctlv3_test.go +++ b/e2e/etcdctlv3_test.go @@ -25,35 +25,40 @@ import ( "github.com/coreos/etcd/pkg/testutil" ) -func TestCtlV3Put(t *testing.T) { testCtl(t, putTest) } -func TestCtlV3PutTimeout(t *testing.T) { testCtl(t, putTest, withDialTimeout(0)) } -func TestCtlV3PutTimeoutQuorum(t *testing.T) { testCtl(t, putTest, withDialTimeout(0), withQuorum()) } -func TestCtlV3PutAutoTLS(t *testing.T) { testCtl(t, putTest, withCfg(configAutoTLS)) } -func TestCtlV3PutPeerTLS(t *testing.T) { testCtl(t, putTest, withCfg(configPeerTLS)) } -func TestCtlV3PutClientTLS(t *testing.T) { testCtl(t, putTest, withCfg(configClientTLS)) } +func TestCtlV3Put(t *testing.T) { testCtl(t, putTest) } +func TestCtlV3PutNoTLS(t *testing.T) { testCtl(t, putTest, withCfg(configNoTLS)) } +func TestCtlV3PutClientTLS(t *testing.T) { testCtl(t, putTest, withCfg(configClientTLS)) } +func TestCtlV3PutPeerTLS(t *testing.T) { testCtl(t, putTest, withCfg(configPeerTLS)) } -func TestCtlV3Watch(t *testing.T) { testCtl(t, watchTest) } -func TestCtlV3WatchAutoTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configAutoTLS)) } -func TestCtlV3WatchPeerTLS(t *testing.T) { testCtl(t, watchTest, withCfg(configPeerTLS)) } +func TestCtlV3PutTimeout(t *testing.T) { testCtl(t, putTest, withDialTimeout(0)) } -// TODO: Watch with client TLS is not working -// func TestCtlV3WatchClientTLS(t *testing.T) { -// testCtl(t, watchTest, withCfg(configClientTLS)) -// } +func TestCtlV3Get(t *testing.T) { testCtl(t, getTest) } +func TestCtlV3GetNoTLS(t *testing.T) { testCtl(t, getTest, withCfg(configNoTLS)) } +func TestCtlV3GetClientTLS(t *testing.T) { testCtl(t, getTest, withCfg(configClientTLS)) } +func TestCtlV3GetPeerTLS(t *testing.T) { testCtl(t, getTest, withCfg(configPeerTLS)) } -func TestCtlV3WatchInteractive(t *testing.T) { testCtl(t, watchTest, withInteractive()) } -func TestCtlV3WatchInteractiveAutoTLS(t *testing.T) { - testCtl(t, watchTest, withInteractive(), withCfg(configAutoTLS)) +func TestCtlV3GetPrefix(t *testing.T) { testCtl(t, getTest, withPrefix()) } +func TestCtlV3GetPrefixLimit(t *testing.T) { testCtl(t, getTest, withPrefix(), withLimit(2)) } +func TestCtlV3GetQuorum(t *testing.T) { testCtl(t, getTest, withQuorum()) } + +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 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)) } -// TODO: Watch with client TLS is not working -// func TestCtlV3WatchInteractiveClientTLS(t *testing.T) { -// testCtl(t, watchTest, withInteractive(), withCfg(configClientTLS)) -// } - type ctlCtx struct { t *testing.T cfg etcdProcessClusterConfig @@ -62,9 +67,12 @@ type ctlCtx struct { errc chan error dialTimeout time.Duration - quorum bool + prefix bool + quorum bool // if true, set up 3-node cluster and linearizable read interactive bool watchRevision int + + limit int } type ctlOption func(*ctlCtx) @@ -83,6 +91,10 @@ func withDialTimeout(timeout time.Duration) ctlOption { return func(cx *ctlCtx) { cx.dialTimeout = timeout } } +func withPrefix() ctlOption { + return func(cx *ctlCtx) { cx.prefix = true } +} + func withQuorum() ctlOption { return func(cx *ctlCtx) { cx.quorum = true } } @@ -95,6 +107,10 @@ func withWatchRevision(rev int) ctlOption { return func(cx *ctlCtx) { cx.watchRevision = rev } } +func withLimit(limit int) ctlOption { + return func(cx *ctlCtx) { cx.limit = limit } +} + func setupCtlV3Test(t *testing.T, cfg etcdProcessClusterConfig, quorum bool) *etcdProcessCluster { mustEtcdctl(t) if !quorum { @@ -116,7 +132,7 @@ func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) { ) ret := ctlCtx{ t: t, - cfg: configNoTLS, + cfg: configAutoTLS, errc: make(chan error, 1), dialTimeout: defaultDialTimeout, watchRevision: defaultWatchRevision, @@ -149,43 +165,71 @@ func testCtl(t *testing.T, testFunc func(ctlCtx), opts ...ctlOption) { } func putTest(cx ctlCtx) { - key, value := "foo", "bar" - defer close(cx.errc) + key, value := "foo", "bar" + if err := ctlV3Put(cx, key, value); err != nil { if cx.dialTimeout > 0 && isGRPCTimedout(err) { - cx.errc <- fmt.Errorf("put error (%v)", err) - return + cx.t.Fatalf("putTest error (%v)", err) } } - if err := ctlV3Get(cx, key, value); err != nil { + if err := ctlV3Get(cx, key, kv{key, value}); err != nil { if cx.dialTimeout > 0 && isGRPCTimedout(err) { - cx.errc <- fmt.Errorf("get error (%v)", err) - return + cx.t.Fatalf("putTest error (%v)", err) } } } func watchTest(cx ctlCtx) { - key, value := "foo", "bar" - defer close(cx.errc) + key, value := "foo", "bar" + go func() { if err := ctlV3Put(cx, key, value); err != nil { - cx.t.Fatal(err) + cx.t.Fatalf("watchTest error (%v)", err) } }() if err := ctlV3Watch(cx, key, value); err != nil { if cx.dialTimeout > 0 && isGRPCTimedout(err) { - cx.errc <- fmt.Errorf("watch error (%v)", err) - return + cx.t.Fatalf("watchTest error (%v)", err) } } } +func getTest(cx ctlCtx) { + defer close(cx.errc) + + var ( + kvs = []kv{{"key1", "val1"}, {"key2", "val2"}, {"key3", "val3"}} + ) + + for i := range kvs { + if err := ctlV3Put(cx, kvs[i].key, kvs[i].val); err != nil { + if cx.dialTimeout > 0 && isGRPCTimedout(err) { + cx.t.Fatalf("getTest error (%v)", err) + } + } + } + + if cx.limit > 0 { + kvs = kvs[:cx.limit] + } + keyToGet := "key" + if !cx.prefix { + keyToGet = "key1" + kvs = kvs[:1] + } + // TODO: configure order, sort-by + + if err := ctlV3Get(cx, keyToGet, kvs...); err != nil { + if cx.dialTimeout > 0 && isGRPCTimedout(err) { + cx.t.Fatalf("getTest error (%v)", err) + } + } +} func ctlV3PrefixArgs(clus *etcdProcessCluster, dialTimeout time.Duration) []string { if len(clus.proxies()) > 0 { // TODO: add proxy check as in v2 panic("v3 proxy not implemented") @@ -211,12 +255,28 @@ func ctlV3Put(cx ctlCtx, key, value string) error { return spawnWithExpect(cmdArgs, "OK") } -func ctlV3Get(cx ctlCtx, key, value string) error { +type kv struct { + key, val string +} + +func ctlV3Get(cx ctlCtx, key string, kvs ...kv) error { cmdArgs := append(ctlV3PrefixArgs(cx.epc, cx.dialTimeout), "get", key) if !cx.quorum { cmdArgs = append(cmdArgs, "--consistency", "s") } - return spawnWithExpects(cmdArgs, key, value) + if cx.prefix { + cmdArgs = append(cmdArgs, "--prefix") + } + if cx.limit > 0 { + cmdArgs = append(cmdArgs, "--limit", strconv.Itoa(cx.limit)) + } + // TODO: configure order, sort-by + + var lines []string + for _, elem := range kvs { + lines = append(lines, elem.key, elem.val) + } + return spawnWithExpects(cmdArgs, lines...) } func ctlV3Watch(cx ctlCtx, key, value string) error {