Skip to content

Commit ea83418

Browse files
committed
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>
1 parent de0f233 commit ea83418

File tree

3 files changed

+48
-39
lines changed

3 files changed

+48
-39
lines changed

pkg/e2e/compose_build_test.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package e2e
1818

1919
import (
2020
"net/http"
21-
"os"
2221
"strings"
2322
"testing"
2423
"time"
@@ -81,11 +80,6 @@ func TestLocalComposeBuild(t *testing.T) {
8180
})
8281

8382
t.Run("build failed with ssh default value", func(t *testing.T) {
84-
//unset SSH_AUTH_SOCK to be sure we don't have a default value for the SSH Agent
85-
defaultSSHAUTHSOCK := os.Getenv("SSH_AUTH_SOCK")
86-
os.Unsetenv("SSH_AUTH_SOCK") //nolint:errcheck
87-
defer os.Setenv("SSH_AUTH_SOCK", defaultSSHAUTHSOCK) //nolint:errcheck
88-
8983
res := c.RunDockerComposeCmdNoCheck(t, "--project-directory", "fixtures/build-test", "build", "--ssh", "")
9084
res.Assert(t, icmd.Expected{
9185
ExitCode: 1,

pkg/e2e/compose_environment_test.go

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package e2e
1818

1919
import (
20-
"os"
2120
"strings"
2221
"testing"
2322

@@ -43,13 +42,10 @@ func TestEnvPriority(t *testing.T) {
4342
// 4. Dockerfile
4443
// 5. Variable is not defined
4544
t.Run("compose file priority", func(t *testing.T) {
46-
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
47-
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
48-
49-
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
50-
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
51-
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
52-
45+
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose-with-env.yaml",
46+
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run",
47+
"--rm", "-e", "WHEREAMI", "env-compose-priority")
48+
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
5349
assert.Equal(t, strings.TrimSpace(res.Stdout()), "Compose File")
5450
})
5551

@@ -60,12 +56,10 @@ func TestEnvPriority(t *testing.T) {
6056
// 4. Dockerfile
6157
// 5. Variable is not defined
6258
t.Run("shell priority", func(t *testing.T) {
63-
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
64-
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
65-
66-
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml",
67-
"--project-directory", projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override",
68-
"run", "--rm", "-e", "WHEREAMI", "env-compose-priority")
59+
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-priority/compose.yaml", "--project-directory",
60+
projectDir, "--env-file", "./fixtures/environment/env-priority/.env.override", "run", "--rm", "-e",
61+
"WHEREAMI", "env-compose-priority")
62+
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
6963
assert.Equal(t, strings.TrimSpace(res.Stdout()), "shell")
7064
})
7165

@@ -137,11 +131,9 @@ func TestEnvInterpolation(t *testing.T) {
137131
// 4. Dockerfile
138132
// 5. Variable is not defined
139133
t.Run("shell priority from run command", func(t *testing.T) {
140-
os.Setenv("WHEREAMI", "shell") //nolint:errcheck
141-
defer os.Unsetenv("WHEREAMI") //nolint:errcheck
142-
res := c.RunDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml",
134+
cmd := c.NewDockerComposeCmd(t, "-f", "./fixtures/environment/env-interpolation/compose.yaml",
143135
"--project-directory", projectDir, "config")
144-
136+
res := icmd.RunCmd(cmd, icmd.WithEnv("WHEREAMI=shell"))
145137
res.Assert(t, icmd.Expected{Out: `IMAGE: default_env:shell`})
146138
})
147139
}

pkg/e2e/framework.go

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"time"
3131

3232
"github.com/pkg/errors"
33+
"github.com/stretchr/testify/require"
3334
"gotest.tools/v3/assert"
3435
is "gotest.tools/v3/assert/cmp"
3536
"gotest.tools/v3/icmd"
@@ -154,28 +155,29 @@ func CopyFile(sourceFile string, destinationFile string) error {
154155
return err
155156
}
156157

158+
// BaseEnvironment provides the minimal environment variables used across all
159+
// Docker / Compose commands.
160+
func (c *CLI) BaseEnvironment() []string {
161+
return []string{
162+
"DOCKER_CONFIG=" + c.ConfigDir,
163+
"KUBECONFIG=invalid",
164+
}
165+
}
166+
157167
// NewCmd creates a cmd object configured with the test environment set
158168
func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd {
159-
env := append(os.Environ(),
160-
"DOCKER_CONFIG="+c.ConfigDir,
161-
"KUBECONFIG=invalid",
162-
)
163169
return icmd.Cmd{
164170
Command: append([]string{command}, args...),
165-
Env: env,
171+
Env: c.BaseEnvironment(),
166172
}
167173
}
168174

169175
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
170176
func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
171-
env := append(os.Environ(),
172-
append(envvars,
173-
"DOCKER_CONFIG="+c.ConfigDir,
174-
"KUBECONFIG=invalid")...,
175-
)
177+
cmdEnv := append(c.BaseEnvironment(), envvars...)
176178
return icmd.Cmd{
177179
Command: append([]string{command}, args...),
178-
Env: env,
180+
Env: cmdEnv,
179181
}
180182
}
181183

@@ -234,13 +236,34 @@ func (c *CLI) RunDockerComposeCmd(t testing.TB, args ...string) *icmd.Result {
234236

235237
// RunDockerComposeCmdNoCheck runs a docker compose command, don't presume of any expectation and returns a result
236238
func (c *CLI) RunDockerComposeCmdNoCheck(t testing.TB, args ...string) *icmd.Result {
239+
return icmd.RunCmd(c.NewDockerComposeCmd(t, args...))
240+
}
241+
242+
// NewDockerComposeCmd creates a command object for Compose, either in plugin
243+
// or standalone mode (based on build tags).
244+
func (c *CLI) NewDockerComposeCmd(t testing.TB, args ...string) icmd.Cmd {
245+
t.Helper()
237246
if composeStandaloneMode {
238-
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
239-
assert.NilError(t, err)
240-
return icmd.RunCmd(c.NewCmd(composeBinary, args...))
247+
return c.NewCmd(ComposeStandalonePath(t), args...)
241248
}
242249
args = append([]string{"compose"}, args...)
243-
return icmd.RunCmd(c.NewCmd(DockerExecutableName, args...))
250+
return c.NewCmd(DockerExecutableName, args...)
251+
}
252+
253+
// ComposeStandalonePath returns the path to the locally-built Compose
254+
// standalone binary from the repo.
255+
//
256+
// This function will fail the test immediately if invoked when not running
257+
// in standalone test mode.
258+
func ComposeStandalonePath(t testing.TB) string {
259+
t.Helper()
260+
if !composeStandaloneMode {
261+
require.Fail(t, "Not running in standalone mode")
262+
}
263+
composeBinary, err := findExecutable(DockerComposeExecutableName, []string{"../../bin", "../../../bin"})
264+
require.NoError(t, err, "Could not find standalone Compose binary (%q)",
265+
DockerComposeExecutableName)
266+
return composeBinary
244267
}
245268

246269
// StdoutContains returns a predicate on command result expecting a string in stdout

0 commit comments

Comments
 (0)