state_test.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. package container // import "github.com/docker/docker/container"
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/docker/docker/api/types"
  7. )
  8. func TestIsValidHealthString(t *testing.T) {
  9. contexts := []struct {
  10. Health string
  11. Expected bool
  12. }{
  13. {types.Healthy, true},
  14. {types.Unhealthy, true},
  15. {types.Starting, true},
  16. {types.NoHealthcheck, true},
  17. {"fail", false},
  18. }
  19. for _, c := range contexts {
  20. v := IsValidHealthString(c.Health)
  21. if v != c.Expected {
  22. t.Fatalf("Expected %t, but got %t", c.Expected, v)
  23. }
  24. }
  25. }
  26. func TestStateRunStop(t *testing.T) {
  27. s := NewState()
  28. // Begin another wait with WaitConditionRemoved. It should complete
  29. // within 200 milliseconds.
  30. ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
  31. defer cancel()
  32. removalWait := s.Wait(ctx, WaitConditionRemoved)
  33. // Full lifecycle two times.
  34. for i := 1; i <= 2; i++ {
  35. // A wait with WaitConditionNotRunning should return
  36. // immediately since the state is now either "created" (on the
  37. // first iteration) or "exited" (on the second iteration). It
  38. // shouldn't take more than 50 milliseconds.
  39. ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
  40. defer cancel()
  41. // Expectx exit code to be i-1 since it should be the exit
  42. // code from the previous loop or 0 for the created state.
  43. if status := <-s.Wait(ctx, WaitConditionNotRunning); status.ExitCode() != i-1 {
  44. t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i-1, status.Err())
  45. }
  46. // A wait with WaitConditionNextExit should block until the
  47. // container has started and exited. It shouldn't take more
  48. // than 100 milliseconds.
  49. ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
  50. defer cancel()
  51. initialWait := s.Wait(ctx, WaitConditionNextExit)
  52. // Set the state to "Running".
  53. s.Lock()
  54. s.SetRunning(i, true)
  55. s.Unlock()
  56. // Assert desired state.
  57. if !s.IsRunning() {
  58. t.Fatal("State not running")
  59. }
  60. if s.Pid != i {
  61. t.Fatalf("Pid %v, expected %v", s.Pid, i)
  62. }
  63. if s.ExitCode() != 0 {
  64. t.Fatalf("ExitCode %v, expected 0", s.ExitCode())
  65. }
  66. // Now that it's running, a wait with WaitConditionNotRunning
  67. // should block until we stop the container. It shouldn't take
  68. // more than 100 milliseconds.
  69. ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
  70. defer cancel()
  71. exitWait := s.Wait(ctx, WaitConditionNotRunning)
  72. // Set the state to "Exited".
  73. s.Lock()
  74. s.SetStopped(&ExitStatus{ExitCode: i})
  75. s.Unlock()
  76. // Assert desired state.
  77. if s.IsRunning() {
  78. t.Fatal("State is running")
  79. }
  80. if s.ExitCode() != i {
  81. t.Fatalf("ExitCode %v, expected %v", s.ExitCode(), i)
  82. }
  83. if s.Pid != 0 {
  84. t.Fatalf("Pid %v, expected 0", s.Pid)
  85. }
  86. // Receive the initialWait result.
  87. if status := <-initialWait; status.ExitCode() != i {
  88. t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err())
  89. }
  90. // Receive the exitWait result.
  91. if status := <-exitWait; status.ExitCode() != i {
  92. t.Fatalf("ExitCode %v, expected %v, err %q", status.ExitCode(), i, status.Err())
  93. }
  94. }
  95. // Set the state to dead and removed.
  96. s.Lock()
  97. s.Dead = true
  98. s.Unlock()
  99. s.SetRemoved()
  100. // Wait for removed status or timeout.
  101. if status := <-removalWait; status.ExitCode() != 2 {
  102. // Should have the final exit code from the loop.
  103. t.Fatalf("Removal wait exitCode %v, expected %v, err %q", status.ExitCode(), 2, status.Err())
  104. }
  105. }
  106. func TestStateTimeoutWait(t *testing.T) {
  107. s := NewState()
  108. s.Lock()
  109. s.SetRunning(0, true)
  110. s.Unlock()
  111. // Start a wait with a timeout.
  112. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
  113. defer cancel()
  114. waitC := s.Wait(ctx, WaitConditionNotRunning)
  115. // It should timeout *before* this 200ms timer does.
  116. select {
  117. case <-time.After(200 * time.Millisecond):
  118. t.Fatal("Stop callback doesn't fire in 200 milliseconds")
  119. case status := <-waitC:
  120. t.Log("Stop callback fired")
  121. // Should be a timeout error.
  122. if status.Err() == nil {
  123. t.Fatal("expected timeout error, got nil")
  124. }
  125. if status.ExitCode() != -1 {
  126. t.Fatalf("expected exit code %v, got %v", -1, status.ExitCode())
  127. }
  128. }
  129. s.Lock()
  130. s.SetStopped(&ExitStatus{ExitCode: 0})
  131. s.Unlock()
  132. // Start another wait with a timeout. This one should return
  133. // immediately.
  134. ctx, cancel = context.WithTimeout(context.Background(), 100*time.Millisecond)
  135. defer cancel()
  136. waitC = s.Wait(ctx, WaitConditionNotRunning)
  137. select {
  138. case <-time.After(200 * time.Millisecond):
  139. t.Fatal("Stop callback doesn't fire in 200 milliseconds")
  140. case status := <-waitC:
  141. t.Log("Stop callback fired")
  142. if status.ExitCode() != 0 {
  143. t.Fatalf("expected exit code %v, got %v, err %q", 0, status.ExitCode(), status.Err())
  144. }
  145. }
  146. }
  147. func TestIsValidStateString(t *testing.T) {
  148. states := []struct {
  149. state string
  150. expected bool
  151. }{
  152. {"paused", true},
  153. {"restarting", true},
  154. {"running", true},
  155. {"dead", true},
  156. {"start", false},
  157. {"created", true},
  158. {"exited", true},
  159. {"removing", true},
  160. {"stop", false},
  161. }
  162. for _, s := range states {
  163. v := IsValidStateString(s.state)
  164. if v != s.expected {
  165. t.Fatalf("Expected %t, but got %t", s.expected, v)
  166. }
  167. }
  168. }