github.com/xdlianrong208/docker-ce-comments@v17.12.1-ce-rc2+incompatible/components/engine/integration-cli/docker_cli_attach_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os/exec" 8 "runtime" 9 "strings" 10 "sync" 11 "time" 12 13 "github.com/docker/docker/integration-cli/cli" 14 "github.com/go-check/check" 15 "github.com/gotestyourself/gotestyourself/icmd" 16 ) 17 18 const attachWait = 5 * time.Second 19 20 func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) { 21 endGroup := &sync.WaitGroup{} 22 startGroup := &sync.WaitGroup{} 23 endGroup.Add(3) 24 startGroup.Add(3) 25 26 cli.DockerCmd(c, "run", "--name", "attacher", "-d", "busybox", "/bin/sh", "-c", "while true; do sleep 1; echo hello; done") 27 cli.WaitRun(c, "attacher") 28 29 startDone := make(chan struct{}) 30 endDone := make(chan struct{}) 31 32 go func() { 33 endGroup.Wait() 34 close(endDone) 35 }() 36 37 go func() { 38 startGroup.Wait() 39 close(startDone) 40 }() 41 42 for i := 0; i < 3; i++ { 43 go func() { 44 cmd := exec.Command(dockerBinary, "attach", "attacher") 45 46 defer func() { 47 cmd.Wait() 48 endGroup.Done() 49 }() 50 51 out, err := cmd.StdoutPipe() 52 if err != nil { 53 c.Fatal(err) 54 } 55 defer out.Close() 56 57 if err := cmd.Start(); err != nil { 58 c.Fatal(err) 59 } 60 61 buf := make([]byte, 1024) 62 63 if _, err := out.Read(buf); err != nil && err != io.EOF { 64 c.Fatal(err) 65 } 66 67 startGroup.Done() 68 69 if !strings.Contains(string(buf), "hello") { 70 c.Fatalf("unexpected output %s expected hello\n", string(buf)) 71 } 72 }() 73 } 74 75 select { 76 case <-startDone: 77 case <-time.After(attachWait): 78 c.Fatalf("Attaches did not initialize properly") 79 } 80 81 cli.DockerCmd(c, "kill", "attacher") 82 83 select { 84 case <-endDone: 85 case <-time.After(attachWait): 86 c.Fatalf("Attaches did not finish properly") 87 } 88 } 89 90 func (s *DockerSuite) TestAttachTTYWithoutStdin(c *check.C) { 91 // TODO @jhowardmsft. Figure out how to get this running again reliable on Windows. 92 // It works by accident at the moment. Sometimes. I've gone back to v1.13.0 and see the same. 93 // On Windows, docker run -d -ti busybox causes the container to exit immediately. 94 // Obviously a year back when I updated the test, that was not the case. However, 95 // with this, and the test racing with the tear-down which panic's, sometimes CI 96 // will just fail and `MISS` all the other tests. For now, disabling it. Will 97 // open an issue to track re-enabling this and root-causing the problem. 98 testRequires(c, DaemonIsLinux) 99 out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox") 100 101 id := strings.TrimSpace(out) 102 c.Assert(waitRun(id), check.IsNil) 103 104 done := make(chan error) 105 go func() { 106 defer close(done) 107 108 cmd := exec.Command(dockerBinary, "attach", id) 109 if _, err := cmd.StdinPipe(); err != nil { 110 done <- err 111 return 112 } 113 114 expected := "the input device is not a TTY" 115 if runtime.GOOS == "windows" { 116 expected += ". If you are using mintty, try prefixing the command with 'winpty'" 117 } 118 if out, _, err := runCommandWithOutput(cmd); err == nil { 119 done <- fmt.Errorf("attach should have failed") 120 return 121 } else if !strings.Contains(out, expected) { 122 done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected) 123 return 124 } 125 }() 126 127 select { 128 case err := <-done: 129 c.Assert(err, check.IsNil) 130 case <-time.After(attachWait): 131 c.Fatal("attach is running but should have failed") 132 } 133 } 134 135 func (s *DockerSuite) TestAttachDisconnect(c *check.C) { 136 testRequires(c, DaemonIsLinux) 137 out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat") 138 id := strings.TrimSpace(out) 139 140 cmd := exec.Command(dockerBinary, "attach", id) 141 stdin, err := cmd.StdinPipe() 142 if err != nil { 143 c.Fatal(err) 144 } 145 defer stdin.Close() 146 stdout, err := cmd.StdoutPipe() 147 c.Assert(err, check.IsNil) 148 defer stdout.Close() 149 c.Assert(cmd.Start(), check.IsNil) 150 defer func() { 151 cmd.Process.Kill() 152 cmd.Wait() 153 }() 154 155 _, err = stdin.Write([]byte("hello\n")) 156 c.Assert(err, check.IsNil) 157 out, err = bufio.NewReader(stdout).ReadString('\n') 158 c.Assert(err, check.IsNil) 159 c.Assert(strings.TrimSpace(out), check.Equals, "hello") 160 161 c.Assert(stdin.Close(), check.IsNil) 162 163 // Expect container to still be running after stdin is closed 164 running := inspectField(c, id, "State.Running") 165 c.Assert(running, check.Equals, "true") 166 } 167 168 func (s *DockerSuite) TestAttachPausedContainer(c *check.C) { 169 testRequires(c, IsPausable) 170 runSleepingContainer(c, "-d", "--name=test") 171 dockerCmd(c, "pause", "test") 172 173 result := dockerCmdWithResult("attach", "test") 174 result.Assert(c, icmd.Expected{ 175 Error: "exit status 1", 176 ExitCode: 1, 177 Err: "You cannot attach to a paused container, unpause it first", 178 }) 179 }