github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/integration-cli/docker_cli_attach_unix_test.go (about) 1 // +build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "os/exec" 8 "strings" 9 "time" 10 11 "github.com/docker/docker/pkg/integration/checker" 12 "github.com/docker/docker/pkg/stringid" 13 "github.com/go-check/check" 14 "github.com/kr/pty" 15 ) 16 17 // #9860 Make sure attach ends when container ends (with no errors) 18 func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) { 19 20 out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`) 21 22 id := strings.TrimSpace(out) 23 c.Assert(waitRun(id), check.IsNil) 24 25 _, tty, err := pty.Open() 26 c.Assert(err, check.IsNil) 27 28 attachCmd := exec.Command(dockerBinary, "attach", id) 29 attachCmd.Stdin = tty 30 attachCmd.Stdout = tty 31 attachCmd.Stderr = tty 32 err = attachCmd.Start() 33 c.Assert(err, check.IsNil) 34 35 errChan := make(chan error) 36 go func() { 37 defer close(errChan) 38 // Container is waiting for us to signal it to stop 39 dockerCmd(c, "stop", id) 40 // And wait for the attach command to end 41 errChan <- attachCmd.Wait() 42 }() 43 44 // Wait for the docker to end (should be done by the 45 // stop command in the go routine) 46 dockerCmd(c, "wait", id) 47 48 select { 49 case err := <-errChan: 50 c.Assert(err, check.IsNil) 51 case <-time.After(attachWait): 52 c.Fatal("timed out without attach returning") 53 } 54 55 } 56 57 func (s *DockerSuite) TestAttachAfterDetach(c *check.C) { 58 59 name := "detachtest" 60 61 cpty, tty, err := pty.Open() 62 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err)) 63 cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox") 64 cmd.Stdin = tty 65 cmd.Stdout = tty 66 cmd.Stderr = tty 67 68 errChan := make(chan error) 69 go func() { 70 errChan <- cmd.Run() 71 close(errChan) 72 }() 73 74 c.Assert(waitRun(name), check.IsNil) 75 76 cpty.Write([]byte{16}) 77 time.Sleep(100 * time.Millisecond) 78 cpty.Write([]byte{17}) 79 80 select { 81 case err := <-errChan: 82 c.Assert(err, check.IsNil) 83 case <-time.After(5 * time.Second): 84 c.Fatal("timeout while detaching") 85 } 86 87 cpty, tty, err = pty.Open() 88 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err)) 89 90 cmd = exec.Command(dockerBinary, "attach", name) 91 cmd.Stdin = tty 92 cmd.Stdout = tty 93 cmd.Stderr = tty 94 95 err = cmd.Start() 96 c.Assert(err, checker.IsNil) 97 98 bytes := make([]byte, 10) 99 var nBytes int 100 readErr := make(chan error, 1) 101 102 go func() { 103 time.Sleep(500 * time.Millisecond) 104 cpty.Write([]byte("\n")) 105 time.Sleep(500 * time.Millisecond) 106 107 nBytes, err = cpty.Read(bytes) 108 cpty.Close() 109 readErr <- err 110 }() 111 112 select { 113 case err := <-readErr: 114 c.Assert(err, check.IsNil) 115 case <-time.After(2 * time.Second): 116 c.Fatal("timeout waiting for attach read") 117 } 118 119 err = cmd.Wait() 120 c.Assert(err, checker.IsNil) 121 122 c.Assert(string(bytes[:nBytes]), checker.Contains, "/ #") 123 124 } 125 126 // TestAttachDetach checks that attach in tty mode can be detached using the long container ID 127 func (s *DockerSuite) TestAttachDetach(c *check.C) { 128 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 129 id := strings.TrimSpace(out) 130 c.Assert(waitRun(id), check.IsNil) 131 132 cpty, tty, err := pty.Open() 133 c.Assert(err, check.IsNil) 134 defer cpty.Close() 135 136 cmd := exec.Command(dockerBinary, "attach", id) 137 cmd.Stdin = tty 138 stdout, err := cmd.StdoutPipe() 139 c.Assert(err, check.IsNil) 140 defer stdout.Close() 141 err = cmd.Start() 142 c.Assert(err, check.IsNil) 143 c.Assert(waitRun(id), check.IsNil) 144 145 _, err = cpty.Write([]byte("hello\n")) 146 c.Assert(err, check.IsNil) 147 out, err = bufio.NewReader(stdout).ReadString('\n') 148 c.Assert(err, check.IsNil) 149 c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out)) 150 151 // escape sequence 152 _, err = cpty.Write([]byte{16}) 153 c.Assert(err, checker.IsNil) 154 time.Sleep(100 * time.Millisecond) 155 _, err = cpty.Write([]byte{17}) 156 c.Assert(err, checker.IsNil) 157 158 ch := make(chan struct{}) 159 go func() { 160 cmd.Wait() 161 ch <- struct{}{} 162 }() 163 164 running, err := inspectField(id, "State.Running") 165 c.Assert(err, checker.IsNil) 166 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 167 168 go func() { 169 dockerCmd(c, "kill", id) 170 }() 171 172 select { 173 case <-ch: 174 case <-time.After(10 * time.Millisecond): 175 c.Fatal("timed out waiting for container to exit") 176 } 177 178 } 179 180 // TestAttachDetachTruncatedID checks that attach in tty mode can be detached 181 func (s *DockerSuite) TestAttachDetachTruncatedID(c *check.C) { 182 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 183 id := stringid.TruncateID(strings.TrimSpace(out)) 184 c.Assert(waitRun(id), check.IsNil) 185 186 cpty, tty, err := pty.Open() 187 c.Assert(err, checker.IsNil) 188 defer cpty.Close() 189 190 cmd := exec.Command(dockerBinary, "attach", id) 191 cmd.Stdin = tty 192 stdout, err := cmd.StdoutPipe() 193 c.Assert(err, checker.IsNil) 194 defer stdout.Close() 195 err = cmd.Start() 196 c.Assert(err, checker.IsNil) 197 198 _, err = cpty.Write([]byte("hello\n")) 199 c.Assert(err, checker.IsNil) 200 out, err = bufio.NewReader(stdout).ReadString('\n') 201 c.Assert(err, checker.IsNil) 202 c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out)) 203 204 // escape sequence 205 _, err = cpty.Write([]byte{16}) 206 c.Assert(err, checker.IsNil) 207 time.Sleep(100 * time.Millisecond) 208 _, err = cpty.Write([]byte{17}) 209 c.Assert(err, checker.IsNil) 210 211 ch := make(chan struct{}) 212 go func() { 213 cmd.Wait() 214 ch <- struct{}{} 215 }() 216 217 running, err := inspectField(id, "State.Running") 218 c.Assert(err, checker.IsNil) 219 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 220 221 go func() { 222 dockerCmd(c, "kill", id) 223 }() 224 225 select { 226 case <-ch: 227 case <-time.After(10 * time.Millisecond): 228 c.Fatal("timed out waiting for container to exit") 229 } 230 231 }