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