docker_cli_attach_unix_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // +build !windows
  2. package main
  3. import (
  4. "bufio"
  5. "os/exec"
  6. "strings"
  7. "testing"
  8. "time"
  9. "github.com/kr/pty"
  10. )
  11. // #9860
  12. func TestAttachClosedOnContainerStop(t *testing.T) {
  13. defer deleteAllContainers()
  14. cmd := exec.Command(dockerBinary, "run", "-dti", "busybox", "sleep", "2")
  15. out, _, err := runCommandWithOutput(cmd)
  16. if err != nil {
  17. t.Fatalf("failed to start container: %v (%v)", out, err)
  18. }
  19. id := strings.TrimSpace(out)
  20. if err := waitRun(id); err != nil {
  21. t.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. t.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. t.Fatalf("attach returned error %s", err)
  36. }
  37. }()
  38. waitCmd := exec.Command(dockerBinary, "wait", id)
  39. if out, _, err = runCommandWithOutput(waitCmd); err != nil {
  40. t.Fatalf("error thrown while waiting for container: %s, %v", out, err)
  41. }
  42. select {
  43. case <-done:
  44. case <-time.After(attachWait):
  45. t.Fatal("timed out without attach returning")
  46. }
  47. logDone("attach - return after container finished")
  48. }
  49. func TestAttachAfterDetach(t *testing.T) {
  50. defer deleteAllContainers()
  51. name := "detachtest"
  52. cpty, tty, err := pty.Open()
  53. if err != nil {
  54. t.Fatalf("Could not open pty: %v", err)
  55. }
  56. cmd := exec.Command(dockerBinary, "run", "-ti", "--name", name, "busybox")
  57. cmd.Stdin = tty
  58. cmd.Stdout = tty
  59. cmd.Stderr = tty
  60. detached := make(chan struct{})
  61. go func() {
  62. if err := cmd.Run(); err != nil {
  63. t.Fatalf("attach returned error %s", err)
  64. }
  65. close(detached)
  66. }()
  67. time.Sleep(500 * time.Millisecond)
  68. if err := waitRun(name); err != nil {
  69. t.Fatal(err)
  70. }
  71. cpty.Write([]byte{16})
  72. time.Sleep(100 * time.Millisecond)
  73. cpty.Write([]byte{17})
  74. <-detached
  75. cpty, tty, err = pty.Open()
  76. if err != nil {
  77. t.Fatalf("Could not open pty: %v", err)
  78. }
  79. cmd = exec.Command(dockerBinary, "attach", name)
  80. cmd.Stdin = tty
  81. cmd.Stdout = tty
  82. cmd.Stderr = tty
  83. if err := cmd.Start(); err != nil {
  84. t.Fatal(err)
  85. }
  86. bytes := make([]byte, 10)
  87. var nBytes int
  88. readErr := make(chan error, 1)
  89. go func() {
  90. time.Sleep(500 * time.Millisecond)
  91. cpty.Write([]byte("\n"))
  92. time.Sleep(500 * time.Millisecond)
  93. nBytes, err = cpty.Read(bytes)
  94. cpty.Close()
  95. readErr <- err
  96. }()
  97. select {
  98. case err := <-readErr:
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. case <-time.After(2 * time.Second):
  103. t.Fatal("timeout waiting for attach read")
  104. }
  105. if err := cmd.Wait(); err != nil {
  106. t.Fatal(err)
  107. }
  108. if !strings.Contains(string(bytes[:nBytes]), "/ #") {
  109. t.Fatalf("failed to get a new prompt. got %s", string(bytes[:nBytes]))
  110. }
  111. logDone("attach - reconnect after detaching")
  112. }
  113. // TestAttachDetach checks that attach in tty mode can be detached using the long container ID
  114. func TestAttachDetach(t *testing.T) {
  115. out, _, _ := dockerCmd(t, "run", "-itd", "busybox", "cat")
  116. id := strings.TrimSpace(out)
  117. if err := waitRun(id); err != nil {
  118. t.Fatal(err)
  119. }
  120. cpty, tty, err := pty.Open()
  121. if err != nil {
  122. t.Fatal(err)
  123. }
  124. defer cpty.Close()
  125. cmd := exec.Command(dockerBinary, "attach", id)
  126. cmd.Stdin = tty
  127. stdout, err := cmd.StdoutPipe()
  128. if err != nil {
  129. t.Fatal(err)
  130. }
  131. defer stdout.Close()
  132. if err := cmd.Start(); err != nil {
  133. t.Fatal(err)
  134. }
  135. if err := waitRun(id); err != nil {
  136. t.Fatalf("error waiting for container to start: %v", err)
  137. }
  138. if _, err := cpty.Write([]byte("hello\n")); err != nil {
  139. t.Fatal(err)
  140. }
  141. out, err = bufio.NewReader(stdout).ReadString('\n')
  142. if err != nil {
  143. t.Fatal(err)
  144. }
  145. if strings.TrimSpace(out) != "hello" {
  146. t.Fatalf("exepected 'hello', got %q", out)
  147. }
  148. // escape sequence
  149. if _, err := cpty.Write([]byte{16}); err != nil {
  150. t.Fatal(err)
  151. }
  152. time.Sleep(100 * time.Millisecond)
  153. if _, err := cpty.Write([]byte{17}); err != nil {
  154. t.Fatal(err)
  155. }
  156. ch := make(chan struct{})
  157. go func() {
  158. cmd.Wait()
  159. ch <- struct{}{}
  160. }()
  161. running, err := inspectField(id, "State.Running")
  162. if err != nil {
  163. t.Fatal(err)
  164. }
  165. if running != "true" {
  166. t.Fatal("exepected container to still be running")
  167. }
  168. go func() {
  169. dockerCmd(t, "kill", id)
  170. }()
  171. select {
  172. case <-ch:
  173. case <-time.After(10 * time.Millisecond):
  174. t.Fatal("timed out waiting for container to exit")
  175. }
  176. logDone("attach - detach")
  177. }