github.com/yamamoto-febc/docker@v1.9.0/integration-cli/docker_cli_attach_unix_test.go (about)

     1  // +build !windows
     2  
     3  package main
     4  
     5  import (
     6  	"bufio"
     7  	"os/exec"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/docker/docker/pkg/stringid"
    12  	"github.com/go-check/check"
    13  	"github.com/kr/pty"
    14  )
    15  
    16  // #9860 Make sure attach ends when container ends (with no errors)
    17  func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
    18  
    19  	out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`)
    20  
    21  	id := strings.TrimSpace(out)
    22  	c.Assert(waitRun(id), check.IsNil)
    23  
    24  	_, tty, err := pty.Open()
    25  	c.Assert(err, check.IsNil)
    26  
    27  	attachCmd := exec.Command(dockerBinary, "attach", id)
    28  	attachCmd.Stdin = tty
    29  	attachCmd.Stdout = tty
    30  	attachCmd.Stderr = tty
    31  	err = attachCmd.Start()
    32  	c.Assert(err, check.IsNil)
    33  
    34  	errChan := make(chan error)
    35  	go func() {
    36  		defer close(errChan)
    37  		// Container is wating for us to signal it to stop
    38  		dockerCmd(c, "stop", id)
    39  		// And wait for the attach command to end
    40  		errChan <- attachCmd.Wait()
    41  	}()
    42  
    43  	// Wait for the docker to end (should be done by the
    44  	// stop command in the go routine)
    45  	dockerCmd(c, "wait", id)
    46  
    47  	select {
    48  	case err := <-errChan:
    49  		c.Assert(err, check.IsNil)
    50  	case <-time.After(attachWait):
    51  		c.Fatal("timed out without attach returning")
    52  	}
    53  
    54  }
    55  
    56  func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
    57  
    58  	name := "detachtest"
    59  
    60  	cpty, tty, err := pty.Open()
    61  	if err != nil {
    62  		c.Fatalf("Could not open pty: %v", err)
    63  	}
    64  	cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox")
    65  	cmd.Stdin = tty
    66  	cmd.Stdout = tty
    67  	cmd.Stderr = tty
    68  
    69  	errChan := make(chan error)
    70  	go func() {
    71  		errChan <- cmd.Run()
    72  		close(errChan)
    73  	}()
    74  
    75  	c.Assert(waitRun(name), check.IsNil)
    76  
    77  	cpty.Write([]byte{16})
    78  	time.Sleep(100 * time.Millisecond)
    79  	cpty.Write([]byte{17})
    80  
    81  	select {
    82  	case err := <-errChan:
    83  		c.Assert(err, check.IsNil)
    84  	case <-time.After(5 * time.Second):
    85  		c.Fatal("timeout while detaching")
    86  	}
    87  
    88  	cpty, tty, err = pty.Open()
    89  	if err != nil {
    90  		c.Fatalf("Could not open pty: %v", err)
    91  	}
    92  
    93  	cmd = exec.Command(dockerBinary, "attach", name)
    94  	cmd.Stdin = tty
    95  	cmd.Stdout = tty
    96  	cmd.Stderr = tty
    97  
    98  	if err := cmd.Start(); err != nil {
    99  		c.Fatal(err)
   100  	}
   101  
   102  	bytes := make([]byte, 10)
   103  	var nBytes int
   104  	readErr := make(chan error, 1)
   105  
   106  	go func() {
   107  		time.Sleep(500 * time.Millisecond)
   108  		cpty.Write([]byte("\n"))
   109  		time.Sleep(500 * time.Millisecond)
   110  
   111  		nBytes, err = cpty.Read(bytes)
   112  		cpty.Close()
   113  		readErr <- err
   114  	}()
   115  
   116  	select {
   117  	case err := <-readErr:
   118  		c.Assert(err, check.IsNil)
   119  	case <-time.After(2 * time.Second):
   120  		c.Fatal("timeout waiting for attach read")
   121  	}
   122  
   123  	if err := cmd.Wait(); err != nil {
   124  		c.Fatal(err)
   125  	}
   126  
   127  	if !strings.Contains(string(bytes[:nBytes]), "/ #") {
   128  		c.Fatalf("failed to get a new prompt. got %s", string(bytes[:nBytes]))
   129  	}
   130  
   131  }
   132  
   133  // TestAttachDetach checks that attach in tty mode can be detached using the long container ID
   134  func (s *DockerSuite) TestAttachDetach(c *check.C) {
   135  	out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
   136  	id := strings.TrimSpace(out)
   137  	c.Assert(waitRun(id), check.IsNil)
   138  
   139  	cpty, tty, err := pty.Open()
   140  	if err != nil {
   141  		c.Fatal(err)
   142  	}
   143  	defer cpty.Close()
   144  
   145  	cmd := exec.Command(dockerBinary, "attach", id)
   146  	cmd.Stdin = tty
   147  	stdout, err := cmd.StdoutPipe()
   148  	if err != nil {
   149  		c.Fatal(err)
   150  	}
   151  	defer stdout.Close()
   152  	if err := cmd.Start(); err != nil {
   153  		c.Fatal(err)
   154  	}
   155  	c.Assert(waitRun(id), check.IsNil)
   156  
   157  	if _, err := cpty.Write([]byte("hello\n")); err != nil {
   158  		c.Fatal(err)
   159  	}
   160  	out, err = bufio.NewReader(stdout).ReadString('\n')
   161  	if err != nil {
   162  		c.Fatal(err)
   163  	}
   164  	if strings.TrimSpace(out) != "hello" {
   165  		c.Fatalf("expected 'hello', got %q", out)
   166  	}
   167  
   168  	// escape sequence
   169  	if _, err := cpty.Write([]byte{16}); err != nil {
   170  		c.Fatal(err)
   171  	}
   172  	time.Sleep(100 * time.Millisecond)
   173  	if _, err := cpty.Write([]byte{17}); err != nil {
   174  		c.Fatal(err)
   175  	}
   176  
   177  	ch := make(chan struct{})
   178  	go func() {
   179  		cmd.Wait()
   180  		ch <- struct{}{}
   181  	}()
   182  
   183  	running, err := inspectField(id, "State.Running")
   184  	if err != nil {
   185  		c.Fatal(err)
   186  	}
   187  	if running != "true" {
   188  		c.Fatal("expected container to still be running")
   189  	}
   190  
   191  	go func() {
   192  		dockerCmd(c, "kill", id)
   193  	}()
   194  
   195  	select {
   196  	case <-ch:
   197  	case <-time.After(10 * time.Millisecond):
   198  		c.Fatal("timed out waiting for container to exit")
   199  	}
   200  
   201  }
   202  
   203  // TestAttachDetachTruncatedID checks that attach in tty mode can be detached
   204  func (s *DockerSuite) TestAttachDetachTruncatedID(c *check.C) {
   205  	out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
   206  	id := stringid.TruncateID(strings.TrimSpace(out))
   207  	c.Assert(waitRun(id), check.IsNil)
   208  
   209  	cpty, tty, err := pty.Open()
   210  	if err != nil {
   211  		c.Fatal(err)
   212  	}
   213  	defer cpty.Close()
   214  
   215  	cmd := exec.Command(dockerBinary, "attach", id)
   216  	cmd.Stdin = tty
   217  	stdout, err := cmd.StdoutPipe()
   218  	if err != nil {
   219  		c.Fatal(err)
   220  	}
   221  	defer stdout.Close()
   222  	if err := cmd.Start(); err != nil {
   223  		c.Fatal(err)
   224  	}
   225  
   226  	if _, err := cpty.Write([]byte("hello\n")); err != nil {
   227  		c.Fatal(err)
   228  	}
   229  	out, err = bufio.NewReader(stdout).ReadString('\n')
   230  	if err != nil {
   231  		c.Fatal(err)
   232  	}
   233  	if strings.TrimSpace(out) != "hello" {
   234  		c.Fatalf("expected 'hello', got %q", out)
   235  	}
   236  
   237  	// escape sequence
   238  	if _, err := cpty.Write([]byte{16}); err != nil {
   239  		c.Fatal(err)
   240  	}
   241  	time.Sleep(100 * time.Millisecond)
   242  	if _, err := cpty.Write([]byte{17}); err != nil {
   243  		c.Fatal(err)
   244  	}
   245  
   246  	ch := make(chan struct{})
   247  	go func() {
   248  		cmd.Wait()
   249  		ch <- struct{}{}
   250  	}()
   251  
   252  	running, err := inspectField(id, "State.Running")
   253  	if err != nil {
   254  		c.Fatal(err)
   255  	}
   256  	if running != "true" {
   257  		c.Fatal("expected container to still be running")
   258  	}
   259  
   260  	go func() {
   261  		dockerCmd(c, "kill", id)
   262  	}()
   263  
   264  	select {
   265  	case <-ch:
   266  	case <-time.After(10 * time.Millisecond):
   267  		c.Fatal("timed out waiting for container to exit")
   268  	}
   269  
   270  }