github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/integration/container/restart_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/api/types/container"
    11  	"github.com/docker/docker/client"
    12  	"github.com/docker/docker/testutil/daemon"
    13  	"gotest.tools/v3/assert"
    14  	"gotest.tools/v3/poll"
    15  	"gotest.tools/v3/skip"
    16  )
    17  
    18  func TestDaemonRestartKillContainers(t *testing.T) {
    19  	skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
    20  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
    21  	skip.If(t, testEnv.IsRootless, "rootless mode doesn't support live-restore")
    22  	type testCase struct {
    23  		desc       string
    24  		config     *container.Config
    25  		hostConfig *container.HostConfig
    26  
    27  		xRunning            bool
    28  		xRunningLiveRestore bool
    29  		xStart              bool
    30  		xHealthCheck        bool
    31  	}
    32  
    33  	for _, tc := range []testCase{
    34  		{
    35  			desc:                "container without restart policy",
    36  			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
    37  			xRunningLiveRestore: true,
    38  			xStart:              true,
    39  		},
    40  		{
    41  			desc:                "container with restart=always",
    42  			config:              &container.Config{Image: "busybox", Cmd: []string{"top"}},
    43  			hostConfig:          &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
    44  			xRunning:            true,
    45  			xRunningLiveRestore: true,
    46  			xStart:              true,
    47  		},
    48  		{
    49  			desc: "container with restart=always and with healthcheck",
    50  			config: &container.Config{Image: "busybox", Cmd: []string{"top"},
    51  				Healthcheck: &container.HealthConfig{
    52  					Test:     []string{"CMD-SHELL", "sleep 1"},
    53  					Interval: time.Second,
    54  				},
    55  			},
    56  			hostConfig:          &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
    57  			xRunning:            true,
    58  			xRunningLiveRestore: true,
    59  			xStart:              true,
    60  			xHealthCheck:        true,
    61  		},
    62  		{
    63  			desc:       "container created should not be restarted",
    64  			config:     &container.Config{Image: "busybox", Cmd: []string{"top"}},
    65  			hostConfig: &container.HostConfig{RestartPolicy: container.RestartPolicy{Name: "always"}},
    66  		},
    67  	} {
    68  		for _, liveRestoreEnabled := range []bool{false, true} {
    69  			for fnName, stopDaemon := range map[string]func(*testing.T, *daemon.Daemon){
    70  				"kill-daemon": func(t *testing.T, d *daemon.Daemon) {
    71  					err := d.Kill()
    72  					assert.NilError(t, err)
    73  				},
    74  				"stop-daemon": func(t *testing.T, d *daemon.Daemon) {
    75  					d.Stop(t)
    76  				},
    77  			} {
    78  				t.Run(fmt.Sprintf("live-restore=%v/%s/%s", liveRestoreEnabled, tc.desc, fnName), func(t *testing.T) {
    79  					c := tc
    80  					liveRestoreEnabled := liveRestoreEnabled
    81  					stopDaemon := stopDaemon
    82  
    83  					t.Parallel()
    84  
    85  					d := daemon.New(t)
    86  					client := d.NewClientT(t)
    87  
    88  					args := []string{"--iptables=false"}
    89  					if liveRestoreEnabled {
    90  						args = append(args, "--live-restore")
    91  					}
    92  
    93  					d.StartWithBusybox(t, args...)
    94  					defer d.Stop(t)
    95  					ctx := context.Background()
    96  
    97  					resp, err := client.ContainerCreate(ctx, c.config, c.hostConfig, nil, nil, "")
    98  					assert.NilError(t, err)
    99  					defer client.ContainerRemove(ctx, resp.ID, types.ContainerRemoveOptions{Force: true})
   100  
   101  					if c.xStart {
   102  						err = client.ContainerStart(ctx, resp.ID, types.ContainerStartOptions{})
   103  						assert.NilError(t, err)
   104  					}
   105  
   106  					stopDaemon(t, d)
   107  					d.Start(t, args...)
   108  
   109  					expected := c.xRunning
   110  					if liveRestoreEnabled {
   111  						expected = c.xRunningLiveRestore
   112  					}
   113  
   114  					var running bool
   115  					for i := 0; i < 30; i++ {
   116  						inspect, err := client.ContainerInspect(ctx, resp.ID)
   117  						assert.NilError(t, err)
   118  
   119  						running = inspect.State.Running
   120  						if running == expected {
   121  							break
   122  						}
   123  						time.Sleep(2 * time.Second)
   124  
   125  					}
   126  					assert.Equal(t, expected, running, "got unexpected running state, expected %v, got: %v", expected, running)
   127  
   128  					if c.xHealthCheck {
   129  						startTime := time.Now()
   130  						ctxPoll, cancel := context.WithTimeout(ctx, 30*time.Second)
   131  						defer cancel()
   132  						poll.WaitOn(t, pollForNewHealthCheck(ctxPoll, client, startTime, resp.ID), poll.WithDelay(100*time.Millisecond))
   133  					}
   134  					// TODO(cpuguy83): test pause states... this seems to be rather undefined currently
   135  				})
   136  			}
   137  		}
   138  	}
   139  }
   140  
   141  func pollForNewHealthCheck(ctx context.Context, client *client.Client, startTime time.Time, containerID string) func(log poll.LogT) poll.Result {
   142  	return func(log poll.LogT) poll.Result {
   143  		inspect, err := client.ContainerInspect(ctx, containerID)
   144  		if err != nil {
   145  			return poll.Error(err)
   146  		}
   147  		healthChecksTotal := len(inspect.State.Health.Log)
   148  		if healthChecksTotal > 0 {
   149  			if inspect.State.Health.Log[healthChecksTotal-1].Start.After(startTime) {
   150  				return poll.Success()
   151  			}
   152  		}
   153  		return poll.Continue("waiting for a new container healthcheck")
   154  	}
   155  }