Skip to content

Commit d3eb04f

Browse files
authored
Merge pull request moby#51312 from austinvazquez/refactor-client-container-wait
client: refactor ContainerWait to use client defined options/results structs
2 parents 40bf2b0 + cf173bc commit d3eb04f

File tree

9 files changed

+79
-57
lines changed

9 files changed

+79
-57
lines changed

client/client_interfaces.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ type ContainerAPIClient interface {
7676
ContainerTop(ctx context.Context, container string, options ContainerTopOptions) (ContainerTopResult, error)
7777
ContainerUnpause(ctx context.Context, container string, options ContainerUnPauseOptions) (ContainerUnPauseResult, error)
7878
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error)
79-
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error)
79+
ContainerWait(ctx context.Context, container string, options ContainerWaitOptions) ContainerWaitResult
8080
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
8181
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options CopyToContainerOptions) error
8282
ContainersPrune(ctx context.Context, opts ContainerPruneOptions) (ContainerPruneResult, error)

client/container_wait.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ import (
1313

1414
const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
1515

16+
// ContainerWaitOptions holds options for container wait operations.
17+
type ContainerWaitOptions struct {
18+
Condition container.WaitCondition
19+
}
20+
21+
// ContainerWaitResult defines the result of a container wait operation.
22+
type ContainerWaitResult struct {
23+
Results <-chan container.WaitResponse
24+
Errors <-chan error
25+
}
26+
1627
// ContainerWait waits until the specified container is in a certain state
1728
// indicated by the given condition, either "not-running" ([container.WaitConditionNotRunning])
1829
// (default), "next-exit" ([container.WaitConditionNextExit]), or "removed".
@@ -30,26 +41,26 @@ const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
3041
// synchronize ContainerWait with other calls, such as specifying a
3142
// "next-exit" condition ([container.WaitConditionNextExit]) before
3243
// issuing a [Client.ContainerStart] request.
33-
func (cli *Client) ContainerWait(ctx context.Context, containerID string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
44+
func (cli *Client) ContainerWait(ctx context.Context, containerID string, options ContainerWaitOptions) ContainerWaitResult {
3445
resultC := make(chan container.WaitResponse)
3546
errC := make(chan error, 1)
3647

3748
containerID, err := trimID("container", containerID)
3849
if err != nil {
3950
errC <- err
40-
return resultC, errC
51+
return ContainerWaitResult{Results: resultC, Errors: errC}
4152
}
4253

4354
query := url.Values{}
44-
if condition != "" {
45-
query.Set("condition", string(condition))
55+
if options.Condition != "" {
56+
query.Set("condition", string(options.Condition))
4657
}
4758

4859
resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", query, nil, nil)
4960
if err != nil {
5061
defer ensureReaderClosed(resp)
5162
errC <- err
52-
return resultC, errC
63+
return ContainerWaitResult{Results: resultC, Errors: errC}
5364
}
5465

5566
go func() {
@@ -80,7 +91,7 @@ func (cli *Client) ContainerWait(ctx context.Context, containerID string, condit
8091
resultC <- res
8192
}()
8293

83-
return resultC, errC
94+
return ContainerWaitResult{Results: resultC, Errors: errC}
8495
}
8596

8697
// legacyContainerWait returns immediately and doesn't have an option to wait

client/container_wait_test.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ import (
2121
func TestContainerWaitError(t *testing.T) {
2222
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
2323
assert.NilError(t, err)
24-
resultC, errC := client.ContainerWait(context.Background(), "nothing", "")
24+
wait := client.ContainerWait(context.Background(), "nothing", ContainerWaitOptions{})
2525
select {
26-
case result := <-resultC:
26+
case result := <-wait.Results:
2727
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
28-
case err := <-errC:
28+
case err := <-wait.Errors:
2929
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
3030
}
3131
}
@@ -38,11 +38,11 @@ func TestContainerWaitConnectionError(t *testing.T) {
3838
client, err := NewClientWithOpts(WithAPIVersionNegotiation(), WithHost("tcp://no-such-host.invalid"))
3939
assert.NilError(t, err)
4040

41-
resultC, errC := client.ContainerWait(context.Background(), "nothing", "")
41+
wait := client.ContainerWait(context.Background(), "nothing", ContainerWaitOptions{})
4242
select {
43-
case result := <-resultC:
43+
case result := <-wait.Results:
4444
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
45-
case err := <-errC:
45+
case err := <-wait.Errors:
4646
assert.Check(t, is.ErrorType(err, IsErrConnectionFailed))
4747
}
4848
}
@@ -59,11 +59,11 @@ func TestContainerWait(t *testing.T) {
5959
}))
6060
assert.NilError(t, err)
6161

62-
resultC, errC := client.ContainerWait(context.Background(), "container_id", "")
62+
wait := client.ContainerWait(context.Background(), "container_id", ContainerWaitOptions{})
6363
select {
64-
case err := <-errC:
64+
case err := <-wait.Errors:
6565
assert.NilError(t, err)
66-
case result := <-resultC:
66+
case result := <-wait.Results:
6767
assert.Check(t, is.Equal(result.StatusCode, int64(15)))
6868
}
6969
}
@@ -82,11 +82,11 @@ func TestContainerWaitProxyInterrupt(t *testing.T) {
8282
}))
8383
assert.NilError(t, err)
8484

85-
resultC, errC := client.ContainerWait(context.Background(), "container_id", "")
85+
wait := client.ContainerWait(context.Background(), "container_id", ContainerWaitOptions{})
8686
select {
87-
case err := <-errC:
87+
case err := <-wait.Errors:
8888
assert.Check(t, is.ErrorContains(err, expErr))
89-
case result := <-resultC:
89+
case result := <-wait.Results:
9090
t.Fatalf("Unexpected result: %v", result)
9191
}
9292
}
@@ -102,12 +102,12 @@ func TestContainerWaitProxyInterruptLong(t *testing.T) {
102102
}))
103103
assert.NilError(t, err)
104104

105-
resultC, errC := client.ContainerWait(context.Background(), "container_id", "")
105+
wait := client.ContainerWait(context.Background(), "container_id", ContainerWaitOptions{})
106106
select {
107-
case err := <-errC:
107+
case err := <-wait.Errors:
108108
// LimitReader limiting isn't exact, because of how the Readers do chunking.
109109
assert.Check(t, len(err.Error()) <= containerWaitErrorMsgLimit*2, "Expected error to be limited around %d, actual length: %d", containerWaitErrorMsgLimit, len(err.Error()))
110-
case result := <-resultC:
110+
case result := <-wait.Results:
111111
t.Fatalf("Unexpected result: %v", result)
112112
}
113113
}
@@ -134,12 +134,12 @@ func TestContainerWaitErrorHandling(t *testing.T) {
134134
}, nil
135135
}))
136136
assert.NilError(t, err)
137-
resultC, errC := client.ContainerWait(ctx, "container_id", "")
137+
wait := client.ContainerWait(ctx, "container_id", ContainerWaitOptions{})
138138
select {
139-
case err := <-errC:
139+
case err := <-wait.Errors:
140140
assert.Check(t, is.Equal(err.Error(), test.exp.Error()))
141141
return
142-
case result := <-resultC:
142+
case result := <-wait.Results:
143143
t.Fatalf("expected to not get a wait result, got %d", result.StatusCode)
144144
return
145145
}
@@ -153,8 +153,8 @@ func ExampleClient_ContainerWait_withTimeout() {
153153
defer cancel()
154154

155155
client, _ := NewClientWithOpts(FromEnv)
156-
_, errC := client.ContainerWait(ctx, "container_id", "")
157-
if err := <-errC; err != nil {
156+
wait := client.ContainerWait(ctx, "container_id", ContainerWaitOptions{})
157+
if err := <-wait.Errors; err != nil {
158158
log.Fatal(err)
159159
}
160160
}

integration-cli/docker_api_containers_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -820,12 +820,12 @@ func (s *DockerAPISuite) TestContainerAPIWait(c *testing.T) {
820820
assert.NilError(c, err)
821821
defer apiClient.Close()
822822

823-
waitResC, errC := apiClient.ContainerWait(testutil.GetContext(c), name, "")
823+
wait := apiClient.ContainerWait(testutil.GetContext(c), name, client.ContainerWaitOptions{})
824824

825825
select {
826-
case err = <-errC:
826+
case err = <-wait.Errors:
827827
assert.NilError(c, err)
828-
case waitRes := <-waitResC:
828+
case waitRes := <-wait.Results:
829829
assert.Equal(c, waitRes.StatusCode, int64(0))
830830
}
831831
}

integration/container/create_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ func TestCreateTmpfsOverrideAnonymousVolume(t *testing.T) {
498498
// Normally an anonymous volume would, except now tmpfs should prevent that.
499499
assert.Assert(t, is.Len(inspect.Container.Mounts, 0))
500500

501-
chWait, chErr := apiClient.ContainerWait(ctx, id, container.WaitConditionNextExit)
501+
wait := apiClient.ContainerWait(ctx, id, client.ContainerWaitOptions{Condition: container.WaitConditionNextExit})
502502
_, err = apiClient.ContainerStart(ctx, id, client.ContainerStartOptions{})
503503
assert.NilError(t, err)
504504

@@ -508,13 +508,13 @@ func TestCreateTmpfsOverrideAnonymousVolume(t *testing.T) {
508508
select {
509509
case <-timeout.C:
510510
t.Fatal("timeout waiting for container to exit")
511-
case status := <-chWait:
511+
case status := <-wait.Results:
512512
var errMsg string
513513
if status.Error != nil {
514514
errMsg = status.Error.Message
515515
}
516516
assert.Equal(t, int(status.StatusCode), 0, errMsg)
517-
case err := <-chErr:
517+
case err := <-wait.Errors:
518518
assert.NilError(t, err)
519519
}
520520
}

integration/container/daemon_linux_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,10 @@ func TestRestartDaemonWithRestartingContainer(t *testing.T) {
216216

217217
ctxTimeout, cancel := context.WithTimeout(ctx, 30*time.Second)
218218
defer cancel()
219-
chOk, chErr := apiClient.ContainerWait(ctxTimeout, id, containertypes.WaitConditionNextExit)
219+
wait := apiClient.ContainerWait(ctxTimeout, id, client.ContainerWaitOptions{Condition: containertypes.WaitConditionNextExit})
220220
select {
221-
case <-chOk:
222-
case err := <-chErr:
221+
case <-wait.Results:
222+
case err := <-wait.Errors:
223223
assert.NilError(t, err)
224224
}
225225
}

integration/container/wait_test.go

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ func TestWaitNonBlocked(t *testing.T) {
4545
containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd))
4646
poll.WaitOn(t, container.IsInState(ctx, cli, containerID, containertypes.StateExited), poll.WithTimeout(30*time.Second))
4747

48-
waitResC, errC := cli.ContainerWait(ctx, containerID, "")
48+
wait := cli.ContainerWait(ctx, containerID, client.ContainerWaitOptions{})
4949
select {
50-
case err := <-errC:
50+
case err := <-wait.Errors:
5151
assert.NilError(t, err)
52-
case waitRes := <-waitResC:
52+
case waitRes := <-wait.Results:
5353
assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode))
5454
}
5555
})
@@ -85,15 +85,15 @@ func TestWaitBlocked(t *testing.T) {
8585
// t.Parallel()
8686
ctx := testutil.StartSpan(ctx, t)
8787
containerID := container.Run(ctx, t, cli, container.WithCmd("sh", "-c", tc.cmd))
88-
waitResC, errC := cli.ContainerWait(ctx, containerID, "")
88+
wait := cli.ContainerWait(ctx, containerID, client.ContainerWaitOptions{})
8989

9090
_, err := cli.ContainerStop(ctx, containerID, client.ContainerStopOptions{})
9191
assert.NilError(t, err)
9292

9393
select {
94-
case err := <-errC:
94+
case err := <-wait.Errors:
9595
assert.NilError(t, err)
96-
case waitRes := <-waitResC:
96+
case waitRes := <-wait.Results:
9797
assert.Check(t, is.Equal(tc.expectedCode, waitRes.StatusCode))
9898
case <-time.After(2 * time.Second):
9999
t.Fatal("timeout waiting for `docker wait`")
@@ -150,11 +150,11 @@ func TestWaitConditions(t *testing.T) {
150150

151151
_, err = cli.ContainerStart(ctx, containerID, client.ContainerStartOptions{})
152152
assert.NilError(t, err)
153-
waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond)
153+
wait := cli.ContainerWait(ctx, containerID, client.ContainerWaitOptions{Condition: tc.waitCond})
154154
select {
155-
case err := <-errC:
155+
case err := <-wait.Errors:
156156
t.Fatalf("ContainerWait() err = %v", err)
157-
case res := <-waitResC:
157+
case res := <-wait.Results:
158158
t.Fatalf("ContainerWait() sent exit code (%v) before ContainerStart()", res)
159159
default:
160160
}
@@ -166,9 +166,9 @@ func TestWaitConditions(t *testing.T) {
166166
assert.NilError(t, err)
167167

168168
select {
169-
case err := <-errC:
169+
case err := <-wait.Errors:
170170
assert.NilError(t, err)
171-
case waitRes := <-waitResC:
171+
case waitRes := <-wait.Results:
172172
assert.Check(t, is.Equal(int64(99), waitRes.StatusCode))
173173
case <-time.After(StopContainerWindowsPollTimeout):
174174
ctr, _ := cli.ContainerInspect(ctx, containerID, client.ContainerInspectOptions{})
@@ -213,7 +213,7 @@ func TestWaitRestartedContainer(t *testing.T) {
213213
defer cli.ContainerRemove(ctx, containerID, client.ContainerRemoveOptions{Force: true})
214214

215215
// Container is running now, wait for exit
216-
waitResC, errC := cli.ContainerWait(ctx, containerID, tc.waitCond)
216+
wait := cli.ContainerWait(ctx, containerID, client.ContainerWaitOptions{Condition: tc.waitCond})
217217

218218
timeout := 10
219219
// On Windows it will always timeout, because our process won't receive SIGTERM
@@ -229,11 +229,11 @@ func TestWaitRestartedContainer(t *testing.T) {
229229
assert.NilError(t, err)
230230

231231
select {
232-
case err := <-errC:
232+
case err := <-wait.Errors:
233233
t.Fatalf("Unexpected error: %v", err)
234234
case <-time.After(time.Second * 3):
235235
t.Fatalf("Wait should end after restart")
236-
case waitRes := <-waitResC:
236+
case waitRes := <-wait.Results:
237237
expectedCode := int64(5)
238238

239239
if !isWindowDaemon {

vendor/github.com/moby/moby/client/client_interfaces.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/moby/moby/client/container_wait.go

Lines changed: 17 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)