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  }