github.com/damirazo/docker@v1.9.0/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/stringid" 12 "github.com/go-check/check" 13 "github.com/kr/pty" 14 ) 15 16 // #9860 Make sure attach ends when container ends (with no errors) 17 func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) { 18 19 out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`) 20 21 id := strings.TrimSpace(out) 22 c.Assert(waitRun(id), check.IsNil) 23 24 _, tty, err := pty.Open() 25 c.Assert(err, check.IsNil) 26 27 attachCmd := exec.Command(dockerBinary, "attach", id) 28 attachCmd.Stdin = tty 29 attachCmd.Stdout = tty 30 attachCmd.Stderr = tty 31 err = attachCmd.Start() 32 c.Assert(err, check.IsNil) 33 34 errChan := make(chan error) 35 go func() { 36 defer close(errChan) 37 // Container is wating for us to signal it to stop 38 dockerCmd(c, "stop", id) 39 // And wait for the attach command to end 40 errChan <- attachCmd.Wait() 41 }() 42 43 // Wait for the docker to end (should be done by the 44 // stop command in the go routine) 45 dockerCmd(c, "wait", id) 46 47 select { 48 case err := <-errChan: 49 c.Assert(err, check.IsNil) 50 case <-time.After(attachWait): 51 c.Fatal("timed out without attach returning") 52 } 53 54 } 55 56 func (s *DockerSuite) TestAttachAfterDetach(c *check.C) { 57 58 name := "detachtest" 59 60 cpty, tty, err := pty.Open() 61 if err != nil { 62 c.Fatalf("Could not open pty: %v", err) 63 } 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 if err != nil { 90 c.Fatalf("Could not open pty: %v", err) 91 } 92 93 cmd = exec.Command(dockerBinary, "attach", name) 94 cmd.Stdin = tty 95 cmd.Stdout = tty 96 cmd.Stderr = tty 97 98 if err := cmd.Start(); err != nil { 99 c.Fatal(err) 100 } 101 102 bytes := make([]byte, 10) 103 var nBytes int 104 readErr := make(chan error, 1) 105 106 go func() { 107 time.Sleep(500 * time.Millisecond) 108 cpty.Write([]byte("\n")) 109 time.Sleep(500 * time.Millisecond) 110 111 nBytes, err = cpty.Read(bytes) 112 cpty.Close() 113 readErr <- err 114 }() 115 116 select { 117 case err := <-readErr: 118 c.Assert(err, check.IsNil) 119 case <-time.After(2 * time.Second): 120 c.Fatal("timeout waiting for attach read") 121 } 122 123 if err := cmd.Wait(); err != nil { 124 c.Fatal(err) 125 } 126 127 if !strings.Contains(string(bytes[:nBytes]), "/ #") { 128 c.Fatalf("failed to get a new prompt. got %s", string(bytes[:nBytes])) 129 } 130 131 } 132 133 // TestAttachDetach checks that attach in tty mode can be detached using the long container ID 134 func (s *DockerSuite) TestAttachDetach(c *check.C) { 135 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 136 id := strings.TrimSpace(out) 137 c.Assert(waitRun(id), check.IsNil) 138 139 cpty, tty, err := pty.Open() 140 if err != nil { 141 c.Fatal(err) 142 } 143 defer cpty.Close() 144 145 cmd := exec.Command(dockerBinary, "attach", id) 146 cmd.Stdin = tty 147 stdout, err := cmd.StdoutPipe() 148 if err != nil { 149 c.Fatal(err) 150 } 151 defer stdout.Close() 152 if err := cmd.Start(); err != nil { 153 c.Fatal(err) 154 } 155 c.Assert(waitRun(id), check.IsNil) 156 157 if _, err := cpty.Write([]byte("hello\n")); err != nil { 158 c.Fatal(err) 159 } 160 out, err = bufio.NewReader(stdout).ReadString('\n') 161 if err != nil { 162 c.Fatal(err) 163 } 164 if strings.TrimSpace(out) != "hello" { 165 c.Fatalf("expected 'hello', got %q", out) 166 } 167 168 // escape sequence 169 if _, err := cpty.Write([]byte{16}); err != nil { 170 c.Fatal(err) 171 } 172 time.Sleep(100 * time.Millisecond) 173 if _, err := cpty.Write([]byte{17}); err != nil { 174 c.Fatal(err) 175 } 176 177 ch := make(chan struct{}) 178 go func() { 179 cmd.Wait() 180 ch <- struct{}{} 181 }() 182 183 running, err := inspectField(id, "State.Running") 184 if err != nil { 185 c.Fatal(err) 186 } 187 if running != "true" { 188 c.Fatal("expected container to still be running") 189 } 190 191 go func() { 192 dockerCmd(c, "kill", id) 193 }() 194 195 select { 196 case <-ch: 197 case <-time.After(10 * time.Millisecond): 198 c.Fatal("timed out waiting for container to exit") 199 } 200 201 } 202 203 // TestAttachDetachTruncatedID checks that attach in tty mode can be detached 204 func (s *DockerSuite) TestAttachDetachTruncatedID(c *check.C) { 205 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 206 id := stringid.TruncateID(strings.TrimSpace(out)) 207 c.Assert(waitRun(id), check.IsNil) 208 209 cpty, tty, err := pty.Open() 210 if err != nil { 211 c.Fatal(err) 212 } 213 defer cpty.Close() 214 215 cmd := exec.Command(dockerBinary, "attach", id) 216 cmd.Stdin = tty 217 stdout, err := cmd.StdoutPipe() 218 if err != nil { 219 c.Fatal(err) 220 } 221 defer stdout.Close() 222 if err := cmd.Start(); err != nil { 223 c.Fatal(err) 224 } 225 226 if _, err := cpty.Write([]byte("hello\n")); err != nil { 227 c.Fatal(err) 228 } 229 out, err = bufio.NewReader(stdout).ReadString('\n') 230 if err != nil { 231 c.Fatal(err) 232 } 233 if strings.TrimSpace(out) != "hello" { 234 c.Fatalf("expected 'hello', got %q", out) 235 } 236 237 // escape sequence 238 if _, err := cpty.Write([]byte{16}); err != nil { 239 c.Fatal(err) 240 } 241 time.Sleep(100 * time.Millisecond) 242 if _, err := cpty.Write([]byte{17}); err != nil { 243 c.Fatal(err) 244 } 245 246 ch := make(chan struct{}) 247 go func() { 248 cmd.Wait() 249 ch <- struct{}{} 250 }() 251 252 running, err := inspectField(id, "State.Running") 253 if err != nil { 254 c.Fatal(err) 255 } 256 if running != "true" { 257 c.Fatal("expected container to still be running") 258 } 259 260 go func() { 261 dockerCmd(c, "kill", id) 262 }() 263 264 select { 265 case <-ch: 266 case <-time.After(10 * time.Millisecond): 267 c.Fatal("timed out waiting for container to exit") 268 } 269 270 }