github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/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/go-check/check" 13 "github.com/kr/pty" 14 "gotest.tools/assert" 15 ) 16 17 // #9860 Make sure attach ends when container ends (with no errors) 18 func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) { 19 testRequires(c, testEnv.IsLocalDaemon) 20 21 out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`) 22 23 id := strings.TrimSpace(out) 24 assert.NilError(c, waitRun(id)) 25 26 pty, tty, err := pty.Open() 27 assert.NilError(c, err) 28 29 attachCmd := exec.Command(dockerBinary, "attach", id) 30 attachCmd.Stdin = tty 31 attachCmd.Stdout = tty 32 attachCmd.Stderr = tty 33 err = attachCmd.Start() 34 assert.NilError(c, err) 35 36 errChan := make(chan error) 37 go func() { 38 time.Sleep(300 * time.Millisecond) 39 defer close(errChan) 40 // Container is waiting for us to signal it to stop 41 dockerCmd(c, "stop", id) 42 // And wait for the attach command to end 43 errChan <- attachCmd.Wait() 44 }() 45 46 // Wait for the docker to end (should be done by the 47 // stop command in the go routine) 48 dockerCmd(c, "wait", id) 49 50 select { 51 case err := <-errChan: 52 tty.Close() 53 out, _ := ioutil.ReadAll(pty) 54 c.Assert(err, check.IsNil, check.Commentf("out: %v", string(out))) 55 case <-time.After(attachWait): 56 c.Fatal("timed out without attach returning") 57 } 58 59 } 60 61 func (s *DockerSuite) TestAttachAfterDetach(c *check.C) { 62 name := "detachtest" 63 64 cpty, tty, err := pty.Open() 65 assert.NilError(c, err, "Could not open pty: %v", err) 66 cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox") 67 cmd.Stdin = tty 68 cmd.Stdout = tty 69 cmd.Stderr = tty 70 71 cmdExit := make(chan error) 72 go func() { 73 cmdExit <- cmd.Run() 74 close(cmdExit) 75 }() 76 77 c.Assert(waitRun(name), check.IsNil) 78 79 cpty.Write([]byte{16}) 80 time.Sleep(100 * time.Millisecond) 81 cpty.Write([]byte{17}) 82 83 select { 84 case <-cmdExit: 85 case <-time.After(5 * time.Second): 86 c.Fatal("timeout while detaching") 87 } 88 89 cpty, tty, err = pty.Open() 90 assert.NilError(c, err, "Could not open pty: %v", err) 91 92 cmd = exec.Command(dockerBinary, "attach", name) 93 cmd.Stdin = tty 94 cmd.Stdout = tty 95 cmd.Stderr = tty 96 97 err = cmd.Start() 98 assert.NilError(c, err) 99 defer cmd.Process.Kill() 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 assert.NilError(c, err) 118 case <-time.After(2 * time.Second): 119 c.Fatal("timeout waiting for attach read") 120 } 121 122 assert.Assert(c, strings.Contains(string(bytes[:nBytes]), "/ #")) 123 } 124 125 // TestAttachDetach checks that attach in tty mode can be detached using the long container ID 126 func (s *DockerSuite) TestAttachDetach(c *check.C) { 127 out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat") 128 id := strings.TrimSpace(out) 129 assert.NilError(c, waitRun(id)) 130 131 cpty, tty, err := pty.Open() 132 assert.NilError(c, err) 133 defer cpty.Close() 134 135 cmd := exec.Command(dockerBinary, "attach", id) 136 cmd.Stdin = tty 137 stdout, err := cmd.StdoutPipe() 138 assert.NilError(c, err) 139 defer stdout.Close() 140 err = cmd.Start() 141 assert.NilError(c, err) 142 assert.NilError(c, waitRun(id)) 143 144 _, err = cpty.Write([]byte("hello\n")) 145 assert.NilError(c, err) 146 out, err = bufio.NewReader(stdout).ReadString('\n') 147 assert.NilError(c, err) 148 assert.Equal(c, strings.TrimSpace(out), "hello") 149 150 // escape sequence 151 _, err = cpty.Write([]byte{16}) 152 assert.NilError(c, err) 153 time.Sleep(100 * time.Millisecond) 154 _, err = cpty.Write([]byte{17}) 155 assert.NilError(c, err) 156 157 ch := make(chan struct{}) 158 go func() { 159 cmd.Wait() 160 close(ch) 161 }() 162 163 select { 164 case <-ch: 165 case <-time.After(1 * time.Second): 166 c.Fatal("timed out waiting for container to exit") 167 } 168 169 running := inspectField(c, id, "State.Running") 170 assert.Equal(c, running, "true") // container should be running 171 }