github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/integration-cli/docker_cli_attach_unix_test.go (about) 1 //go:build !windows 2 3 package main 4 5 import ( 6 "bufio" 7 "io" 8 "os/exec" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/creack/pty" 14 "github.com/docker/docker/integration-cli/cli" 15 "gotest.tools/v3/assert" 16 ) 17 18 // #9860 Make sure attach ends when container ends (with no errors) 19 func (s *DockerCLIAttachSuite) TestAttachClosedOnContainerStop(c *testing.T) { 20 testRequires(c, testEnv.IsLocalDaemon) 21 22 out := cli.DockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`).Stdout() 23 id := strings.TrimSpace(out) 24 cli.WaitRun(c, id) 25 26 pt, 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, 1) 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 cli.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 cli.DockerCmd(c, "wait", id) 49 50 select { 51 case err := <-errChan: 52 tty.Close() 53 out, _ := io.ReadAll(pt) 54 assert.Assert(c, err == nil, "out: %v", string(out)) 55 case <-time.After(attachWait): 56 c.Fatal("timed out without attach returning") 57 } 58 } 59 60 func (s *DockerCLIAttachSuite) TestAttachAfterDetach(c *testing.T) { 61 name := "detachtest" 62 63 cpty, tty, err := pty.Open() 64 assert.NilError(c, err, "Could not open pty: %v", err) 65 cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox") 66 cmd.Stdin = tty 67 cmd.Stdout = tty 68 cmd.Stderr = tty 69 70 cmdExit := make(chan error, 1) 71 go func() { 72 cmdExit <- cmd.Run() 73 close(cmdExit) 74 }() 75 76 cli.WaitRun(c, name) 77 78 cpty.Write([]byte{16}) 79 time.Sleep(100 * time.Millisecond) 80 cpty.Write([]byte{17}) 81 82 select { 83 case <-cmdExit: 84 case <-time.After(5 * time.Second): 85 c.Fatal("timeout while detaching") 86 } 87 88 cpty, tty, err = pty.Open() 89 assert.NilError(c, err, "Could not open pty: %v", err) 90 91 cmd = exec.Command(dockerBinary, "attach", name) 92 cmd.Stdin = tty 93 cmd.Stdout = tty 94 cmd.Stderr = tty 95 96 err = cmd.Start() 97 assert.NilError(c, err) 98 defer cmd.Process.Kill() 99 100 bytes := make([]byte, 10) 101 var nBytes int 102 readErr := make(chan error, 1) 103 104 go func() { 105 time.Sleep(500 * time.Millisecond) 106 cpty.Write([]byte("\n")) 107 time.Sleep(500 * time.Millisecond) 108 109 nBytes, err = cpty.Read(bytes) 110 cpty.Close() 111 readErr <- err 112 }() 113 114 select { 115 case err := <-readErr: 116 assert.NilError(c, err) 117 case <-time.After(2 * time.Second): 118 c.Fatal("timeout waiting for attach read") 119 } 120 121 assert.Assert(c, strings.Contains(string(bytes[:nBytes]), "/ #")) 122 } 123 124 // TestAttachDetach checks that attach in tty mode can be detached using the long container ID 125 func (s *DockerCLIAttachSuite) TestAttachDetach(c *testing.T) { 126 out := cli.DockerCmd(c, "run", "-itd", "busybox", "cat").Stdout() 127 id := strings.TrimSpace(out) 128 cli.WaitRun(c, id) 129 130 cpty, tty, err := pty.Open() 131 assert.NilError(c, err) 132 defer cpty.Close() 133 134 cmd := exec.Command(dockerBinary, "attach", id) 135 cmd.Stdin = tty 136 stdout, err := cmd.StdoutPipe() 137 assert.NilError(c, err) 138 defer stdout.Close() 139 err = cmd.Start() 140 assert.NilError(c, err) 141 cli.WaitRun(c, id) 142 143 _, err = cpty.Write([]byte("hello\n")) 144 assert.NilError(c, err) 145 out, err = bufio.NewReader(stdout).ReadString('\n') 146 assert.NilError(c, err) 147 assert.Equal(c, strings.TrimSpace(out), "hello") 148 149 // escape sequence 150 _, err = cpty.Write([]byte{16}) 151 assert.NilError(c, err) 152 time.Sleep(100 * time.Millisecond) 153 _, err = cpty.Write([]byte{17}) 154 assert.NilError(c, err) 155 156 ch := make(chan struct{}) 157 go func() { 158 cmd.Wait() 159 close(ch) 160 }() 161 162 select { 163 case <-ch: 164 case <-time.After(1 * time.Second): 165 c.Fatal("timed out waiting for container to exit") 166 } 167 168 running := inspectField(c, id, "State.Running") 169 assert.Equal(c, running, "true") // container should be running 170 }