github.com/rumpl/bof@v23.0.0-rc.2+incompatible/integration/container/wait_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/integration/internal/container" 11 "github.com/docker/docker/testutil/request" 12 "gotest.tools/v3/assert" 13 is "gotest.tools/v3/assert/cmp" 14 "gotest.tools/v3/poll" 15 "gotest.tools/v3/skip" 16 ) 17 18 func TestWaitNonBlocked(t *testing.T) { 19 defer setupTest(t)() 20 cli := request.NewAPIClient(t) 21 22 testCases := []struct { 23 doc string 24 cmd string 25 expectedCode int64 26 }{ 27 { 28 doc: "wait-nonblocking-exit-0", 29 cmd: "exit 0", 30 expectedCode: 0, 31 }, 32 { 33 doc: "wait-nonblocking-exit-random", 34 cmd: "exit 99", 35 expectedCode: 99, 36 }, 37 } 38 39 for _, tc := range testCases { 40 tc := tc 41 t.Run(tc.doc, func(t *testing.T) { 42 t.Parallel() 43 ctx := context.Background() 44 containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd)) 45 poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "exited"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) 46 47 waitResC, errC := cli.ContainerWait(ctx, containerID, "") 48 select { 49 case err := <-errC: 50 assert.NilError(t, err) 51 case waitRes := <-waitResC: 52 assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode)) 53 } 54 }) 55 } 56 } 57 58 func TestWaitBlocked(t *testing.T) { 59 // Windows busybox does not support trap in this way, not sleep with sub-second 60 // granularity. It will always exit 0x40010004. 61 skip.If(t, testEnv.DaemonInfo.OSType != "linux") 62 defer setupTest(t)() 63 cli := request.NewAPIClient(t) 64 65 testCases := []struct { 66 doc string 67 cmd string 68 expectedCode int64 69 }{ 70 { 71 doc: "test-wait-blocked-exit-zero", 72 cmd: "trap 'exit 0' TERM; while true; do usleep 10; done", 73 expectedCode: 0, 74 }, 75 { 76 doc: "test-wait-blocked-exit-random", 77 cmd: "trap 'exit 99' TERM; while true; do usleep 10; done", 78 expectedCode: 99, 79 }, 80 } 81 for _, tc := range testCases { 82 tc := tc 83 t.Run(tc.doc, func(t *testing.T) { 84 t.Parallel() 85 ctx := context.Background() 86 containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd)) 87 poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "running"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) 88 89 waitResC, errC := cli.ContainerWait(ctx, containerID, "") 90 91 err := cli.ContainerStop(ctx, containerID, containertypes.StopOptions{}) 92 assert.NilError(t, err) 93 94 select { 95 case err := <-errC: 96 assert.NilError(t, err) 97 case waitRes := <-waitResC: 98 assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode)) 99 case <-time.After(2 * time.Second): 100 t.Fatal("timeout waiting for `docker wait`") 101 } 102 }) 103 } 104 } 105 106 func TestWaitConditions(t *testing.T) { 107 defer setupTest(t)() 108 cli := request.NewAPIClient(t) 109 110 testCases := []struct { 111 doc string 112 waitCond containertypes.WaitCondition 113 expectedCode int64 114 }{ 115 { 116 doc: "default", 117 expectedCode: 99, 118 }, 119 { 120 doc: "not-running", 121 expectedCode: 99, 122 waitCond: containertypes.WaitConditionNotRunning, 123 }, 124 { 125 doc: "next-exit", 126 expectedCode: 99, 127 waitCond: containertypes.WaitConditionNextExit, 128 }, 129 { 130 doc: "removed", 131 expectedCode: 99, 132 waitCond: containertypes.WaitConditionRemoved, 133 }, 134 } 135 136 for _, tc := range testCases { 137 tc := tc 138 t.Run(tc.doc, func(t *testing.T) { 139 t.Parallel() 140 ctx := context.Background() 141 opts := []func(*container.TestContainerConfig){ 142 container.WithCmd("sh", "-c", "sleep 1; exit 99"), 143 } 144 if tc.waitCond == containertypes.WaitConditionRemoved { 145 opts = append(opts, container.WithAutoRemove) 146 } 147 containerID := container.Run(ctx, t, cli, opts...) 148 poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "running"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) 149 150 waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond) 151 select { 152 case err := <-errC: 153 assert.NilError(t, err) 154 case waitRes := <-waitResC: 155 assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode)) 156 } 157 }) 158 } 159 } 160 161 func TestWaitRestartedContainer(t *testing.T) { 162 defer setupTest(t)() 163 cli := request.NewAPIClient(t) 164 165 testCases := []struct { 166 doc string 167 waitCond containertypes.WaitCondition 168 }{ 169 { 170 doc: "default", 171 }, 172 { 173 doc: "not-running", 174 waitCond: containertypes.WaitConditionNotRunning, 175 }, 176 { 177 doc: "next-exit", 178 waitCond: containertypes.WaitConditionNextExit, 179 }, 180 } 181 182 // We can't catch the SIGTERM in the Windows based busybox image 183 isWindowDaemon := testEnv.DaemonInfo.OSType == "windows" 184 185 for _, tc := range testCases { 186 tc := tc 187 t.Run(tc.doc, func(t *testing.T) { 188 t.Parallel() 189 ctx := context.Background() 190 containerID := container.Run(ctx, t, cli, 191 container.WithCmd("sh", "-c", "trap 'exit 5' SIGTERM; while true; do sleep 0.1; done"), 192 ) 193 defer cli.ContainerRemove(ctx, containerID, types.ContainerRemoveOptions{Force: true}) 194 195 poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "running"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) 196 197 // Container is running now, wait for exit 198 waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond) 199 200 timeout := 5 201 // On Windows it will always timeout, because our process won't receive SIGTERM 202 // Skip to force killing immediately 203 if isWindowDaemon { 204 timeout = 0 205 } 206 207 err := cli.ContainerRestart(ctx, containerID, containertypes.StopOptions{Timeout: &timeout, Signal: "SIGTERM"}) 208 assert.NilError(t, err) 209 210 select { 211 case err := <-errC: 212 t.Fatalf("Unexpected error: %v", err) 213 case <-time.After(time.Second * 3): 214 t.Fatalf("Wait should end after restart") 215 case waitRes := <-waitResC: 216 expectedCode := int64(5) 217 218 if !isWindowDaemon { 219 assert.Check(t, is.Equal(expectedCode, waitRes.StatusCode)) 220 } 221 } 222 }) 223 } 224 }