docker_cli_attach_unix_test.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. // +build !windows
  2. package main
  3. import (
  4. "bufio"
  5. "io/ioutil"
  6. "os/exec"
  7. "strings"
  8. "time"
  9. "github.com/docker/docker/integration-cli/checker"
  10. "github.com/go-check/check"
  11. "github.com/kr/pty"
  12. )
  13. // #9860 Make sure attach ends when container ends (with no errors)
  14. func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
  15. testRequires(c, testEnv.IsLocalDaemon)
  16. out, _ := dockerCmd(c, "run", "-dti", "busybox", "/bin/sh", "-c", `trap 'exit 0' SIGTERM; while true; do sleep 1; done`)
  17. id := strings.TrimSpace(out)
  18. c.Assert(waitRun(id), check.IsNil)
  19. pty, tty, err := pty.Open()
  20. c.Assert(err, check.IsNil)
  21. attachCmd := exec.Command(dockerBinary, "attach", id)
  22. attachCmd.Stdin = tty
  23. attachCmd.Stdout = tty
  24. attachCmd.Stderr = tty
  25. err = attachCmd.Start()
  26. c.Assert(err, check.IsNil)
  27. errChan := make(chan error)
  28. go func() {
  29. time.Sleep(300 * time.Millisecond)
  30. defer close(errChan)
  31. // Container is waiting for us to signal it to stop
  32. dockerCmd(c, "stop", id)
  33. // And wait for the attach command to end
  34. errChan <- attachCmd.Wait()
  35. }()
  36. // Wait for the docker to end (should be done by the
  37. // stop command in the go routine)
  38. dockerCmd(c, "wait", id)
  39. select {
  40. case err := <-errChan:
  41. tty.Close()
  42. out, _ := ioutil.ReadAll(pty)
  43. c.Assert(err, check.IsNil, check.Commentf("out: %v", string(out)))
  44. case <-time.After(attachWait):
  45. c.Fatal("timed out without attach returning")
  46. }
  47. }
  48. func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
  49. name := "detachtest"
  50. cpty, tty, err := pty.Open()
  51. c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err))
  52. cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox")
  53. cmd.Stdin = tty
  54. cmd.Stdout = tty
  55. cmd.Stderr = tty
  56. cmdExit := make(chan error)
  57. go func() {
  58. cmdExit <- cmd.Run()
  59. close(cmdExit)
  60. }()
  61. c.Assert(waitRun(name), check.IsNil)
  62. cpty.Write([]byte{16})
  63. time.Sleep(100 * time.Millisecond)
  64. cpty.Write([]byte{17})
  65. select {
  66. case <-cmdExit:
  67. case <-time.After(5 * time.Second):
  68. c.Fatal("timeout while detaching")
  69. }
  70. cpty, tty, err = pty.Open()
  71. c.Assert(err, checker.IsNil, check.Commentf("Could not open pty: %v", err))
  72. cmd = exec.Command(dockerBinary, "attach", name)
  73. cmd.Stdin = tty
  74. cmd.Stdout = tty
  75. cmd.Stderr = tty
  76. err = cmd.Start()
  77. c.Assert(err, checker.IsNil)
  78. defer cmd.Process.Kill()
  79. bytes := make([]byte, 10)
  80. var nBytes int
  81. readErr := make(chan error, 1)
  82. go func() {
  83. time.Sleep(500 * time.Millisecond)
  84. cpty.Write([]byte("\n"))
  85. time.Sleep(500 * time.Millisecond)
  86. nBytes, err = cpty.Read(bytes)
  87. cpty.Close()
  88. readErr <- err
  89. }()
  90. select {
  91. case err := <-readErr:
  92. c.Assert(err, check.IsNil)
  93. case <-time.After(2 * time.Second):
  94. c.Fatal("timeout waiting for attach read")
  95. }
  96. c.Assert(string(bytes[:nBytes]), checker.Contains, "/ #")
  97. }
  98. // TestAttachDetach checks that attach in tty mode can be detached using the long container ID
  99. func (s *DockerSuite) TestAttachDetach(c *check.C) {
  100. out, _ := dockerCmd(c, "run", "-itd", "busybox", "cat")
  101. id := strings.TrimSpace(out)
  102. c.Assert(waitRun(id), check.IsNil)
  103. cpty, tty, err := pty.Open()
  104. c.Assert(err, check.IsNil)
  105. defer cpty.Close()
  106. cmd := exec.Command(dockerBinary, "attach", id)
  107. cmd.Stdin = tty
  108. stdout, err := cmd.StdoutPipe()
  109. c.Assert(err, check.IsNil)
  110. defer stdout.Close()
  111. err = cmd.Start()
  112. c.Assert(err, check.IsNil)
  113. c.Assert(waitRun(id), check.IsNil)
  114. _, err = cpty.Write([]byte("hello\n"))
  115. c.Assert(err, check.IsNil)
  116. out, err = bufio.NewReader(stdout).ReadString('\n')
  117. c.Assert(err, check.IsNil)
  118. c.Assert(strings.TrimSpace(out), checker.Equals, "hello")
  119. // escape sequence
  120. _, err = cpty.Write([]byte{16})
  121. c.Assert(err, checker.IsNil)
  122. time.Sleep(100 * time.Millisecond)
  123. _, err = cpty.Write([]byte{17})
  124. c.Assert(err, checker.IsNil)
  125. ch := make(chan struct{})
  126. go func() {
  127. cmd.Wait()
  128. close(ch)
  129. }()
  130. select {
  131. case <-ch:
  132. case <-time.After(1 * time.Second):
  133. c.Fatal("timed out waiting for container to exit")
  134. }
  135. running := inspectField(c, id, "State.Running")
  136. c.Assert(running, checker.Equals, "true") // container should be running
  137. }