Browse Source

e2e: use pkg/expect

Anthony Romano 9 years ago
parent
commit
5022dce31a
3 changed files with 37 additions and 65 deletions
  1. 12 43
      e2e/etcd_test.go
  2. 11 11
      e2e/etcdctl_test.go
  3. 14 11
      e2e/etcdctlv3_test.go

+ 12 - 43
e2e/etcd_test.go

@@ -23,9 +23,9 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/coreos/etcd/pkg/expect"
 	"github.com/coreos/etcd/pkg/fileutil"
 	"github.com/coreos/etcd/pkg/fileutil"
 	"github.com/coreos/etcd/pkg/testutil"
 	"github.com/coreos/etcd/pkg/testutil"
-	"github.com/coreos/gexpect"
 )
 )
 
 
 const (
 const (
@@ -190,15 +190,15 @@ func cURLPrefixArgsUseTLS(clus *etcdProcessCluster, key string) []string {
 
 
 func cURLPut(clus *etcdProcessCluster, key, val, expected string) error {
 func cURLPut(clus *etcdProcessCluster, key, val, expected string) error {
 	args := append(cURLPrefixArgs(clus, key), "-XPUT", "-d", "value="+val)
 	args := append(cURLPrefixArgs(clus, key), "-XPUT", "-d", "value="+val)
-	return spawnWithExpectedString(args, expected)
+	return spawnWithExpect(args, expected)
 }
 }
 
 
 func cURLGet(clus *etcdProcessCluster, key, expected string) error {
 func cURLGet(clus *etcdProcessCluster, key, expected string) error {
-	return spawnWithExpectedString(cURLPrefixArgs(clus, key), expected)
+	return spawnWithExpect(cURLPrefixArgs(clus, key), expected)
 }
 }
 
 
 func cURLGetUseTLS(clus *etcdProcessCluster, key, expected string) error {
 func cURLGetUseTLS(clus *etcdProcessCluster, key, expected string) error {
-	return spawnWithExpectedString(cURLPrefixArgsUseTLS(clus, key), expected)
+	return spawnWithExpect(cURLPrefixArgsUseTLS(clus, key), expected)
 }
 }
 
 
 type etcdProcessCluster struct {
 type etcdProcessCluster struct {
@@ -208,7 +208,7 @@ type etcdProcessCluster struct {
 
 
 type etcdProcess struct {
 type etcdProcess struct {
 	cfg   *etcdProcessConfig
 	cfg   *etcdProcessConfig
-	proc  *gexpect.ExpectSubprocess
+	proc  *expect.ExpectProcess
 	donec chan struct{} // closed when Interact() terminates
 	donec chan struct{} // closed when Interact() terminates
 }
 }
 
 
@@ -260,17 +260,8 @@ func newEtcdProcessCluster(cfg *etcdProcessClusterConfig) (*etcdProcessCluster,
 				// rs = "proxy: listening for client requests on"
 				// rs = "proxy: listening for client requests on"
 				rs = "proxy: endpoints found"
 				rs = "proxy: endpoints found"
 			}
 			}
-			ok, err := etcdp.proc.ExpectRegex(rs)
-			if err != nil {
-				readyC <- err
-			} else if !ok {
-				readyC <- fmt.Errorf("couldn't get expected output: '%s'", rs)
-			} else {
-				readyC <- nil
-			}
-			etcdp.proc.ReadLine()
-			etcdp.proc.Interact() // this blocks(leaks) if another goroutine is reading
-			etcdp.proc.ReadLine() // wait for leaky goroutine to accept an EOF
+			_, err := etcdp.proc.Expect(rs)
+			readyC <- err
 			close(etcdp.donec)
 			close(etcdp.donec)
 		}(epc.procs[i])
 		}(epc.procs[i])
 	}
 	}
@@ -424,10 +415,10 @@ func (epc *etcdProcessCluster) Close() (err error) {
 	return err
 	return err
 }
 }
 
 
-func spawnCmd(args []string) (*gexpect.ExpectSubprocess, error) {
-	// redirect stderr to stdout since gexpect only uses stdout
-	cmd := `/bin/sh -c "` + strings.Join(args, " ") + ` 2>&1 "`
-	return gexpect.Spawn(cmd)
+func spawnCmd(args []string) (*expect.ExpectProcess, error) {
+	// redirect stderr to stdout since expect only uses stdout
+	cmdargs := append([]string{"-c"}, strings.Join(append(args, "2>&1"), " "))
+	return expect.NewExpect("/bin/sh", cmdargs...)
 }
 }
 
 
 func spawnWithExpect(args []string, expected string) error {
 func spawnWithExpect(args []string, expected string) error {
@@ -435,33 +426,11 @@ func spawnWithExpect(args []string, expected string) error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	ok, err := proc.ExpectRegex(expected)
-	perr := proc.Close()
-	if err != nil {
-		return err
-	}
-	if !ok {
-		return fmt.Errorf("couldn't get expected output: '%s'", expected)
-	}
-	return perr
-}
-
-// spawnWithExpectedString compares outputs in string format.
-// This is useful when gexpect does not match regex correctly with
-// some UTF-8 format characters.
-func spawnWithExpectedString(args []string, expected string) error {
-	proc, err := spawnCmd(args)
-	if err != nil {
-		return err
-	}
-	s, err := proc.ReadLine()
+	_, err = proc.Expect(expected)
 	perr := proc.Close()
 	perr := proc.Close()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	if !strings.Contains(s, expected) {
-		return fmt.Errorf("expected %q, got %q", expected, s)
-	}
 	return perr
 	return perr
 }
 }
 
 

+ 11 - 11
e2e/etcdctl_test.go

@@ -243,15 +243,15 @@ func etcdctlPrefixArgs(clus *etcdProcessCluster) []string {
 
 
 func etcdctlSet(clus *etcdProcessCluster, key, value string) error {
 func etcdctlSet(clus *etcdProcessCluster, key, value string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "set", key, value)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "set", key, value)
-	return spawnWithExpectedString(cmdArgs, value)
+	return spawnWithExpect(cmdArgs, value)
 }
 }
 
 
 func etcdctlMk(clus *etcdProcessCluster, key, value string, first bool) error {
 func etcdctlMk(clus *etcdProcessCluster, key, value string, first bool) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "mk", key, value)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "mk", key, value)
 	if first {
 	if first {
-		return spawnWithExpectedString(cmdArgs, value)
+		return spawnWithExpect(cmdArgs, value)
 	}
 	}
-	return spawnWithExpectedString(cmdArgs, "Error:  105: Key already exists")
+	return spawnWithExpect(cmdArgs, "Error:  105: Key already exists")
 }
 }
 
 
 func etcdctlGet(clus *etcdProcessCluster, key, value string, quorum bool) error {
 func etcdctlGet(clus *etcdProcessCluster, key, value string, quorum bool) error {
@@ -259,13 +259,13 @@ func etcdctlGet(clus *etcdProcessCluster, key, value string, quorum bool) error
 	if quorum {
 	if quorum {
 		cmdArgs = append(cmdArgs, "--quorum")
 		cmdArgs = append(cmdArgs, "--quorum")
 	}
 	}
-	return spawnWithExpectedString(cmdArgs, value)
+	return spawnWithExpect(cmdArgs, value)
 }
 }
 
 
 func etcdctlRm(clus *etcdProcessCluster, key, value string, first bool) error {
 func etcdctlRm(clus *etcdProcessCluster, key, value string, first bool) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "rm", key)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "rm", key)
 	if first {
 	if first {
-		return spawnWithExpectedString(cmdArgs, "PrevNode.Value: "+value)
+		return spawnWithExpect(cmdArgs, "PrevNode.Value: "+value)
 	}
 	}
 	return spawnWithExpect(cmdArgs, "Error:  100: Key not found")
 	return spawnWithExpect(cmdArgs, "Error:  100: Key not found")
 }
 }
@@ -292,32 +292,32 @@ func etcdctlWatch(clus *etcdProcessCluster, key, value string, noSync bool) <-ch
 
 
 func etcdctlRoleAdd(clus *etcdProcessCluster, role string) error {
 func etcdctlRoleAdd(clus *etcdProcessCluster, role string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "role", "add", role)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "role", "add", role)
-	return spawnWithExpectedString(cmdArgs, role)
+	return spawnWithExpect(cmdArgs, role)
 }
 }
 
 
 func etcdctlRoleList(clus *etcdProcessCluster, expectedRole string) error {
 func etcdctlRoleList(clus *etcdProcessCluster, expectedRole string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "role", "list")
 	cmdArgs := append(etcdctlPrefixArgs(clus), "role", "list")
-	return spawnWithExpectedString(cmdArgs, expectedRole)
+	return spawnWithExpect(cmdArgs, expectedRole)
 }
 }
 
 
 func etcdctlUserAdd(clus *etcdProcessCluster, user, pass string) error {
 func etcdctlUserAdd(clus *etcdProcessCluster, user, pass string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "add", user+":"+pass)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "add", user+":"+pass)
-	return spawnWithExpectedString(cmdArgs, "User "+user+" created")
+	return spawnWithExpect(cmdArgs, "User "+user+" created")
 }
 }
 
 
 func etcdctlUserGrant(clus *etcdProcessCluster, user, role string) error {
 func etcdctlUserGrant(clus *etcdProcessCluster, user, role string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "grant", "--roles", role, user)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "grant", "--roles", role, user)
-	return spawnWithExpectedString(cmdArgs, "User "+user+" updated")
+	return spawnWithExpect(cmdArgs, "User "+user+" updated")
 }
 }
 
 
 func etcdctlUserGet(clus *etcdProcessCluster, user string) error {
 func etcdctlUserGet(clus *etcdProcessCluster, user string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "get", user)
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "get", user)
-	return spawnWithExpectedString(cmdArgs, "User: "+user)
+	return spawnWithExpect(cmdArgs, "User: "+user)
 }
 }
 
 
 func etcdctlUserList(clus *etcdProcessCluster, expectedUser string) error {
 func etcdctlUserList(clus *etcdProcessCluster, expectedUser string) error {
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "list")
 	cmdArgs := append(etcdctlPrefixArgs(clus), "user", "list")
-	return spawnWithExpectedString(cmdArgs, expectedUser)
+	return spawnWithExpect(cmdArgs, expectedUser)
 }
 }
 
 
 func mustEtcdctl(t *testing.T) {
 func mustEtcdctl(t *testing.T) {

+ 14 - 11
e2e/etcdctlv3_test.go

@@ -15,6 +15,7 @@
 package e2e
 package e2e
 
 
 import (
 import (
+	"fmt"
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
@@ -69,23 +70,22 @@ func testCtlV3Set(t *testing.T, cfg *etcdProcessClusterConfig, dialTimeout time.
 
 
 	key, value := "foo", "bar"
 	key, value := "foo", "bar"
 
 
-	donec := make(chan struct{})
+	errc := make(chan error, 1)
+	expectTimeout := dialTimeout > 0 && dialTimeout <= time.Nanosecond
 	go func() {
 	go func() {
+		defer close(errc)
 		if err := ctlV3Put(epc, key, value, dialTimeout); err != nil {
 		if err := ctlV3Put(epc, key, value, dialTimeout); err != nil {
-			if dialTimeout > 0 && dialTimeout <= time.Nanosecond && isGRPCTimedout(err) { // timeout expected
-				donec <- struct{}{}
+			if expectTimeout && isGRPCTimedout(err) {
+				errc <- fmt.Errorf("put error (%v)", err)
 				return
 				return
 			}
 			}
-			t.Fatalf("put error (%v)", err)
 		}
 		}
 		if err := ctlV3Get(epc, key, value, dialTimeout, quorum); err != nil {
 		if err := ctlV3Get(epc, key, value, dialTimeout, quorum); err != nil {
-			if dialTimeout > 0 && dialTimeout <= time.Nanosecond && isGRPCTimedout(err) { // timeout expected
-				donec <- struct{}{}
+			if expectTimeout && isGRPCTimedout(err) {
+				errc <- fmt.Errorf("get error (%v)", err)
 				return
 				return
 			}
 			}
-			t.Fatalf("get error (%v)", err)
 		}
 		}
-		donec <- struct{}{}
 	}()
 	}()
 
 
 	select {
 	select {
@@ -93,7 +93,10 @@ func testCtlV3Set(t *testing.T, cfg *etcdProcessClusterConfig, dialTimeout time.
 		if dialTimeout > 0 {
 		if dialTimeout > 0 {
 			t.Fatalf("test timed out for %v", dialTimeout)
 			t.Fatalf("test timed out for %v", dialTimeout)
 		}
 		}
-	case <-donec:
+	case err := <-errc:
+		if err != nil {
+			t.Fatal(err)
+		}
 	}
 	}
 }
 }
 
 
@@ -119,7 +122,7 @@ func ctlV3PrefixArgs(clus *etcdProcessCluster, dialTimeout time.Duration) []stri
 
 
 func ctlV3Put(clus *etcdProcessCluster, key, value string, dialTimeout time.Duration) error {
 func ctlV3Put(clus *etcdProcessCluster, key, value string, dialTimeout time.Duration) error {
 	cmdArgs := append(ctlV3PrefixArgs(clus, dialTimeout), "put", key, value)
 	cmdArgs := append(ctlV3PrefixArgs(clus, dialTimeout), "put", key, value)
-	return spawnWithExpectedString(cmdArgs, "OK")
+	return spawnWithExpect(cmdArgs, "OK")
 }
 }
 
 
 func ctlV3Get(clus *etcdProcessCluster, key, value string, dialTimeout time.Duration, quorum bool) error {
 func ctlV3Get(clus *etcdProcessCluster, key, value string, dialTimeout time.Duration, quorum bool) error {
@@ -128,7 +131,7 @@ func ctlV3Get(clus *etcdProcessCluster, key, value string, dialTimeout time.Dura
 		cmdArgs = append(cmdArgs, "--consistency", "s")
 		cmdArgs = append(cmdArgs, "--consistency", "s")
 	}
 	}
 	// TODO: match by value. Currently it prints out both key and value in multi-lines.
 	// TODO: match by value. Currently it prints out both key and value in multi-lines.
-	return spawnWithExpectedString(cmdArgs, key)
+	return spawnWithExpect(cmdArgs, key)
 }
 }
 
 
 func setupCtlV3Test(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) *etcdProcessCluster {
 func setupCtlV3Test(t *testing.T, cfg *etcdProcessClusterConfig, quorum bool) *etcdProcessCluster {