health_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "context"
  4. "testing"
  5. "time"
  6. "github.com/docker/docker/api/types"
  7. containertypes "github.com/docker/docker/api/types/container"
  8. "github.com/docker/docker/client"
  9. "github.com/docker/docker/integration/internal/container"
  10. "gotest.tools/v3/assert"
  11. "gotest.tools/v3/poll"
  12. "gotest.tools/v3/skip"
  13. )
  14. // TestHealthCheckWorkdir verifies that health-checks inherit the containers'
  15. // working-dir.
  16. func TestHealthCheckWorkdir(t *testing.T) {
  17. skip.If(t, testEnv.OSType == "windows", "FIXME")
  18. defer setupTest(t)()
  19. ctx := context.Background()
  20. client := testEnv.APIClient()
  21. cID := container.Run(ctx, t, client, container.WithTty(true), container.WithWorkingDir("/foo"), func(c *container.TestContainerConfig) {
  22. c.Config.Healthcheck = &containertypes.HealthConfig{
  23. Test: []string{"CMD-SHELL", "if [ \"$PWD\" = \"/foo\" ]; then exit 0; else exit 1; fi;"},
  24. Interval: 50 * time.Millisecond,
  25. Retries: 3,
  26. }
  27. })
  28. poll.WaitOn(t, pollForHealthStatus(ctx, client, cID, types.Healthy), poll.WithDelay(100*time.Millisecond))
  29. }
  30. // GitHub #37263
  31. // Do not stop healthchecks just because we sent a signal to the container
  32. func TestHealthKillContainer(t *testing.T) {
  33. skip.If(t, testEnv.OSType == "windows", "Windows only supports SIGKILL and SIGTERM? See https://github.com/moby/moby/issues/39574")
  34. defer setupTest(t)()
  35. ctx := context.Background()
  36. client := testEnv.APIClient()
  37. id := container.Run(ctx, t, client, func(c *container.TestContainerConfig) {
  38. cmd := `
  39. # Set the initial HEALTH value so the healthcheck passes
  40. HEALTH="1"
  41. echo $HEALTH > /health
  42. # Any time doHealth is run we flip the value
  43. # This lets us use kill signals to determine when healtchecks have run.
  44. doHealth() {
  45. case "$HEALTH" in
  46. "0")
  47. HEALTH="1"
  48. ;;
  49. "1")
  50. HEALTH="0"
  51. ;;
  52. esac
  53. echo $HEALTH > /health
  54. }
  55. trap 'doHealth' USR1
  56. while true; do sleep 1; done
  57. `
  58. c.Config.Cmd = []string{"/bin/sh", "-c", cmd}
  59. c.Config.Healthcheck = &containertypes.HealthConfig{
  60. Test: []string{"CMD-SHELL", `[ "$(cat /health)" = "1" ]`},
  61. Interval: time.Second,
  62. Retries: 5,
  63. }
  64. })
  65. ctxPoll, cancel := context.WithTimeout(ctx, 30*time.Second)
  66. defer cancel()
  67. poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))
  68. err := client.ContainerKill(ctx, id, "SIGUSR1")
  69. assert.NilError(t, err)
  70. ctxPoll, cancel = context.WithTimeout(ctx, 30*time.Second)
  71. defer cancel()
  72. poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "unhealthy"), poll.WithDelay(100*time.Millisecond))
  73. err = client.ContainerKill(ctx, id, "SIGUSR1")
  74. assert.NilError(t, err)
  75. ctxPoll, cancel = context.WithTimeout(ctx, 30*time.Second)
  76. defer cancel()
  77. poll.WaitOn(t, pollForHealthStatus(ctxPoll, client, id, "healthy"), poll.WithDelay(100*time.Millisecond))
  78. }
  79. func pollForHealthStatus(ctx context.Context, client client.APIClient, containerID string, healthStatus string) func(log poll.LogT) poll.Result {
  80. return func(log poll.LogT) poll.Result {
  81. inspect, err := client.ContainerInspect(ctx, containerID)
  82. switch {
  83. case err != nil:
  84. return poll.Error(err)
  85. case inspect.State.Health.Status == healthStatus:
  86. return poll.Success()
  87. default:
  88. return poll.Continue("waiting for container to become %s", healthStatus)
  89. }
  90. }
  91. }