Skip to content

Commit e6ba29a

Browse files
authored
chore: improve integration test compatibility with older Coder versions (#247)
Previously, testing with coder versions older than 2.7 would fail due to the template push command not creating the template automatically. Also, improves logic around pulling the image if it does not exist locally.
1 parent 9f66e78 commit e6ba29a

File tree

3 files changed

+50
-19
lines changed

3 files changed

+50
-19
lines changed

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ require (
7676
go.opentelemetry.io/otel/sdk v1.27.0 // indirect
7777
go.opentelemetry.io/otel/trace v1.27.0 // indirect
7878
golang.org/x/crypto v0.23.0 // indirect
79+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
80+
golang.org/x/mod v0.18.0 // indirect
7981
golang.org/x/net v0.25.0 // indirect
8082
golang.org/x/sys v0.20.0 // indirect
8183
golang.org/x/text v0.15.0 // indirect

go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,13 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y
252252
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
253253
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
254254
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
255+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
256+
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
255257
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
256258
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
257259
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
260+
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
261+
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
258262
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
259263
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
260264
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

integration/integration_test.go

+44-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"github.com/docker/docker/pkg/stdcopy"
2222
"github.com/stretchr/testify/assert"
2323
"github.com/stretchr/testify/require"
24+
"golang.org/x/exp/slices"
25+
"golang.org/x/mod/semver"
2426
)
2527

2628
// TestIntegration performs an integration test against an ephemeral Coder deployment.
@@ -37,6 +39,16 @@ func TestIntegration(t *testing.T) {
3739
t.Skip("Skipping integration tests during tf acceptance tests")
3840
}
3941

42+
coderImg := os.Getenv("CODER_IMAGE")
43+
if coderImg == "" {
44+
coderImg = "ghcr.io/coder/coder"
45+
}
46+
47+
coderVersion := os.Getenv("CODER_VERSION")
48+
if coderVersion == "" {
49+
coderVersion = "latest"
50+
}
51+
4052
timeoutStr := os.Getenv("TIMEOUT_MINS")
4153
if timeoutStr == "" {
4254
timeoutStr = "10"
@@ -88,9 +100,17 @@ func TestIntegration(t *testing.T) {
88100
} {
89101
t.Run(tt.name, func(t *testing.T) {
90102
// Given: we have an existing Coder deployment running locally
91-
ctrID := setup(ctx, t, tt.name)
103+
ctrID := setup(ctx, t, tt.name, coderImg, coderVersion)
92104
// Import named template
93-
_, rc := execContainer(ctx, t, ctrID, fmt.Sprintf(`coder templates push %s --directory /src/integration/%s --var output_path=/tmp/%s.json --yes`, tt.name, tt.name, tt.name))
105+
106+
// NOTE: Template create command was deprecated after this version
107+
// ref: https://github.com/coder/coder/pull/11390
108+
templateCreateCmd := "push"
109+
if semver.Compare(coderVersion, "v2.7.0") < 1 {
110+
t.Logf("using now-deprecated templates create command for older coder version")
111+
templateCreateCmd = "create"
112+
}
113+
_, rc := execContainer(ctx, t, ctrID, fmt.Sprintf(`coder templates %s %s --directory /src/integration/%s --var output_path=/tmp/%s.json --yes`, templateCreateCmd, tt.name, tt.name, tt.name))
94114
require.Equal(t, 0, rc)
95115
// Create a workspace
96116
_, rc = execContainer(ctx, t, ctrID, fmt.Sprintf(`coder create %s -t %s --yes`, tt.name, tt.name))
@@ -105,7 +125,7 @@ func TestIntegration(t *testing.T) {
105125
}
106126
}
107127

108-
func setup(ctx context.Context, t *testing.T, name string) string {
128+
func setup(ctx context.Context, t *testing.T, name, coderImg, coderVersion string) string {
109129
var (
110130
// For this test to work, we pass in a custom terraformrc to use
111131
// the locally built version of the provider.
@@ -118,16 +138,6 @@ func setup(ctx context.Context, t *testing.T, name string) string {
118138
localURL = "http://localhost:3000"
119139
)
120140

121-
coderImg := os.Getenv("CODER_IMAGE")
122-
if coderImg == "" {
123-
coderImg = "ghcr.io/coder/coder"
124-
}
125-
126-
coderVersion := os.Getenv("CODER_VERSION")
127-
if coderVersion == "" {
128-
coderVersion = "latest"
129-
}
130-
131141
t.Logf("using coder image %s:%s", coderImg, coderVersion)
132142

133143
// Ensure the binary is built
@@ -151,11 +161,7 @@ func setup(ctx context.Context, t *testing.T, name string) string {
151161

152162
// Ensure the image is available locally.
153163
refStr := coderImg + ":" + coderVersion
154-
t.Logf("ensuring image %q", refStr)
155-
resp, err := cli.ImagePull(ctx, refStr, image.PullOptions{})
156-
require.NoError(t, err)
157-
_, err = io.ReadAll(resp)
158-
require.NoError(t, err)
164+
ensureImage(ctx, t, cli, refStr)
159165

160166
// Stand up a temporary Coder instance
161167
ctr, err := cli.ContainerCreate(ctx, &container.Config{
@@ -213,6 +219,25 @@ func setup(ctx context.Context, t *testing.T, name string) string {
213219
return ctr.ID
214220
}
215221

222+
func ensureImage(ctx context.Context, t *testing.T, cli *client.Client, ref string) {
223+
t.Helper()
224+
225+
t.Logf("ensuring image %q", ref)
226+
images, err := cli.ImageList(ctx, image.ListOptions{})
227+
require.NoError(t, err, "list images")
228+
for _, img := range images {
229+
if slices.Contains(img.RepoTags, ref) {
230+
t.Logf("image %q found locally, not pulling", ref)
231+
return
232+
}
233+
}
234+
t.Logf("image %s not found locally, attempting to pull", ref)
235+
resp, err := cli.ImagePull(ctx, ref, image.PullOptions{})
236+
require.NoError(t, err)
237+
_, err = io.ReadAll(resp)
238+
require.NoError(t, err)
239+
}
240+
216241
// execContainer executes the given command in the given container and returns
217242
// the output and the exit code of the command.
218243
func execContainer(ctx context.Context, t *testing.T, containerID, command string) (string, int) {
@@ -249,7 +274,7 @@ func assertOutput(t *testing.T, expected, actual map[string]string) {
249274

250275
for expectedKey, expectedValExpr := range expected {
251276
actualVal := actual[expectedKey]
252-
assert.Regexp(t, expectedValExpr, actualVal)
277+
assert.Regexp(t, expectedValExpr, actualVal, "output key %q does not have expected value", expectedKey)
253278
}
254279
for actualKey := range actual {
255280
_, ok := expected[actualKey]

0 commit comments

Comments
 (0)