exec_test.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package container // import "github.com/docker/docker/integration/container"
  2. import (
  3. "context"
  4. "io"
  5. "testing"
  6. "time"
  7. "github.com/docker/docker/api/types"
  8. "github.com/docker/docker/api/types/strslice"
  9. "github.com/docker/docker/api/types/versions"
  10. "github.com/docker/docker/integration/internal/container"
  11. "gotest.tools/v3/assert"
  12. is "gotest.tools/v3/assert/cmp"
  13. "gotest.tools/v3/skip"
  14. )
  15. // TestExecWithCloseStdin adds case for moby#37870 issue.
  16. func TestExecWithCloseStdin(t *testing.T) {
  17. skip.If(t, testEnv.RuntimeIsWindowsContainerd(), "FIXME. Hang on Windows + containerd combination")
  18. skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "broken in earlier versions")
  19. defer setupTest(t)()
  20. ctx := context.Background()
  21. client := testEnv.APIClient()
  22. // run top with detached mode
  23. cID := container.Run(ctx, t, client)
  24. expected := "closeIO"
  25. execResp, err := client.ContainerExecCreate(ctx, cID,
  26. types.ExecConfig{
  27. AttachStdin: true,
  28. AttachStdout: true,
  29. Cmd: strslice.StrSlice([]string{"sh", "-c", "cat && echo " + expected}),
  30. },
  31. )
  32. assert.NilError(t, err)
  33. resp, err := client.ContainerExecAttach(ctx, execResp.ID,
  34. types.ExecStartCheck{
  35. Detach: false,
  36. Tty: false,
  37. },
  38. )
  39. assert.NilError(t, err)
  40. defer resp.Close()
  41. // close stdin to send EOF to cat
  42. assert.NilError(t, resp.CloseWrite())
  43. var (
  44. waitCh = make(chan struct{})
  45. resCh = make(chan struct {
  46. content string
  47. err error
  48. }, 1)
  49. )
  50. go func() {
  51. close(waitCh)
  52. defer close(resCh)
  53. r, err := io.ReadAll(resp.Reader)
  54. resCh <- struct {
  55. content string
  56. err error
  57. }{
  58. content: string(r),
  59. err: err,
  60. }
  61. }()
  62. <-waitCh
  63. select {
  64. case <-time.After(3 * time.Second):
  65. t.Fatal("failed to read the content in time")
  66. case got := <-resCh:
  67. assert.NilError(t, got.err)
  68. // NOTE: using Contains because no-tty's stream contains UX information
  69. // like size, stream type.
  70. assert.Assert(t, is.Contains(got.content, expected))
  71. }
  72. }
  73. func TestExec(t *testing.T) {
  74. skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.35"), "broken in earlier versions")
  75. defer setupTest(t)()
  76. ctx := context.Background()
  77. client := testEnv.APIClient()
  78. cID := container.Run(ctx, t, client, container.WithTty(true), container.WithWorkingDir("/root"))
  79. id, err := client.ContainerExecCreate(ctx, cID,
  80. types.ExecConfig{
  81. WorkingDir: "/tmp",
  82. Env: strslice.StrSlice([]string{"FOO=BAR"}),
  83. AttachStdout: true,
  84. Cmd: strslice.StrSlice([]string{"sh", "-c", "env"}),
  85. },
  86. )
  87. assert.NilError(t, err)
  88. inspect, err := client.ContainerExecInspect(ctx, id.ID)
  89. assert.NilError(t, err)
  90. assert.Check(t, is.Equal(inspect.ExecID, id.ID))
  91. resp, err := client.ContainerExecAttach(ctx, id.ID,
  92. types.ExecStartCheck{
  93. Detach: false,
  94. Tty: false,
  95. },
  96. )
  97. assert.NilError(t, err)
  98. defer resp.Close()
  99. r, err := io.ReadAll(resp.Reader)
  100. assert.NilError(t, err)
  101. out := string(r)
  102. assert.NilError(t, err)
  103. expected := "PWD=/tmp"
  104. if testEnv.OSType == "windows" {
  105. expected = "PWD=C:/tmp"
  106. }
  107. assert.Assert(t, is.Contains(out, expected), "exec command not running in expected /tmp working directory")
  108. assert.Assert(t, is.Contains(out, "FOO=BAR"), "exec command not running with expected environment variable FOO")
  109. }
  110. func TestExecUser(t *testing.T) {
  111. skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "broken in earlier versions")
  112. skip.If(t, testEnv.OSType == "windows", "FIXME. Probably needs to wait for container to be in running state.")
  113. defer setupTest(t)()
  114. ctx := context.Background()
  115. client := testEnv.APIClient()
  116. cID := container.Run(ctx, t, client, container.WithTty(true), container.WithUser("1:1"))
  117. result, err := container.Exec(ctx, client, cID, []string{"id"})
  118. assert.NilError(t, err)
  119. assert.Assert(t, is.Contains(result.Stdout(), "uid=1(daemon) gid=1(daemon)"), "exec command not running as uid/gid 1")
  120. }