github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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/Prakhar-Agarwal-byte/moby/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  }