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 }