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