exec_test.go 4.3 KB

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