Browse Source

Mock Hijack and Implement Unit test for Attach

Guillaume J. Charmes 12 năm trước cách đây
mục cha
commit
15ae314cbb
2 tập tin đã thay đổi với 121 bổ sung10 xóa
  1. 116 3
      api_test.go
  2. 5 7
      commands_test.go

+ 116 - 3
api_test.go

@@ -702,8 +702,94 @@ func TestPostContainersWait(t *testing.T) {
 }
 
 func TestPostContainersAttach(t *testing.T) {
-	//FIXME: Implement this test
-	t.Log("Test on implemented")
+	runtime, err := newTestRuntime()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer nuke(runtime)
+
+	srv := &Server{runtime: runtime}
+
+	container, err := NewBuilder(runtime).Create(
+		&Config{
+			Image:     GetTestImage(runtime).Id,
+			Cmd:       []string{"/bin/cat"},
+			OpenStdin: true,
+		},
+	)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer runtime.Destroy(container)
+
+	// Start the process
+	if err := container.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	stdin, stdinPipe := io.Pipe()
+	stdout, stdoutPipe := io.Pipe()
+
+	// Attach to it
+	c1 := make(chan struct{})
+	go func() {
+		// We're simulating a disconnect so the return value doesn't matter. What matters is the
+		// fact that CmdAttach returns.
+
+		r := &hijackTester{
+			ResponseRecorder: httptest.NewRecorder(),
+			in:               stdin,
+			out:              stdoutPipe,
+		}
+
+		req, err := http.NewRequest("POST", "/containers/"+container.Id+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		body, err := postContainersAttach(srv, r, req, map[string]string{"name": container.Id})
+		close(c1)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if body != nil {
+			t.Fatalf("No body expected, received: %s\n", body)
+		}
+	}()
+
+	// Acknowledge hijack
+	setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
+		stdout.Read([]byte{})
+		stdout.Read(make([]byte, 4096))
+	})
+
+	setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	// Close pipes (client disconnects)
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
+		t.Fatal(err)
+	}
+
+	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
+	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
+		<-c1
+	})
+
+	// We closed stdin, expect /bin/cat to still be running
+	// Wait a little bit to make sure container.monitor() did his thing
+	err = container.WaitTimeout(500 * time.Millisecond)
+	if err == nil || !container.State.Running {
+		t.Fatalf("/bin/cat is not running after closing stdin")
+	}
+
+	// Try to avoid the timeoout in destroy. Best effort, don't check error
+	cStdin, _ := container.StdinPipe()
+	cStdin.Close()
+	container.Wait()
 }
 
 // FIXME: Test deleting runnign container
@@ -760,5 +846,32 @@ func TestDeleteContainers(t *testing.T) {
 
 func TestDeleteImages(t *testing.T) {
 	//FIXME: Implement this test
-	t.Log("Test on implemented")
+	t.Log("Test not implemented")
+}
+
+// Mocked types for tests
+type NopConn struct {
+	io.ReadCloser
+	io.Writer
+}
+
+func (c *NopConn) LocalAddr() net.Addr                { return nil }
+func (c *NopConn) RemoteAddr() net.Addr               { return nil }
+func (c *NopConn) SetDeadline(t time.Time) error      { return nil }
+func (c *NopConn) SetReadDeadline(t time.Time) error  { return nil }
+func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
+
+type hijackTester struct {
+	*httptest.ResponseRecorder
+	in  io.ReadCloser
+	out io.Writer
+}
+
+func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+	bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
+	conn := &NopConn{
+		ReadCloser: t.in,
+		Writer:     t.out,
+	}
+	return conn, bufrw, nil
 }

+ 5 - 7
commands_test.go

@@ -1,17 +1,15 @@
 package docker
 
 import (
-	/*"bufio"
+	"bufio"
 	"fmt"
-	"github.com/dotcloud/docker/rcli"
 	"io"
-	"io/ioutil"
-	"strings"*/
+	_ "io/ioutil"
+	"strings"
 	"testing"
 	"time"
 )
 
-/*TODO
 func closeWrap(args ...io.Closer) error {
 	e := false
 	ret := fmt.Errorf("Error closing elements")
@@ -26,7 +24,7 @@ func closeWrap(args ...io.Closer) error {
 	}
 	return nil
 }
-*/
+
 func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
 	c := make(chan bool)
 
@@ -44,7 +42,6 @@ func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
 	}
 }
 
-/*TODO
 func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
 	for i := 0; i < count; i++ {
 		if _, err := w.Write([]byte(input)); err != nil {
@@ -61,6 +58,7 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error
 	return nil
 }
 
+/*TODO
 func cmdWait(srv *Server, container *Container) error {
 	stdout, stdoutPipe := io.Pipe()