docker_cli_attach_unix_test.go 5.4 KB

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