1package container // import "github.com/docker/docker/integration/container"
2
3import (
4	"context"
5	"strconv"
6	"testing"
7	"time"
8
9	"github.com/docker/docker/integration/internal/container"
10	"gotest.tools/v3/assert"
11	"gotest.tools/v3/poll"
12	"gotest.tools/v3/skip"
13)
14
15// TestStopContainerWithTimeout checks that ContainerStop with
16// a timeout works as documented, i.e. in case of negative timeout
17// waiting is not limited (issue #35311).
18func TestStopContainerWithTimeout(t *testing.T) {
19	skip.If(t, testEnv.OSType == "windows")
20	defer setupTest(t)()
21	client := testEnv.APIClient()
22	ctx := context.Background()
23
24	testCmd := container.WithCmd("sh", "-c", "sleep 2 && exit 42")
25	testData := []struct {
26		doc              string
27		timeout          int
28		expectedExitCode int
29	}{
30		// In case container is forcefully killed, 137 is returned,
31		// otherwise the exit code from the above script
32		{
33			"zero timeout: expect forceful container kill",
34			1, 0x40010004,
35		},
36		{
37			"too small timeout: expect forceful container kill",
38			2, 0x40010004,
39		},
40		{
41			"big enough timeout: expect graceful container stop",
42			120, 42,
43		},
44		{
45			"unlimited timeout: expect graceful container stop",
46			-1, 42,
47		},
48	}
49
50	for _, d := range testData {
51		d := d
52		t.Run(strconv.Itoa(d.timeout), func(t *testing.T) {
53			t.Parallel()
54			id := container.Run(ctx, t, client, testCmd)
55
56			timeout := time.Duration(d.timeout) * time.Second
57			err := client.ContainerStop(ctx, id, &timeout)
58			assert.NilError(t, err)
59
60			poll.WaitOn(t, container.IsStopped(ctx, client, id),
61				poll.WithDelay(100*time.Millisecond))
62
63			inspect, err := client.ContainerInspect(ctx, id)
64			assert.NilError(t, err)
65			assert.Equal(t, inspect.State.ExitCode, d.expectedExitCode)
66		})
67	}
68}
69