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