Browse Source

Merge pull request #4939 from gyuho/e2e_txn_version

e2e: etcdctlv3 version, txn basic tests
Gyu-Ho Lee 9 năm trước cách đây
mục cha
commit
bb69dd324e
3 tập tin đã thay đổi với 141 bổ sung5 xóa
  1. 137 1
      e2e/etcdctlv3_test.go
  2. 2 2
      pkg/expect/expect.go
  3. 2 2
      pkg/expect/expect_test.go

+ 137 - 1
e2e/etcdctlv3_test.go

@@ -23,6 +23,7 @@ import (
 	"time"
 
 	"github.com/coreos/etcd/pkg/testutil"
+	"github.com/coreos/etcd/version"
 )
 
 func TestCtlV3Put(t *testing.T)          { testCtl(t, putTest) }
@@ -59,6 +60,27 @@ func TestCtlV3WatchInteractivePeerTLS(t *testing.T) {
 	testCtl(t, watchTest, withInteractive(), withCfg(configPeerTLS))
 }
 
+// TODO: watch by prefix
+
+func TestCtlV3TxnInteractiveSuccess(t *testing.T) {
+	testCtl(t, txnTestSuccess, withInteractive())
+}
+func TestCtlV3TxnInteractiveSuccessNoTLS(t *testing.T) {
+	testCtl(t, txnTestSuccess, withInteractive(), withCfg(configNoTLS))
+}
+func TestCtlV3TxnInteractiveSuccessClientTLS(t *testing.T) {
+	testCtl(t, txnTestSuccess, withInteractive(), withCfg(configClientTLS))
+}
+func TestCtlV3TxnInteractiveSuccessPeerTLS(t *testing.T) {
+	testCtl(t, txnTestSuccess, withInteractive(), withCfg(configPeerTLS))
+}
+
+func TestCtlV3TxnInteractiveFail(t *testing.T) {
+	testCtl(t, txnTestFail, withInteractive())
+}
+
+func TestCtlV3Version(t *testing.T) { testCtl(t, versionTest) }
+
 type ctlCtx struct {
 	t   *testing.T
 	cfg etcdProcessClusterConfig
@@ -199,6 +221,14 @@ func watchTest(cx ctlCtx) {
 	}
 }
 
+func versionTest(cx ctlCtx) {
+	defer close(cx.errc)
+
+	if err := ctlV3Version(cx); err != nil {
+		cx.t.Fatalf("versionTest error (%v)", err)
+	}
+}
+
 func getTest(cx ctlCtx) {
 	defer close(cx.errc)
 
@@ -230,6 +260,42 @@ func getTest(cx ctlCtx) {
 		}
 	}
 }
+
+func txnTestSuccess(cx ctlCtx) {
+	defer close(cx.errc)
+
+	if err := ctlV3Put(cx, "key1", "value1"); err != nil {
+		cx.t.Fatalf("txnTestSuccess error (%v)", err)
+	}
+	if err := ctlV3Put(cx, "key2", "value2"); err != nil {
+		cx.t.Fatalf("txnTestSuccess error (%v)", err)
+	}
+
+	rqs := txnRequests{
+		compare:  []string{`version("key1") = "1"`, `version("key2") = "1"`},
+		ifSucess: []string{"get key1", "get key2"},
+		ifFail:   []string{`put key1 "fail"`, `put key2 "fail"`},
+		results:  []string{"SUCCESS", "key1", "value1", "key2", "value2"},
+	}
+	if err := ctlV3Txn(cx, rqs); err != nil {
+		cx.t.Fatal(err)
+	}
+}
+
+func txnTestFail(cx ctlCtx) {
+	defer close(cx.errc)
+
+	rqs := txnRequests{
+		compare:  []string{`version("key") < "0"`},
+		ifSucess: []string{`put key "success"`},
+		ifFail:   []string{`put key "fail"`},
+		results:  []string{"FAILURE", "OK"},
+	}
+	if err := ctlV3Txn(cx, rqs); err != nil {
+		cx.t.Fatal(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")
@@ -297,7 +363,7 @@ func ctlV3Watch(cx ctlCtx, key, value string) error {
 	if cx.watchRevision > 0 {
 		watchLine = fmt.Sprintf("watch %s --rev %d", key, cx.watchRevision)
 	}
-	if err = proc.SendLine(watchLine); err != nil {
+	if err = proc.Send(watchLine + "\r"); err != nil {
 		return err
 	}
 	_, err = proc.Expect(key)
@@ -311,6 +377,76 @@ func ctlV3Watch(cx ctlCtx, key, value string) error {
 	return proc.Close()
 }
 
+type txnRequests struct {
+	compare  []string
+	ifSucess []string
+	ifFail   []string
+	results  []string
+}
+
+func ctlV3Txn(cx ctlCtx, rqs txnRequests) error {
+	// TODO: support non-interactive mode
+	cmdArgs := append(ctlV3PrefixArgs(cx.epc, cx.dialTimeout), "txn")
+	if cx.interactive {
+		cmdArgs = append(cmdArgs, "--interactive")
+	}
+	proc, err := spawnCmd(cmdArgs)
+	if err != nil {
+		return err
+	}
+	_, err = proc.Expect("compares:")
+	if err != nil {
+		return err
+	}
+	for _, req := range rqs.compare {
+		if err = proc.Send(req + "\r"); err != nil {
+			return err
+		}
+	}
+	if err = proc.Send("\r"); err != nil {
+		return err
+	}
+
+	_, err = proc.Expect("success requests (get, put, delete):")
+	if err != nil {
+		return err
+	}
+	for _, req := range rqs.ifSucess {
+		if err = proc.Send(req + "\r"); err != nil {
+			return err
+		}
+	}
+	if err = proc.Send("\r"); err != nil {
+		return err
+	}
+
+	_, err = proc.Expect("failure requests (get, put, delete):")
+	if err != nil {
+		return err
+	}
+	for _, req := range rqs.ifFail {
+		if err = proc.Send(req + "\r"); err != nil {
+			return err
+		}
+	}
+	if err = proc.Send("\r"); err != nil {
+		return err
+	}
+
+	for _, line := range rqs.results {
+		_, err = proc.Expect(line)
+		if err != nil {
+			return err
+		}
+	}
+	return proc.Close()
+}
+
+func ctlV3Version(cx ctlCtx) error {
+	cmdArgs := append(ctlV3PrefixArgs(cx.epc, cx.dialTimeout), "version")
+	return spawnWithExpect(cmdArgs, version.Version)
+}
+
 func isGRPCTimedout(err error) bool {
 	return strings.Contains(err.Error(), "grpc: timed out trying to connect")
 }

+ 2 - 2
pkg/expect/expect.go

@@ -114,7 +114,7 @@ func (ep *ExpectProcess) Close() error {
 	return err
 }
 
-func (ep *ExpectProcess) SendLine(command string) error {
-	_, err := io.WriteString(ep.fpty, command+"\r\n")
+func (ep *ExpectProcess) Send(command string) error {
+	_, err := io.WriteString(ep.fpty, command)
 	return err
 }

+ 2 - 2
pkg/expect/expect_test.go

@@ -39,13 +39,13 @@ func TestEcho(t *testing.T) {
 	}
 }
 
-func TestSendLine(t *testing.T) {
+func TestSend(t *testing.T) {
 	ep, err := NewExpect("/usr/bin/tr", "a", "b")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ep.Close()
-	if err := ep.SendLine("a"); err != nil {
+	if err := ep.Send("a\r"); err != nil {
 		t.Fatal(err)
 	}
 	_, eerr := ep.Expect("b")