commands_test.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package docker
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "strings"
  7. "testing"
  8. "time"
  9. )
  10. func closeWrap(args ...io.Closer) error {
  11. e := false
  12. ret := fmt.Errorf("Error closing elements")
  13. for _, c := range args {
  14. if err := c.Close(); err != nil {
  15. e = true
  16. ret = fmt.Errorf("%s\n%s", ret, err)
  17. }
  18. }
  19. if e {
  20. return ret
  21. }
  22. return nil
  23. }
  24. func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
  25. c := make(chan bool)
  26. // Make sure we are not too long
  27. go func() {
  28. time.Sleep(d)
  29. c <- true
  30. }()
  31. go func() {
  32. f()
  33. c <- false
  34. }()
  35. if <-c {
  36. t.Fatal(msg)
  37. }
  38. }
  39. func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
  40. for i := 0; i < count; i++ {
  41. if _, err := w.Write([]byte(input)); err != nil {
  42. return err
  43. }
  44. o, err := bufio.NewReader(r).ReadString('\n')
  45. if err != nil {
  46. return err
  47. }
  48. if strings.Trim(o, " \r\n") != output {
  49. return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", output, o)
  50. }
  51. }
  52. return nil
  53. }
  54. // Expected behaviour: the process dies when the client disconnects
  55. func TestRunDisconnect(t *testing.T) {
  56. runtime, err := newTestRuntime()
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. defer nuke(runtime)
  61. srv := &Server{runtime: runtime}
  62. stdin, stdinPipe := io.Pipe()
  63. stdout, stdoutPipe := io.Pipe()
  64. c1 := make(chan struct{})
  65. go func() {
  66. // We're simulating a disconnect so the return value doesn't matter. What matters is the
  67. // fact that CmdRun returns.
  68. srv.CmdRun(stdin, stdoutPipe, "-i", GetTestImage(runtime).Id, "/bin/cat")
  69. close(c1)
  70. }()
  71. setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
  72. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  73. t.Fatal(err)
  74. }
  75. })
  76. // Close pipes (simulate disconnect)
  77. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  78. t.Fatal(err)
  79. }
  80. // as the pipes are close, we expect the process to die,
  81. // therefore CmdRun to unblock. Wait for CmdRun
  82. setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
  83. <-c1
  84. })
  85. // Check the status of the container
  86. container := runtime.containers.Back().Value.(*Container)
  87. if container.State.Running {
  88. t.Fatalf("/bin/cat is still running after closing stdin")
  89. }
  90. }
  91. // Expected behaviour, the process stays alive when the client disconnects
  92. func TestAttachDisconnect(t *testing.T) {
  93. runtime, err := newTestRuntime()
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. defer nuke(runtime)
  98. srv := &Server{runtime: runtime}
  99. container, err := runtime.Create(
  100. &Config{
  101. Image: GetTestImage(runtime).Id,
  102. Memory: 33554432,
  103. Cmd: []string{"/bin/cat"},
  104. OpenStdin: true,
  105. },
  106. )
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. defer runtime.Destroy(container)
  111. // Start the process
  112. if err := container.Start(); err != nil {
  113. t.Fatal(err)
  114. }
  115. stdin, stdinPipe := io.Pipe()
  116. stdout, stdoutPipe := io.Pipe()
  117. // Attach to it
  118. c1 := make(chan struct{})
  119. go func() {
  120. // We're simulating a disconnect so the return value doesn't matter. What matters is the
  121. // fact that CmdAttach returns.
  122. srv.CmdAttach(stdin, stdoutPipe, container.Id)
  123. close(c1)
  124. }()
  125. setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
  126. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  127. t.Fatal(err)
  128. }
  129. })
  130. // Close pipes (client disconnects)
  131. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  132. t.Fatal(err)
  133. }
  134. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  135. setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
  136. <-c1
  137. })
  138. // We closed stdin, expect /bin/cat to still be running
  139. // Wait a little bit to make sure container.monitor() did his thing
  140. err = container.WaitTimeout(500 * time.Millisecond)
  141. if err == nil || !container.State.Running {
  142. t.Fatalf("/bin/cat is not running after closing stdin")
  143. }
  144. // Try to avoid the timeoout in destroy. Best effort, don't check error
  145. cStdin, _ := container.StdinPipe()
  146. cStdin.Close()
  147. }