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