github.com/boynux/docker@v1.11.0-rc4/integration-cli/docker_api_attach_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "io" 6 "net" 7 "net/http" 8 "strings" 9 "time" 10 11 "github.com/docker/docker/pkg/integration/checker" 12 "github.com/go-check/check" 13 "golang.org/x/net/websocket" 14 ) 15 16 func (s *DockerSuite) TestGetContainersAttachWebsocket(c *check.C) { 17 testRequires(c, DaemonIsLinux) 18 out, _ := dockerCmd(c, "run", "-dit", "busybox", "cat") 19 20 rwc, err := sockConn(time.Duration(10 * time.Second)) 21 c.Assert(err, checker.IsNil) 22 23 cleanedContainerID := strings.TrimSpace(out) 24 config, err := websocket.NewConfig( 25 "/containers/"+cleanedContainerID+"/attach/ws?stream=1&stdin=1&stdout=1&stderr=1", 26 "http://localhost", 27 ) 28 c.Assert(err, checker.IsNil) 29 30 ws, err := websocket.NewClient(config, rwc) 31 c.Assert(err, checker.IsNil) 32 defer ws.Close() 33 34 expected := []byte("hello") 35 actual := make([]byte, len(expected)) 36 37 outChan := make(chan error) 38 go func() { 39 _, err := ws.Read(actual) 40 outChan <- err 41 close(outChan) 42 }() 43 44 inChan := make(chan error) 45 go func() { 46 _, err := ws.Write(expected) 47 inChan <- err 48 close(inChan) 49 }() 50 51 select { 52 case err := <-inChan: 53 c.Assert(err, checker.IsNil) 54 case <-time.After(5 * time.Second): 55 c.Fatal("Timeout writing to ws") 56 } 57 58 select { 59 case err := <-outChan: 60 c.Assert(err, checker.IsNil) 61 case <-time.After(5 * time.Second): 62 c.Fatal("Timeout reading from ws") 63 } 64 65 c.Assert(actual, checker.DeepEquals, expected, check.Commentf("Websocket didn't return the expected data")) 66 } 67 68 // regression gh14320 69 func (s *DockerSuite) TestPostContainersAttachContainerNotFound(c *check.C) { 70 status, body, err := sockRequest("POST", "/containers/doesnotexist/attach", nil) 71 c.Assert(status, checker.Equals, http.StatusNotFound) 72 c.Assert(err, checker.IsNil) 73 expected := "No such container: doesnotexist\n" 74 c.Assert(string(body), checker.Contains, expected) 75 } 76 77 func (s *DockerSuite) TestGetContainersWsAttachContainerNotFound(c *check.C) { 78 status, body, err := sockRequest("GET", "/containers/doesnotexist/attach/ws", nil) 79 c.Assert(status, checker.Equals, http.StatusNotFound) 80 c.Assert(err, checker.IsNil) 81 expected := "No such container: doesnotexist\n" 82 c.Assert(string(body), checker.Contains, expected) 83 } 84 85 func (s *DockerSuite) TestPostContainersAttach(c *check.C) { 86 testRequires(c, DaemonIsLinux) 87 88 expectSuccess := func(conn net.Conn, br *bufio.Reader, stream string, tty bool) { 89 defer conn.Close() 90 expected := []byte("success") 91 _, err := conn.Write(expected) 92 c.Assert(err, checker.IsNil) 93 94 conn.SetReadDeadline(time.Now().Add(time.Second)) 95 lenHeader := 0 96 if !tty { 97 lenHeader = 8 98 } 99 actual := make([]byte, len(expected)+lenHeader) 100 _, err = io.ReadFull(br, actual) 101 c.Assert(err, checker.IsNil) 102 if !tty { 103 fdMap := map[string]byte{ 104 "stdin": 0, 105 "stdout": 1, 106 "stderr": 2, 107 } 108 c.Assert(actual[0], checker.Equals, fdMap[stream]) 109 } 110 c.Assert(actual[lenHeader:], checker.DeepEquals, expected, check.Commentf("Attach didn't return the expected data from %s", stream)) 111 } 112 113 expectTimeout := func(conn net.Conn, br *bufio.Reader, stream string) { 114 defer conn.Close() 115 _, err := conn.Write([]byte{'t'}) 116 c.Assert(err, checker.IsNil) 117 118 conn.SetReadDeadline(time.Now().Add(time.Second)) 119 actual := make([]byte, 1) 120 _, err = io.ReadFull(br, actual) 121 opErr, ok := err.(*net.OpError) 122 c.Assert(ok, checker.Equals, true, check.Commentf("Error is expected to be *net.OpError, got %v", err)) 123 c.Assert(opErr.Timeout(), checker.Equals, true, check.Commentf("Read from %s is expected to timeout", stream)) 124 } 125 126 // Create a container that only emits stdout. 127 cid, _ := dockerCmd(c, "run", "-di", "busybox", "cat") 128 cid = strings.TrimSpace(cid) 129 // Attach to the container's stdout stream. 130 conn, br, err := sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain") 131 c.Assert(err, checker.IsNil) 132 // Check if the data from stdout can be received. 133 expectSuccess(conn, br, "stdout", false) 134 // Attach to the container's stderr stream. 135 conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain") 136 c.Assert(err, checker.IsNil) 137 // Since the container only emits stdout, attaching to stderr should return nothing. 138 expectTimeout(conn, br, "stdout") 139 140 // Test the similar functions of the stderr stream. 141 cid, _ = dockerCmd(c, "run", "-di", "busybox", "/bin/sh", "-c", "cat >&2") 142 cid = strings.TrimSpace(cid) 143 conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain") 144 c.Assert(err, checker.IsNil) 145 expectSuccess(conn, br, "stderr", false) 146 conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain") 147 c.Assert(err, checker.IsNil) 148 expectTimeout(conn, br, "stderr") 149 150 // Test with tty. 151 cid, _ = dockerCmd(c, "run", "-dit", "busybox", "/bin/sh", "-c", "cat >&2") 152 cid = strings.TrimSpace(cid) 153 // Attach to stdout only. 154 conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stdout=1", nil, "text/plain") 155 c.Assert(err, checker.IsNil) 156 expectSuccess(conn, br, "stdout", true) 157 158 // Attach without stdout stream. 159 conn, br, err = sockRequestHijack("POST", "/containers/"+cid+"/attach?stream=1&stdin=1&stderr=1", nil, "text/plain") 160 c.Assert(err, checker.IsNil) 161 // Nothing should be received because both the stdout and stderr of the container will be 162 // sent to the client as stdout when tty is enabled. 163 expectTimeout(conn, br, "stdout") 164 }