Skip to content

Commit 1c41df8

Browse files
committed
e2e: robustness changes for ddev test
The most important change here is to ensure that the correct Compose standalone binary is used by `ddev`. Since it invokes Compose itself, we need to ensure that `PATH` is set appropriately such that it finds the binary we want to test rather than something from the system. As part of this, the rest of the environment has been isolated, which should make the test more reliable, and avoids polluting `~/.ddev` with test artifacts by using a tmpdir as `HOME` for the test instead of the user's real home folder. Signed-off-by: Milas Bowman <[email protected]>
1 parent ea83418 commit 1c41df8

File tree

2 files changed

+81
-37
lines changed

2 files changed

+81
-37
lines changed

pkg/e2e/ddev_test.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,52 @@ package e2e
1919
import (
2020
"fmt"
2121
"os"
22+
"os/exec"
2223
"path/filepath"
2324
"runtime"
2425
"strings"
2526
"testing"
2627

28+
"github.com/stretchr/testify/require"
2729
"gotest.tools/v3/assert"
2830
)
2931

3032
const ddevVersion = "v1.19.1"
3133

3234
func TestComposeRunDdev(t *testing.T) {
3335
if !composeStandaloneMode {
34-
t.Skip("Not running on standalone mode.")
36+
t.Skip("Not running in plugin mode - ddev only supports invoking standalone `docker-compose`")
3537
}
3638
if runtime.GOOS == "windows" {
3739
t.Skip("Running on Windows. Skipping...")
3840
}
39-
_ = os.Setenv("DDEV_DEBUG", "true")
4041

41-
c := NewParallelCLI(t)
42-
dir, err := os.MkdirTemp("", t.Name()+"-")
43-
assert.NilError(t, err)
44-
45-
// ddev needs to be able to find mkcert to figure out where certs are.
46-
_ = os.Setenv("PATH", fmt.Sprintf("%s:%s", os.Getenv("PATH"), dir))
47-
48-
siteName := filepath.Base(dir)
42+
// ddev shells out to `docker` and `docker-compose` (standalone), so a
43+
// temporary directory is created with symlinks to system Docker and the
44+
// locally-built standalone Compose binary to use as PATH
45+
pathDir := t.TempDir()
46+
dockerBin, err := exec.LookPath(DockerExecutableName)
47+
require.NoError(t, err, "Could not find %q in path", DockerExecutableName)
48+
require.NoError(t, os.Symlink(dockerBin, filepath.Join(pathDir, DockerExecutableName)),
49+
"Could not create %q symlink", DockerExecutableName)
50+
51+
composeBin := ComposeStandalonePath(t)
52+
require.NoError(t, os.Symlink(composeBin, filepath.Join(pathDir, DockerComposeExecutableName)),
53+
"Could not create %q symlink", DockerComposeExecutableName)
54+
55+
c := NewCLI(t, WithEnv(
56+
"DDEV_DEBUG=true",
57+
fmt.Sprintf("HOME=%s", t.TempDir()),
58+
fmt.Sprintf("USER=%s", os.Getenv("USER")),
59+
fmt.Sprintf("PATH=%s", pathDir),
60+
))
61+
62+
ddevDir := t.TempDir()
63+
siteName := filepath.Base(ddevDir)
4964

5065
t.Cleanup(func() {
51-
_ = c.RunCmdInDir(t, dir, "./ddev", "delete", "-Oy")
52-
_ = c.RunCmdInDir(t, dir, "./ddev", "poweroff")
53-
_ = os.RemoveAll(dir)
66+
_ = c.RunCmdInDir(t, ddevDir, "./ddev", "delete", "-Oy")
67+
_ = c.RunCmdInDir(t, ddevDir, "./ddev", "poweroff")
5468
})
5569

5670
osName := "linux"
@@ -59,27 +73,26 @@ func TestComposeRunDdev(t *testing.T) {
5973
}
6074

6175
compressedFilename := fmt.Sprintf("ddev_%s-%s.%s.tar.gz", osName, runtime.GOARCH, ddevVersion)
62-
c.RunCmdInDir(t, dir, "curl", "-LO",
63-
fmt.Sprintf("https://github.com/drud/ddev/releases/download/%s/%s",
64-
ddevVersion,
65-
compressedFilename))
76+
c.RunCmdInDir(t, ddevDir, "curl", "-LO", fmt.Sprintf("https://github.com/drud/ddev/releases/download/%s/%s",
77+
ddevVersion,
78+
compressedFilename))
6679

67-
c.RunCmdInDir(t, dir, "tar", "-xzf", compressedFilename)
80+
c.RunCmdInDir(t, ddevDir, "tar", "-xzf", compressedFilename)
6881

6982
// Create a simple index.php we can test against.
70-
c.RunCmdInDir(t, dir, "sh", "-c", "echo '<?php\nprint \"ddev is working\";' >index.php")
83+
c.RunCmdInDir(t, ddevDir, "sh", "-c", "echo '<?php\nprint \"ddev is working\";' >index.php")
7184

72-
c.RunCmdInDir(t, dir, "./ddev", "config", "--auto")
73-
c.RunCmdInDir(t, dir, "./ddev", "config", "global", "--use-docker-compose-from-path")
74-
vRes := c.RunCmdInDir(t, dir, "./ddev", "version")
85+
c.RunCmdInDir(t, ddevDir, "./ddev", "config", "--auto")
86+
c.RunCmdInDir(t, ddevDir, "./ddev", "config", "global", "--use-docker-compose-from-path")
87+
vRes := c.RunCmdInDir(t, ddevDir, "./ddev", "version")
7588
out := vRes.Stdout()
7689
fmt.Printf("ddev version: %s\n", out)
7790

78-
c.RunCmdInDir(t, dir, "./ddev", "poweroff")
91+
c.RunCmdInDir(t, ddevDir, "./ddev", "poweroff")
7992

80-
c.RunCmdInDir(t, dir, "./ddev", "start", "-y")
93+
c.RunCmdInDir(t, ddevDir, "./ddev", "start", "-y")
8194

82-
curlRes := c.RunCmdInDir(t, dir, "curl", "-sSL", fmt.Sprintf("http://%s.ddev.site", siteName))
95+
curlRes := c.RunCmdInDir(t, ddevDir, "curl", "-sSL", fmt.Sprintf("http://%s.ddev.site", siteName))
8396
out = curlRes.Stdout()
8497
fmt.Println(out)
8598
assert.Assert(t, strings.Contains(out, "ddev is working"), "Could not start project")

pkg/e2e/framework.go

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ import (
3232
"github.com/pkg/errors"
3333
"github.com/stretchr/testify/require"
3434
"gotest.tools/v3/assert"
35-
is "gotest.tools/v3/assert/cmp"
3635
"gotest.tools/v3/icmd"
3736
"gotest.tools/v3/poll"
3837

@@ -61,18 +60,50 @@ func init() {
6160
// CLI is used to wrap the CLI for end to end testing
6261
type CLI struct {
6362
ConfigDir string
63+
64+
env []string
6465
}
6566

66-
// NewParallelCLI returns a configured CLI with t.Parallel() set
67-
func NewParallelCLI(t *testing.T) *CLI {
67+
// CLIOption to customize behavior for all commands for a CLI instance.
68+
type CLIOption func(c *CLI)
69+
70+
// NewParallelCLI marks the parent test as parallel and returns a CLI instance
71+
// suitable for usage across child tests.
72+
func NewParallelCLI(t *testing.T, opts ...CLIOption) *CLI {
73+
t.Helper()
6874
t.Parallel()
69-
return NewCLI(t)
75+
return NewCLI(t, opts...)
7076
}
7177

72-
// NewCLI returns a CLI to use for E2E tests
73-
func NewCLI(t testing.TB) *CLI {
74-
d, err := ioutil.TempDir("", "")
75-
assert.Check(t, is.Nil(err))
78+
// NewCLI creates a CLI instance for running E2E tests.
79+
func NewCLI(t testing.TB, opts ...CLIOption) *CLI {
80+
t.Helper()
81+
82+
configDir := t.TempDir()
83+
initializePlugins(t, configDir)
84+
85+
c := &CLI{
86+
ConfigDir: configDir,
87+
}
88+
89+
for _, opt := range opts {
90+
opt(c)
91+
}
92+
93+
return c
94+
}
95+
96+
// WithEnv sets environment variables that will be passed to commands.
97+
func WithEnv(env ...string) CLIOption {
98+
return func(c *CLI) {
99+
c.env = append(c.env, env...)
100+
}
101+
}
102+
103+
// initializePlugins copies the necessary plugin files to the temporary config
104+
// directory for the test.
105+
func initializePlugins(t testing.TB, d string) {
106+
t.Helper()
76107

77108
t.Cleanup(func() {
78109
if t.Failed() {
@@ -102,8 +133,6 @@ func NewCLI(t testing.TB) *CLI {
102133
panic(err)
103134
}
104135
}
105-
106-
return &CLI{ConfigDir: d}
107136
}
108137

109138
func dirContents(dir string) []string {
@@ -168,13 +197,15 @@ func (c *CLI) BaseEnvironment() []string {
168197
func (c *CLI) NewCmd(command string, args ...string) icmd.Cmd {
169198
return icmd.Cmd{
170199
Command: append([]string{command}, args...),
171-
Env: c.BaseEnvironment(),
200+
Env: append(c.BaseEnvironment(), c.env...),
172201
}
173202
}
174203

175204
// NewCmdWithEnv creates a cmd object configured with the test environment set with additional env vars
176205
func (c *CLI) NewCmdWithEnv(envvars []string, command string, args ...string) icmd.Cmd {
177-
cmdEnv := append(c.BaseEnvironment(), envvars...)
206+
// base env -> CLI overrides -> cmd overrides
207+
cmdEnv := append(c.BaseEnvironment(), c.env...)
208+
cmdEnv = append(cmdEnv, envvars...)
178209
return icmd.Cmd{
179210
Command: append([]string{command}, args...),
180211
Env: cmdEnv,

0 commit comments

Comments
 (0)