docker_cli_attach_unix_test.go 5.6 KB

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