github.com/rish1988/moby@v25.0.2+incompatible/integration/container/wait_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	containertypes "github.com/docker/docker/api/types/container"
     8  	"github.com/docker/docker/integration/internal/container"
     9  	"github.com/docker/docker/testutil"
    10  	"github.com/docker/docker/testutil/request"
    11  	"gotest.tools/v3/assert"
    12  	is "gotest.tools/v3/assert/cmp"
    13  	"gotest.tools/v3/poll"
    14  	"gotest.tools/v3/skip"
    15  )
    16  
    17  func TestWaitNonBlocked(t *testing.T) {
    18  	ctx := setupTest(t)
    19  
    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  
    44  			ctx := testutil.StartSpan(ctx, t)
    45  			containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd))
    46  			poll.WaitOn(t, container.IsInState(ctx, cli, containerID, "exited"), poll.WithTimeout(30*time.Second), poll.WithDelay(100*time.Millisecond))
    47  
    48  			waitResC, errC := cli.ContainerWait(ctx, containerID, "")
    49  			select {
    50  			case err := <-errC:
    51  				assert.NilError(t, err)
    52  			case waitRes := <-waitResC:
    53  				assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode))
    54  			}
    55  		})
    56  	}
    57  }
    58  
    59  func TestWaitBlocked(t *testing.T) {
    60  	// Windows busybox does not support trap in this way, not sleep with sub-second
    61  	// granularity. It will always exit 0x40010004.
    62  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    63  	ctx := setupTest(t)
    64  	cli := request.NewAPIClient(t)
    65  
    66  	testCases := []struct {
    67  		doc          string
    68  		cmd          string
    69  		expectedCode int64
    70  	}{
    71  		{
    72  			doc:          "test-wait-blocked-exit-zero",
    73  			cmd:          "trap 'exit 0' TERM; while true; do usleep 10; done",
    74  			expectedCode: 0,
    75  		},
    76  		{
    77  			doc:          "test-wait-blocked-exit-random",
    78  			cmd:          "trap 'exit 99' TERM; while true; do usleep 10; done",
    79  			expectedCode: 99,
    80  		},
    81  	}
    82  	for _, tc := range testCases {
    83  		tc := tc
    84  		t.Run(tc.doc, func(t *testing.T) {
    85  			t.Parallel()
    86  			ctx := testutil.StartSpan(ctx, t)
    87  			containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd))
    88  			waitResC, errC := cli.ContainerWait(ctx, containerID, "")
    89  
    90  			err := cli.ContainerStop(ctx, containerID, containertypes.StopOptions{})
    91  			assert.NilError(t, err)
    92  
    93  			select {
    94  			case err := <-errC:
    95  				assert.NilError(t, err)
    96  			case waitRes := <-waitResC:
    97  				assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode))
    98  			case <-time.After(2 * time.Second):
    99  				t.Fatal("timeout waiting for `docker wait`")
   100  			}
   101  		})
   102  	}
   103  }
   104  
   105  func TestWaitConditions(t *testing.T) {
   106  	ctx := setupTest(t)
   107  	cli := request.NewAPIClient(t)
   108  
   109  	testCases := []struct {
   110  		doc      string
   111  		waitCond containertypes.WaitCondition
   112  		runOpts  []func(*container.TestContainerConfig)
   113  	}{
   114  		{
   115  			doc: "default",
   116  		},
   117  		{
   118  			doc:      "not-running",
   119  			waitCond: containertypes.WaitConditionNotRunning,
   120  		},
   121  		{
   122  			doc:      "next-exit",
   123  			waitCond: containertypes.WaitConditionNextExit,
   124  		},
   125  		{
   126  			doc:      "removed",
   127  			waitCond: containertypes.WaitConditionRemoved,
   128  			runOpts:  []func(*container.TestContainerConfig){container.WithAutoRemove},
   129  		},
   130  	}
   131  
   132  	for _, tc := range testCases {
   133  		tc := tc
   134  		t.Run(tc.doc, func(t *testing.T) {
   135  			t.Parallel()
   136  			ctx := testutil.StartSpan(ctx, t)
   137  			opts := append([]func(*container.TestContainerConfig){
   138  				container.WithCmd("sh", "-c", "read -r; exit 99"),
   139  				func(tcc *container.TestContainerConfig) {
   140  					tcc.Config.AttachStdin = true
   141  					tcc.Config.OpenStdin = true
   142  				},
   143  			}, tc.runOpts...)
   144  			containerID := container.Create(ctx, t, cli, opts...)
   145  			t.Logf("ContainerID = %v", containerID)
   146  
   147  			streams, err := cli.ContainerAttach(ctx, containerID, containertypes.AttachOptions{Stream: true, Stdin: true})
   148  			assert.NilError(t, err)
   149  			defer streams.Close()
   150  
   151  			assert.NilError(t, cli.ContainerStart(ctx, containerID, containertypes.StartOptions{}))
   152  			waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond)
   153  			select {
   154  			case err := <-errC:
   155  				t.Fatalf("ContainerWait() err = %v", err)
   156  			case res := <-waitResC:
   157  				t.Fatalf("ContainerWait() sent exit code (%v) before ContainerStart()", res)
   158  			default:
   159  			}
   160  
   161  			info, _ := cli.ContainerInspect(ctx, containerID)
   162  			assert.Equal(t, "running", info.State.Status)
   163  
   164  			_, err = streams.Conn.Write([]byte("\n"))
   165  			assert.NilError(t, err)
   166  
   167  			select {
   168  			case err := <-errC:
   169  				assert.NilError(t, err)
   170  			case waitRes := <-waitResC:
   171  				assert.Check(t, is.Equal(int64(99), waitRes.StatusCode))
   172  			case <-time.After(StopContainerWindowsPollTimeout):
   173  				info, _ := cli.ContainerInspect(ctx, containerID)
   174  				t.Fatalf("Timed out waiting for container exit code (status = %q)", info.State.Status)
   175  			}
   176  		})
   177  	}
   178  }
   179  
   180  func TestWaitRestartedContainer(t *testing.T) {
   181  	ctx := setupTest(t)
   182  	cli := request.NewAPIClient(t)
   183  
   184  	testCases := []struct {
   185  		doc      string
   186  		waitCond containertypes.WaitCondition
   187  	}{
   188  		{
   189  			doc: "default",
   190  		},
   191  		{
   192  			doc:      "not-running",
   193  			waitCond: containertypes.WaitConditionNotRunning,
   194  		},
   195  		{
   196  			doc:      "next-exit",
   197  			waitCond: containertypes.WaitConditionNextExit,
   198  		},
   199  	}
   200  
   201  	// We can't catch the SIGTERM in the Windows based busybox image
   202  	isWindowDaemon := testEnv.DaemonInfo.OSType == "windows"
   203  
   204  	for _, tc := range testCases {
   205  		tc := tc
   206  		t.Run(tc.doc, func(t *testing.T) {
   207  			t.Parallel()
   208  			ctx := testutil.StartSpan(ctx, t)
   209  			containerID := container.Run(ctx, t, cli,
   210  				container.WithCmd("sh", "-c", "trap 'exit 5' SIGTERM; while true; do sleep 0.1; done"),
   211  			)
   212  			defer cli.ContainerRemove(ctx, containerID, containertypes.RemoveOptions{Force: true})
   213  
   214  			// Container is running now, wait for exit
   215  			waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond)
   216  
   217  			timeout := 5
   218  			// On Windows it will always timeout, because our process won't receive SIGTERM
   219  			// Skip to force killing immediately
   220  			if isWindowDaemon {
   221  				timeout = 0
   222  			}
   223  
   224  			err := cli.ContainerRestart(ctx, containerID, containertypes.StopOptions{Timeout: &timeout, Signal: "SIGTERM"})
   225  			assert.NilError(t, err)
   226  
   227  			select {
   228  			case err := <-errC:
   229  				t.Fatalf("Unexpected error: %v", err)
   230  			case <-time.After(time.Second * 3):
   231  				t.Fatalf("Wait should end after restart")
   232  			case waitRes := <-waitResC:
   233  				expectedCode := int64(5)
   234  
   235  				if !isWindowDaemon {
   236  					assert.Check(t, is.Equal(expectedCode, waitRes.StatusCode))
   237  				}
   238  			}
   239  		})
   240  	}
   241  }