Browse code

client: ExecCreateResult: define local type with ID field

The `ExecCreateResult` was embedding the `container.ExecCreateRespons`,
which in itself was an alias for `common.IDResponse`. This type has a
single field (`ID`) currently, but the embedding made it awkward to use,
for example, when mocking a `ExecCreateResult` using struct-literals:

func execCreateWithID(_ string, _ client.ExecCreateOptions) (client.ExecCreateResult, error) {
return client.ExecCreateResult{ExecCreateResponse: container.ExecCreateResponse{ID: "execid"}}, nil
}

This patch defines it as a local type with the `ID` as field.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2025/10/24 19:54:41
Showing 7 changed files
... ...
@@ -26,7 +26,7 @@ type ExecCreateOptions struct {
26 26
 
27 27
 // ExecCreateResult holds the result of creating a container exec.
28 28
 type ExecCreateResult struct {
29
-	container.ExecCreateResponse
29
+	ID string
30 30
 }
31 31
 
32 32
 // ExecCreate creates a new exec configuration to run an exec process.
... ...
@@ -58,7 +58,7 @@ func (cli *Client) ExecCreate(ctx context.Context, containerID string, options E
58 58
 
59 59
 	var response container.ExecCreateResponse
60 60
 	err = json.NewDecoder(resp.Body).Decode(&response)
61
-	return ExecCreateResult{ExecCreateResponse: response}, err
61
+	return ExecCreateResult{ID: response.ID}, err
62 62
 }
63 63
 
64 64
 type execStartAttachOptions struct {
... ...
@@ -68,11 +68,11 @@ func TestExecCreate(t *testing.T) {
68 68
 	)
69 69
 	assert.NilError(t, err)
70 70
 
71
-	r, err := client.ExecCreate(context.Background(), "container_id", ExecCreateOptions{
71
+	res, err := client.ExecCreate(context.Background(), "container_id", ExecCreateOptions{
72 72
 		User: "user",
73 73
 	})
74 74
 	assert.NilError(t, err)
75
-	assert.Check(t, is.Equal(r.ID, "exec_id"))
75
+	assert.Check(t, is.Equal(res.ID, "exec_id"))
76 76
 }
77 77
 
78 78
 func TestExecStartError(t *testing.T) {
... ...
@@ -128,13 +128,13 @@ func (s *DockerAPISuite) TestExecAPIStartWithDetach(c *testing.T) {
128 128
 	assert.NilError(c, err)
129 129
 	defer apiClient.Close()
130 130
 
131
-	createResp, err := apiClient.ExecCreate(ctx, name, client.ExecCreateOptions{
131
+	res, err := apiClient.ExecCreate(ctx, name, client.ExecCreateOptions{
132 132
 		Cmd:          []string{"true"},
133 133
 		AttachStderr: true,
134 134
 	})
135 135
 	assert.NilError(c, err)
136 136
 
137
-	_, body, err := request.Post(ctx, fmt.Sprintf("/exec/%s/start", createResp.ID), request.RawString(`{"Detach": true}`), request.JSON)
137
+	_, body, err := request.Post(ctx, fmt.Sprintf("/exec/%s/start", res.ID), request.RawString(`{"Detach": true}`), request.JSON)
138 138
 	assert.NilError(c, err)
139 139
 
140 140
 	b, err := request.ReadBody(body)
... ...
@@ -33,14 +33,14 @@ func TestExecWithCloseStdin(t *testing.T) {
33 33
 	cID := container.Run(ctx, t, apiClient)
34 34
 
35 35
 	const expected = "closeIO"
36
-	execResp, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
36
+	res, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
37 37
 		AttachStdin:  true,
38 38
 		AttachStdout: true,
39 39
 		Cmd:          []string{"sh", "-c", "cat && echo " + expected},
40 40
 	})
41 41
 	assert.NilError(t, err)
42 42
 
43
-	resp, err := apiClient.ExecAttach(ctx, execResp.ID, client.ExecAttachOptions{})
43
+	resp, err := apiClient.ExecAttach(ctx, res.ID, client.ExecAttachOptions{})
44 44
 	assert.NilError(t, err)
45 45
 	defer resp.Close()
46 46
 
... ...
@@ -88,7 +88,7 @@ func TestExec(t *testing.T) {
88 88
 
89 89
 	cID := container.Run(ctx, t, apiClient, container.WithTty(true), container.WithWorkingDir("/root"))
90 90
 
91
-	id, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
91
+	res, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
92 92
 		WorkingDir:   "/tmp",
93 93
 		Env:          []string{"FOO=BAR"},
94 94
 		AttachStdout: true,
... ...
@@ -96,11 +96,11 @@ func TestExec(t *testing.T) {
96 96
 	})
97 97
 	assert.NilError(t, err)
98 98
 
99
-	inspect, err := apiClient.ExecInspect(ctx, id.ID, client.ExecInspectOptions{})
99
+	inspect, err := apiClient.ExecInspect(ctx, res.ID, client.ExecInspectOptions{})
100 100
 	assert.NilError(t, err)
101
-	assert.Check(t, is.Equal(inspect.ExecID, id.ID))
101
+	assert.Check(t, is.Equal(inspect.ExecID, res.ID))
102 102
 
103
-	resp, err := apiClient.ExecAttach(ctx, id.ID, client.ExecAttachOptions{})
103
+	resp, err := apiClient.ExecAttach(ctx, res.ID, client.ExecAttachOptions{})
104 104
 	assert.NilError(t, err)
105 105
 	defer resp.Close()
106 106
 	r, err := io.ReadAll(resp.Reader)
... ...
@@ -126,12 +126,12 @@ func TestExecResize(t *testing.T) {
126 126
 	if runtime.GOOS == "windows" {
127 127
 		cmd = []string{"sleep", "240"}
128 128
 	}
129
-	resp, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
129
+	res, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
130 130
 		Tty: true, // Windows requires a TTY for the resize to work, otherwise fails with "is not a tty: failed precondition", see https://github.com/moby/moby/pull/48665#issuecomment-2412530345
131 131
 		Cmd: cmd,
132 132
 	})
133 133
 	assert.NilError(t, err)
134
-	execID := resp.ID
134
+	execID := res.ID
135 135
 	assert.NilError(t, err)
136 136
 	_, err = apiClient.ExecStart(ctx, execID, client.ExecStartOptions{
137 137
 		Detach: true,
... ...
@@ -58,11 +58,11 @@ func Exec(ctx context.Context, apiClient client.APIClient, id string, cmd []stri
58 58
 		op(&execOptions)
59 59
 	}
60 60
 
61
-	cresp, err := apiClient.ExecCreate(ctx, id, execOptions)
61
+	res, err := apiClient.ExecCreate(ctx, id, execOptions)
62 62
 	if err != nil {
63 63
 		return ExecResult{}, err
64 64
 	}
65
-	execID := cresp.ID
65
+	execID := res.ID
66 66
 
67 67
 	// run it, with stdout/stderr attached
68 68
 	aresp, err := apiClient.ExecAttach(ctx, execID, client.ExecAttachOptions{})
... ...
@@ -237,10 +237,10 @@ func ExecTask(ctx context.Context, t *testing.T, d *daemon.Daemon, task swarmtyp
237 237
 	apiClient := d.NewClientT(t)
238 238
 	defer apiClient.Close()
239 239
 
240
-	resp, err := apiClient.ExecCreate(ctx, task.Status.ContainerStatus.ContainerID, options)
240
+	res, err := apiClient.ExecCreate(ctx, task.Status.ContainerStatus.ContainerID, options)
241 241
 	assert.NilError(t, err, "error creating exec")
242 242
 
243
-	attach, err := apiClient.ExecAttach(ctx, resp.ID, client.ExecAttachOptions{})
243
+	attach, err := apiClient.ExecAttach(ctx, res.ID, client.ExecAttachOptions{})
244 244
 	assert.NilError(t, err, "error attaching to exec")
245 245
 	return attach.HijackedResponse
246 246
 }
... ...
@@ -25,7 +25,7 @@ func TestEventsExecDie(t *testing.T) {
25 25
 
26 26
 	cID := container.Run(ctx, t, apiClient)
27 27
 
28
-	id, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
28
+	res, err := apiClient.ExecCreate(ctx, cID, client.ExecCreateOptions{
29 29
 		Cmd: []string{"echo", "hello"},
30 30
 	})
31 31
 	assert.NilError(t, err)
... ...
@@ -34,7 +34,7 @@ func TestEventsExecDie(t *testing.T) {
34 34
 		Filters: make(client.Filters).Add("container", cID).Add("event", string(events.ActionExecDie)),
35 35
 	})
36 36
 
37
-	_, err = apiClient.ExecStart(ctx, id.ID, client.ExecStartOptions{
37
+	_, err = apiClient.ExecStart(ctx, res.ID, client.ExecStartOptions{
38 38
 		Detach: true,
39 39
 		Tty:    false,
40 40
 	})
... ...
@@ -45,7 +45,7 @@ func TestEventsExecDie(t *testing.T) {
45 45
 		assert.Equal(t, m.Type, events.ContainerEventType)
46 46
 		assert.Equal(t, m.Actor.ID, cID)
47 47
 		assert.Equal(t, m.Action, events.ActionExecDie)
48
-		assert.Equal(t, m.Actor.Attributes["execID"], id.ID)
48
+		assert.Equal(t, m.Actor.Attributes["execID"], res.ID)
49 49
 		assert.Equal(t, m.Actor.Attributes["exitCode"], "0")
50 50
 	case err = <-errs:
51 51
 		assert.NilError(t, err)