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