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