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