diff --git a/integration-cli/docker_cli_wait_test.go b/integration-cli/docker_cli_wait_test.go deleted file mode 100644 index 669e54f1ae..0000000000 --- a/integration-cli/docker_cli_wait_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "bytes" - "os/exec" - "strings" - "time" - - "github.com/docker/docker/integration-cli/checker" - "github.com/go-check/check" - "gotest.tools/icmd" -) - -// non-blocking wait with 0 exit code -func (s *DockerSuite) TestWaitNonBlockedExitZero(c *check.C) { - out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "true") - containerID := strings.TrimSpace(out) - - err := waitInspect(containerID, "{{.State.Running}}", "false", 30*time.Second) - c.Assert(err, checker.IsNil) //Container should have stopped by now - - out, _ = dockerCmd(c, "wait", containerID) - c.Assert(strings.TrimSpace(out), checker.Equals, "0", check.Commentf("failed to set up container, %v", out)) - -} - -// blocking wait with 0 exit code -func (s *DockerSuite) TestWaitBlockedExitZero(c *check.C) { - // Windows busybox does not support trap in this way, not sleep with sub-second - // granularity. It will always exit 0x40010004. - testRequires(c, DaemonIsLinux) - out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "trap 'exit 0' TERM; while true; do usleep 10; done") - containerID := strings.TrimSpace(out) - - c.Assert(waitRun(containerID), checker.IsNil) - - chWait := make(chan string) - go func() { - chWait <- "" - out := icmd.RunCommand(dockerBinary, "wait", containerID).Combined() - chWait <- out - }() - - <-chWait // make sure the goroutine is started - time.Sleep(100 * time.Millisecond) - dockerCmd(c, "stop", containerID) - - select { - case status := <-chWait: - c.Assert(strings.TrimSpace(status), checker.Equals, "0", check.Commentf("expected exit 0, got %s", status)) - case <-time.After(2 * time.Second): - c.Fatal("timeout waiting for `docker wait` to exit") - } - -} - -// non-blocking wait with random exit code -func (s *DockerSuite) TestWaitNonBlockedExitRandom(c *check.C) { - out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "exit 99") - containerID := strings.TrimSpace(out) - - err := waitInspect(containerID, "{{.State.Running}}", "false", 30*time.Second) - c.Assert(err, checker.IsNil) //Container should have stopped by now - out, _ = dockerCmd(c, "wait", containerID) - c.Assert(strings.TrimSpace(out), checker.Equals, "99", check.Commentf("failed to set up container, %v", out)) - -} - -// blocking wait with random exit code -func (s *DockerSuite) TestWaitBlockedExitRandom(c *check.C) { - // Cannot run on Windows as trap in Windows busybox does not support trap in this way. - testRequires(c, DaemonIsLinux) - out, _ := dockerCmd(c, "run", "-d", "busybox", "/bin/sh", "-c", "trap 'exit 99' TERM; while true; do usleep 10; done") - containerID := strings.TrimSpace(out) - c.Assert(waitRun(containerID), checker.IsNil) - - chWait := make(chan error) - waitCmd := exec.Command(dockerBinary, "wait", containerID) - waitCmdOut := bytes.NewBuffer(nil) - waitCmd.Stdout = waitCmdOut - c.Assert(waitCmd.Start(), checker.IsNil) - go func() { - chWait <- waitCmd.Wait() - }() - - dockerCmd(c, "stop", containerID) - - select { - case err := <-chWait: - c.Assert(err, checker.IsNil, check.Commentf(waitCmdOut.String())) - status, err := waitCmdOut.ReadString('\n') - c.Assert(err, checker.IsNil) - c.Assert(strings.TrimSpace(status), checker.Equals, "99", check.Commentf("expected exit 99, got %s", status)) - case <-time.After(2 * time.Second): - waitCmd.Process.Kill() - c.Fatal("timeout waiting for `docker wait` to exit") - } -} diff --git a/integration/container/wait_test.go b/integration/container/wait_test.go new file mode 100644 index 0000000000..09edcabf1e --- /dev/null +++ b/integration/container/wait_test.go @@ -0,0 +1,102 @@ +package container // import "github.com/docker/docker/integration/container" + +import ( + "context" + "testing" + "time" + + "github.com/docker/docker/integration/internal/container" + "github.com/docker/docker/internal/test/request" + "gotest.tools/assert" + is "gotest.tools/assert/cmp" + "gotest.tools/poll" + "gotest.tools/skip" +) + +func TestWaitNonBlocked(t *testing.T) { + defer setupTest(t)() + cli := request.NewAPIClient(t) + + testCases := []struct { + doc string + cmd string + expectedCode int64 + }{ + { + doc: "wait-nonblocking-exit-0", + cmd: "exit 0", + expectedCode: 0, + }, + { + doc: "wait-nonblocking-exit-random", + cmd: "exit 99", + expectedCode: 99, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.doc, func(t *testing.T) { + t.Parallel() + ctx := context.Background() + containerID := container.Run(t, ctx, cli, container.WithCmd("sh", "-c", tc.cmd)) + poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "exited"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) + + waitresC, errC := cli.ContainerWait(ctx, containerID, "") + select { + case err := <-errC: + assert.NilError(t, err) + case waitres := <-waitresC: + assert.Check(t, is.Equal(tc.expectedCode, waitres.StatusCode)) + } + }) + } +} + +func TestWaitBlocked(t *testing.T) { + // Windows busybox does not support trap in this way, not sleep with sub-second + // granularity. It will always exit 0x40010004. + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + defer setupTest(t)() + cli := request.NewAPIClient(t) + + testCases := []struct { + doc string + cmd string + expectedCode int64 + }{ + { + doc: "test-wait-blocked-exit-zero", + cmd: "trap 'exit 0' TERM; while true; do usleep 10; done", + expectedCode: 0, + }, + { + doc: "test-wait-blocked-exit-random", + cmd: "trap 'exit 99' TERM; while true; do usleep 10; done", + expectedCode: 99, + }, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.doc, func(t *testing.T) { + t.Parallel() + ctx := context.Background() + containerID := container.Run(t, ctx, cli, container.WithCmd("sh", "-c", tc.cmd)) + poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "running"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond)) + + waitresC, errC := cli.ContainerWait(ctx, containerID, "") + + err := cli.ContainerStop(ctx, containerID, nil) + assert.NilError(t, err) + + select { + case err := <-errC: + assert.NilError(t, err) + case waitres := <-waitresC: + assert.Check(t, is.Equal(tc.expectedCode, waitres.StatusCode)) + case <-time.After(2 * time.Second): + t.Fatal("timeout waiting for `docker wait`") + } + }) + } +}