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