github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/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 testRequires(c, SameHostDaemon) 20 21 out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`) 22 23 id := strings.TrimSpace(out) 24 c.Assert(waitRun(id), check.IsNil) 25 26 _, tty, err := pty.Open() 27 c.Assert(err, check.IsNil) 28 29 attachCmd := exec.Command(dockerBinary, "attach", id) 30 attachCmd.Stdin = tty 31 attachCmd.Stdout = tty 32 attachCmd.Stderr = tty 33 err = attachCmd.Start() 34 c.Assert(err, check.IsNil) 35 36 errChan := make(chan error) 37 go func() { 38 defer close(errChan) 39 // Container is waiting for us to signal it to stop 40 dockerCmd(c, "stop", id) 41 // And wait for the attach command to end 42 errChan <- attachCmd.Wait() 43 }() 44 45 // Wait for the docker to end (should be done by the 46 // stop command in the go routine) 47 dockerCmd(c, "wait", id) 48 49 select { 50 case err := <-errChan: 51 c.Assert(err, check.IsNil) 52 case <-time.After(attachWait): 53 c.Fatal("timed out without attach returning") 54 } 55 56 } 57 58 func (s *DockerSuite) TestAttachAfterDetach(c *check.C) { 59 60 name := "detachtest" 61 62 cpty, tty, err := pty.Open() 63 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err)) 64 cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox") 65 cmd.Stdin = tty 66 cmd.Stdout = tty 67 cmd.Stderr = tty 68 69 errChan := make(chan error) 70 go func() { 71 errChan <- cmd.Run() 72 close(errChan) 73 }() 74 75 c.Assert(waitRun(name), check.IsNil) 76 77 cpty.Write([]byte{16}) 78 time.Sleep(100 * time.Millisecond) 79 cpty.Write([]byte{17}) 80 81 select { 82 case err := <-errChan: 83 c.Assert(err, check.IsNil) 84 case <-time.After(5 * time.Second): 85 c.Fatal("timeout while detaching") 86 } 87 88 cpty, tty, err = pty.Open() 89 c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err)) 90 91 cmd = exec.Command(dockerBinary, "attach", name) 92 cmd.Stdin = tty 93 cmd.Stdout = tty 94 cmd.Stderr = tty 95 96 err = cmd.Start() 97 c.Assert(err, checker.IsNil) 98 99 bytes := make([]byte, 10) 100 var nBytes int 101 readErr := make(chan error, 1) 102 103 go func() { 104 time.Sleep(500 * time.Millisecond) 105 cpty.Write([]byte("\n")) 106 time.Sleep(500 * time.Millisecond) 107 108 nBytes, err = cpty.Read(bytes) 109 cpty.Close() 110 readErr <- err 111 }() 112 113 select { 114 case err := <-readErr: 115 c.Assert(err, check.IsNil) 116 case <-time.After(2 * time.Second): 117 c.Fatal("timeout waiting for attach read") 118 } 119 120 err = cmd.Wait() 121 c.Assert(err, checker.IsNil) 122 123 c.Assert(string(bytes[:nBytes]), checker.Contains, "/ #") 124 125 } 126 127 // TestAttachDetach checks that attach in tty mode can be detached using the long container ID 128 func (s *DockerSuite) TestAttachDetach(c *check.C) { 129 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 130 id := strings.TrimSpace(out) 131 c.Assert(waitRun(id), check.IsNil) 132 133 cpty, tty, err := pty.Open() 134 c.Assert(err, check.IsNil) 135 defer cpty.Close() 136 137 cmd := exec.Command(dockerBinary, "attach", id) 138 cmd.Stdin = tty 139 stdout, err := cmd.StdoutPipe() 140 c.Assert(err, check.IsNil) 141 defer stdout.Close() 142 err = cmd.Start() 143 c.Assert(err, check.IsNil) 144 c.Assert(waitRun(id), check.IsNil) 145 146 _, err = cpty.Write([]byte("hello\n")) 147 c.Assert(err, check.IsNil) 148 out, err = bufio.NewReader(stdout).ReadString('\n') 149 c.Assert(err, check.IsNil) 150 c.Assert(strings.TrimSpace(out), checker.Equals, "hello", check.Commentf("expected 'hello', got %q", out)) 151 152 // escape sequence 153 _, err = cpty.Write([]byte{16}) 154 c.Assert(err, checker.IsNil) 155 time.Sleep(100 * time.Millisecond) 156 _, err = cpty.Write([]byte{17}) 157 c.Assert(err, checker.IsNil) 158 159 ch := make(chan struct{}) 160 go func() { 161 cmd.Wait() 162 ch <- struct{}{} 163 }() 164 165 running := inspectField(c, id, "State.Running") 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 := inspectField(c, id, "State.Running") 218 c.Assert(running, checker.Equals, "true", check.Commentf("expected container to still be running")) 219 220 go func() { 221 dockerCmd(c, "kill", id) 222 }() 223 224 select { 225 case <-ch: 226 case <-time.After(10 * time.Millisecond): 227 c.Fatal("timed out waiting for container to exit") 228 } 229 230 }