mirror of https://github.com/docker/compose.git
e2e: isolate test command env from system env
When running Docker / Compose commands, do NOT inherit the system environment to ensure that the tests are reproducible regardless of host settings. Additionally, per-command environment overrides are provided to the command instead of using `os.SetEnv`, as this is not safe when running tests in parallel (`testing.T::SetEnv` will actually error if used in this way!) Signed-off-by: Milas Bowman <milas.bowman@docker.com>
This commit is contained in:
parent
de0f23315b
commit
ea8341865d
|
@ -18,7 +18,6 @@ package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -81,11 +80,6 @@ func TestLocalComposeBuild(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("build failed with ssh default value", func(t *testing.T) {
|
t.Run("build failed with ssh default value", func(t *testing.T) {
|
||||||
//unset SSH_AUTH_SOCK to be sure we don't have a default value for the SSH Agent
|
|
||||||
defaultSSHAUTHSOCK := os.Getenv("SSH_AUTH_SOCK")
|
|
||||||
os.Unsetenv("SSH_AUTH_SOCK") //nolint:errcheck
|
|
||||||
defer os.Setenv("SSH_AUTH_SOCK", defaultSSHAUTHSOCK) //nolint:errcheck
|
|
||||||
|
|
||||||
res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "")
|
res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "")
|
||||||
res.Assert(t, icmd.Expected{
|
res.Assert(t, icmd.Expected{
|
||||||
ExitCode: 1,
|
ExitCode: 1,
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package e2e
|
package e2e
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -43,13 +42,10 @@ func TestEnvPriority(t *testing.T) {
|
||||||
// 4. Dockerfile
|
// 4. Dockerfile
|
||||||
// 5. Variable is not defined
|
// 5. Variable is not defined
|
||||||
t.Run("compose file priority", func(t *testing.T) {
|
t.Run("compose file priority", func(t *testing.T) {
|
||||||
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
|
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
|
||||||
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
|
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run",
|
||||||
|
"--rm", "-e", "WHEREAMI", "env-compose-priority")
|
||||||
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
|
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
|
||||||
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
|
|
||||||
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
|
||||||
|
|
||||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "Compose File")
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), "Compose File")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -60,12 +56,10 @@ func TestEnvPriority(t *testing.T) {
|
||||||
// 4. Dockerfile
|
// 4. Dockerfile
|
||||||
// 5. Variable is not defined
|
// 5. Variable is not defined
|
||||||
t.Run("shell priority", func(t *testing.T) {
|
t.Run("shell priority", func(t *testing.T) {
|
||||||
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
|
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
|
||||||
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
|
projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e",
|
||||||
|
"WHEREAMI", "env-compose-priority")
|
||||||
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml",
|
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
|
||||||
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
|
|
||||||
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
|
|
||||||
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
|
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -137,11 +131,9 @@ func TestEnvInterpolation(t *testing.T) {
|
||||||
// 4. Dockerfile
|
// 4. Dockerfile
|
||||||
// 5. Variable is not defined
|
// 5. Variable is not defined
|
||||||
t.Run("shell priority from run command", func(t *testing.T) {
|
t.Run("shell priority from run command", func(t *testing.T) {
|
||||||
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
|
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml",
|
||||||
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
|
|
||||||
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml",
|
|
||||||
"--project-directory", projectDir, "config")
|
"--project-directory", projectDir, "config")
|
||||||
|
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
|
||||||
res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`})
|
res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
"gotest.tools/v3/icmd"
|
"gotest.tools/v3/icmd"
|
||||||
|
@ -154,28 +155,29 @@ func CopyFile(sourceFile string, destinationFile string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BaseEnvironment provides the minimal environment variables used across all
|
||||||
|
// Docker / Compose commands.
|
||||||
|
func (c *CLI) BaseEnvironment() []string {
|
||||||
|
return []string{
|
||||||
|
"DOCKER_CONFIG=" + c.ConfigDir,
|
||||||
|
"KUBECONFIG=invalid",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewCmd creates a cmd object configured with the test environment set
|
// NewCmd creates a cmd object configured with the test environment set
|
||||||
func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd {
|
func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd {
|
||||||
env := append(os.Environ(),
|
|
||||||
"DOCKER_CONFIG="+c.ConfigDir,
|
|
||||||
"KUBECONFIG=invalid",
|
|
||||||
)
|
|
||||||
return icmd.Cmd{
|
return icmd.Cmd{
|
||||||
Command: append([]string{command}, args...),
|
Command: append([]string{command}, args...),
|
||||||
Env: env,
|
Env: c.BaseEnvironment(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
|
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
|
||||||
func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
|
func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
|
||||||
env := append(os.Environ(),
|
cmdEnv := append(c.BaseEnvironment(), envvars...)
|
||||||
append(envvars,
|
|
||||||
"DOCKER_CONFIG="+c.ConfigDir,
|
|
||||||
"KUBECONFIG=invalid")...,
|
|
||||||
)
|
|
||||||
return icmd.Cmd{
|
return icmd.Cmd{
|
||||||
Command: append([]string{command}, args...),
|
Command: append([]string{command}, args...),
|
||||||
Env: env,
|
Env: cmdEnv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,13 +236,34 @@ func (c *CLI) RunDockerComposeCmd(t testing.TB, args ...string) *icmd.Result {
|
||||||
|
|
||||||
// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result
|
// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result
|
||||||
func (c *CLI) RunDockerComposeCmdNoCheck(t testing.TB, args ...string) *icmd.Result {
|
func (c *CLI) RunDockerComposeCmdNoCheck(t testing.TB, args ...string) *icmd.Result {
|
||||||
|
return icmd.RunCmd(c.NewDockerComposeCmd(t, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDockerComposeCmd creates a command object for Compose, either in plugin
|
||||||
|
// or standalone mode (based on build tags).
|
||||||
|
func (c *CLI) NewDockerComposeCmd(t testing.TB, args ...string) icmd.Cmd {
|
||||||
|
t.Helper()
|
||||||
if composeStandaloneMode {
|
if composeStandaloneMode {
|
||||||
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
|
return c.NewCmd(ComposeStandalonePath(t), args...)
|
||||||
assert.NilError(t, err)
|
|
||||||
return icmd.RunCmd(c.NewCmd(composeBinary, args...))
|
|
||||||
}
|
}
|
||||||
args = append([]string{"compose"}, args...)
|
args = append([]string{"compose"}, args...)
|
||||||
return icmd.RunCmd(c.NewCmd(DockerExecutableName, args...))
|
return c.NewCmd(DockerExecutableName, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComposeStandalonePath returns the path to the locally-built Compose
|
||||||
|
// standalone binary from the repo.
|
||||||
|
//
|
||||||
|
// This function will fail the test immediately if invoked when not running
|
||||||
|
// in standalone test mode.
|
||||||
|
func ComposeStandalonePath(t testing.TB) string {
|
||||||
|
t.Helper()
|
||||||
|
if !composeStandaloneMode {
|
||||||
|
require.Fail(t, "Not running in standalone mode")
|
||||||
|
}
|
||||||
|
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
|
||||||
|
require.NoError(t, err, "Could not find standalone Compose binary (%q)",
|
||||||
|
DockerComposeExecutableName)
|
||||||
|
return composeBinary
|
||||||
}
|
}
|
||||||
|
|
||||||
// StdoutContains returns a predicate on command result expecting a string in stdout
|
// StdoutContains returns a predicate on command result expecting a string in stdout
|
||||||
|
|
Loading…
Reference in New Issue