@@ -10,6 +10,7 @@ import (
1010 "strings"
1111 "time"
1212
13+ "github.com/docker/docker/integration-cli/request"
1314 "github.com/docker/docker/pkg/integration/checker"
1415 "github.com/go-check/check"
1516)
@@ -103,21 +104,7 @@ func (s *DockerSuite) TestExecApiStartMultipleTimesError(c *check.C) {
103104 runSleepingContainer (c , "-d" , "--name" , "test" )
104105 execID := createExec (c , "test" )
105106 startExec (c , execID , http .StatusOK )
106-
107- timeout := time .After (60 * time .Second )
108- var execJSON struct { Running bool }
109- for {
110- select {
111- case <- timeout :
112- c .Fatal ("timeout waiting for exec to start" )
113- default :
114- }
115-
116- inspectExec (c , execID , & execJSON )
117- if ! execJSON .Running {
118- break
119- }
120- }
107+ waitForExec (c , execID )
121108
122109 startExec (c , execID , http .StatusConflict )
123110}
@@ -152,8 +139,43 @@ func (s *DockerSuite) TestExecApiStartWithDetach(c *check.C) {
152139 }
153140}
154141
142+ // #30311
143+ func (s * DockerSuite ) TestExecAPIStartValidCommand (c * check.C ) {
144+ name := "exec_test"
145+ dockerCmd (c , "run" , "-d" , "-t" , "--name" , name , "busybox" , "/bin/sh" )
146+
147+ id := createExecCmd (c , name , "true" )
148+ startExec (c , id , http .StatusOK )
149+
150+ waitForExec (c , id )
151+
152+ var inspectJSON struct { ExecIDs []string }
153+ inspectContainer (c , name , & inspectJSON )
154+
155+ c .Assert (inspectJSON .ExecIDs , checker .IsNil )
156+ }
157+
158+ // #30311
159+ func (s * DockerSuite ) TestExecAPIStartInvalidCommand (c * check.C ) {
160+ name := "exec_test"
161+ dockerCmd (c , "run" , "-d" , "-t" , "--name" , name , "busybox" , "/bin/sh" )
162+
163+ id := createExecCmd (c , name , "invalid" )
164+ startExec (c , id , http .StatusNotFound )
165+ waitForExec (c , id )
166+
167+ var inspectJSON struct { ExecIDs []string }
168+ inspectContainer (c , name , & inspectJSON )
169+
170+ c .Assert (inspectJSON .ExecIDs , checker .IsNil )
171+ }
172+
155173func createExec (c * check.C , name string ) string {
156- _ , b , err := sockRequest ("POST" , fmt .Sprintf ("/containers/%s/exec" , name ), map [string ]interface {}{"Cmd" : []string {"true" }})
174+ return createExecCmd (c , name , "true" )
175+ }
176+
177+ func createExecCmd (c * check.C , name string , cmd string ) string {
178+ _ , b , err := request .SockRequest ("POST" , fmt .Sprintf ("/containers/%s/exec" , name ), map [string ]interface {}{"Cmd" : []string {cmd }}, daemonHost ())
157179 c .Assert (err , checker .IsNil , check .Commentf (string (b )))
158180
159181 createResp := struct {
@@ -181,3 +203,29 @@ func inspectExec(c *check.C, id string, out interface{}) {
181203 err = json .NewDecoder (body ).Decode (out )
182204 c .Assert (err , checker .IsNil )
183205}
206+
207+ func waitForExec (c * check.C , id string ) {
208+ timeout := time .After (60 * time .Second )
209+ var execJSON struct { Running bool }
210+ for {
211+ select {
212+ case <- timeout :
213+ c .Fatal ("timeout waiting for exec to start" )
214+ default :
215+ }
216+
217+ inspectExec (c , id , & execJSON )
218+ if ! execJSON .Running {
219+ break
220+ }
221+ }
222+ }
223+
224+ func inspectContainer (c * check.C , id string , out interface {}) {
225+ resp , body , err := request .SockRequestRaw ("GET" , fmt .Sprintf ("/containers/%s/json" , id ), nil , "" , daemonHost ())
226+ c .Assert (err , checker .IsNil )
227+ defer body .Close ()
228+ c .Assert (resp .StatusCode , checker .Equals , http .StatusOK )
229+ err = json .NewDecoder (body ).Decode (out )
230+ c .Assert (err , checker .IsNil )
231+ }
0 commit comments