diff --git a/dockertest.go b/dockertest.go index 396e6c79..0c2714b6 100644 --- a/dockertest.go +++ b/dockertest.go @@ -117,8 +117,8 @@ func (r *Resource) Exec(cmd []string, opts ExecOptions) (exitCode int, err error Container: r.Container.ID, Cmd: cmd, Env: opts.Env, - AttachStderr: opts.StdErr != nil, - AttachStdout: opts.StdOut != nil, + AttachStderr: true, + AttachStdout: true, AttachStdin: opts.StdIn != nil, Tty: opts.TTY, }) @@ -126,6 +126,16 @@ func (r *Resource) Exec(cmd []string, opts ExecOptions) (exitCode int, err error return -1, errors.Wrap(err, "Create exec failed") } + // Always attach stderr/stdout, even if not specified, to ensure that exec + // waits with opts.Detach as false (default) + // ref: https://github.com/fsouza/go-dockerclient/issues/838 + if opts.StdErr == nil { + opts.StdErr = io.Discard + } + if opts.StdOut == nil { + opts.StdOut = io.Discard + } + err = r.pool.Client.StartExec(exec.ID, dc.StartExecOptions{ InputStream: opts.StdIn, OutputStream: opts.StdOut, diff --git a/dockertest_test.go b/dockertest_test.go index dd4a8a36..0661b80e 100644 --- a/dockertest_test.go +++ b/dockertest_test.go @@ -20,8 +20,10 @@ import ( "github.com/stretchr/testify/require" ) -var docker = os.Getenv("DOCKER_URL") -var pool *Pool +var ( + docker = os.Getenv("DOCKER_URL") + pool *Pool +) func TestMain(m *testing.M) { var err error @@ -65,7 +67,6 @@ func TestMongo(t *testing.T) { err = pool.Retry(func() error { response, err := http.Get(fmt.Sprintf("http://127.0.0.1:%s", port)) - if err != nil { return err } @@ -197,7 +198,7 @@ func TestBuildImage(t *testing.T) { dockerfilePath := dir + "/Dockerfile" ioutil.WriteFile(dockerfilePath, []byte("FROM postgres:9.5"), - 0644, + 0o644, ) resource, err := pool.BuildAndRun("postgres-test", dockerfilePath, nil) @@ -219,7 +220,7 @@ ARG foo RUN echo -n $foo > /build-time-value CMD sleep 10 `)), - 0644, + 0o644, ) resource, err := pool.BuildAndRunWithBuildOptions( @@ -467,3 +468,19 @@ func TestClientRaceCondition(t *testing.T) { }) } } + +func TestExecStatus(t *testing.T) { + resource, err := pool.RunWithOptions(&RunOptions{ + Repository: "alpine", + Tag: "3.16", + Cmd: []string{"tail", "-f", "/dev/null"}, + }) + defer resource.Close() + require.Nil(t, err) + exitCode, err := resource.Exec([]string{"/bin/false"}, ExecOptions{}) + require.Nil(t, err) + require.Equal(t, 1, exitCode) + exitCode, err = resource.Exec([]string{"/bin/sh", "-c", "/bin/sleep 2 && exit 42"}, ExecOptions{}) + require.Nil(t, err) + require.Equal(t, 42, exitCode) +}