1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
package container // import "github.com/docker/docker/integration/container"
import (
"context"
"io"
"testing"
"time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/strslice"
"github.com/docker/docker/api/types/versions"
"github.com/docker/docker/integration/internal/container"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/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 := testEnv.APIClient()
// run top with detached mode
cID := container.Run(ctx, t, 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
}, 1)
)
go func() {
close(waitCh)
defer close(resCh)
r, err := io.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")
defer setupTest(t)()
ctx := context.Background()
client := testEnv.APIClient()
cID := container.Run(ctx, t, client, container.WithTty(true), container.WithWorkingDir("/root"))
id, err := client.ContainerExecCreate(ctx, cID,
types.ExecConfig{
WorkingDir: "/tmp",
Env: strslice.StrSlice([]string{"FOO=BAR"}),
AttachStdout: true,
Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}),
},
)
assert.NilError(t, err)
inspect, err := client.ContainerExecInspect(ctx, id.ID)
assert.NilError(t, err)
assert.Check(t, is.Equal(inspect.ExecID, id.ID))
resp, err := client.ContainerExecAttach(ctx, id.ID,
types.ExecStartCheck{
Detach: false,
Tty: false,
},
)
assert.NilError(t, err)
defer resp.Close()
r, err := io.ReadAll(resp.Reader)
assert.NilError(t, err)
out := string(r)
assert.NilError(t, err)
expected := "PWD=/tmp"
if testEnv.OSType == "windows" {
expected = "PWD=C:/tmp"
}
assert.Assert(t, is.Contains(out, expected), "exec command not running in expected /tmp working directory")
assert.Assert(t, is.Contains(out, "FOO=BAR"), "exec command not running with expected environment variable FOO")
}
func TestExecUser(t *testing.T) {
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "broken in earlier versions")
skip.If(t, testEnv.OSType == "windows", "FIXME. Probably needs to wait for container to be in running state.")
defer setupTest(t)()
ctx := context.Background()
client := testEnv.APIClient()
cID := container.Run(ctx, t, client, container.WithTty(true), container.WithUser("1:1"))
result, err := container.Exec(ctx, client, cID, []string{"id"})
assert.NilError(t, err)
assert.Assert(t, is.Contains(result.Stdout(), "uid=1(daemon) gid=1(daemon)"), "exec command not running as uid/gid 1")
}
|