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