testing: add case for exec closeStdin
add regression case for the issue#37870
@@ -4,6 +4,7 @@ import (
"context"
"io/ioutil"
"testing"
+ "time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/strslice"
@@ -15,6 +16,74 @@ import (
"gotest.tools/skip"
)
+// TestExecWithCloseStdin adds case for moby#37870 issue.
+func TestExecWithCloseStdin(t *testing.T) {
+ skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "broken in earlier versions")
+ defer setupTest(t)()
+
+ ctx := context.Background()
+ client := request.NewAPIClient(t)
+
+ // run top with detached mode
+ cID := container.Run(t, ctx, client)
+
+ expected := "closeIO"
+ execResp, err := client.ContainerExecCreate(ctx, cID,
+ types.ExecConfig{
+ AttachStdin: true,
+ AttachStdout: true,
+ Cmd: strslice.StrSlice([]string{"sh", "-c", "cat && echo " + expected}),
+ },
+ )
+ assert.NilError(t, err)
+
+ resp, err := client.ContainerExecAttach(ctx, execResp.ID,
+ types.ExecStartCheck{
+ Detach: false,
+ Tty: false,
+ },
+ )
+ assert.NilError(t, err)
+ defer resp.Close()
+
+ // close stdin to send EOF to cat
+ assert.NilError(t, resp.CloseWrite())
+
+ var (
+ waitCh = make(chan struct{})
+ resCh = make(chan struct {
+ content string
+ err error
+ })
+ )
+
+ go func() {
+ close(waitCh)
+ defer close(resCh)
+ r, err := ioutil.ReadAll(resp.Reader)
+
+ resCh <- struct {
+ content string
+ err error
+ }{
+ content: string(r),
+ err: err,
+ }
+ }()
+
+ <-waitCh
+ select {
+ case <-time.After(3 * time.Second):
+ t.Fatal("failed to read the content in time")
+ case got := <-resCh:
+ assert.NilError(t, got.err)
+
+ // NOTE: using Contains because no-tty's stream contains UX information
+ // like size, stream type.
+ assert.Assert(t, is.Contains(got.content, expected))
+ }
+}
+
func TestExec(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
skip.If(t, testEnv.OSType == "windows", "FIXME. Probably needs to wait for container to be in running state.")
