github.com/lacework-dev/go-moby@v20.10.12+incompatible/integration/container/health_test.go (about)

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