Skip to content

Commit 361df6c

Browse files
committed
add test case for not found
1 parent 53e2f1a commit 361df6c

File tree

3 files changed

+122
-70
lines changed

3 files changed

+122
-70
lines changed

internal/provider/cached_image_data_source.go

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,24 +299,20 @@ func (d *CachedImageDataSource) Read(ctx context.Context, req datasource.ReadReq
299299
}
300300

301301
image, err := envbuilder.RunCacheProbe(ctx, opts)
302+
data.Exists = types.BoolValue(err == nil)
302303
if err != nil {
303-
resp.Diagnostics.AddError("Failed to check for cached image", err.Error())
304-
return
305-
}
306-
307-
digest, err := image.Digest()
308-
if err != nil {
309-
resp.Diagnostics.AddError("Failed to get cached image digest", err.Error())
310-
return
304+
resp.Diagnostics.AddWarning("Cached image not found", err.Error())
305+
} else {
306+
digest, err := image.Digest()
307+
if err != nil {
308+
resp.Diagnostics.AddError("Failed to get cached image digest", err.Error())
309+
return
310+
}
311+
tflog.Info(ctx, fmt.Sprintf("found image: %s@%s", opts.CacheRepo, digest))
312+
data.ID = types.StringValue(digest.String())
313+
data.Image = types.StringValue(fmt.Sprintf("%s@%s", data.CacheRepo, digest.String()))
311314
}
312315

313-
tflog.Info(ctx, fmt.Sprintf("found image: %s@%s", opts.CacheRepo, digest))
314-
315-
// TODO(mafredri): Implement the actual data source read logic.
316-
data.ID = types.StringValue("cached-image-id")
317-
data.Exists = types.BoolValue(true)
318-
data.Image = types.StringValue(fmt.Sprintf("%s@%s", data.CacheRepo, digest.String()))
319-
320316
// Compute the env attribute from the config map.
321317
// TODO(mafredri): Convert any other relevant attributes given via schema.
322318
for key, elem := range data.ExtraEnv.Elements() {

internal/provider/cached_image_data_source_test.go

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,75 @@ import (
1616
// TODO: change this to only test for a non-existent image.
1717
// Move the heavy lifting to integration.
1818
func TestAccCachedImageDataSource(t *testing.T) {
19-
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
20-
t.Cleanup(cancel)
21-
files := map[string]string{
22-
"devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
23-
"Dockerfile": `FROM localhost:5000/test-ubuntu:latest
19+
t.Run("Found", func(t *testing.T) {
20+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
21+
t.Cleanup(cancel)
22+
files := map[string]string{
23+
"devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
24+
"Dockerfile": `FROM localhost:5000/test-ubuntu:latest
2425
RUN apt-get update && apt-get install -y cowsay`,
26+
}
27+
deps := setup(t, files)
28+
seedCache(ctx, t, deps)
29+
tfCfg := fmt.Sprintf(`data "envbuilder_cached_image" "test" {
30+
builder_image = %q
31+
devcontainer_dir = %q
32+
git_url = %q
33+
extra_env = {
34+
"FOO" : "bar"
2535
}
26-
deps := setup(ctx, t, files)
27-
tfCfg := fmt.Sprintf(`data "envbuilder_cached_image" "test" {
36+
cache_repo = %q
37+
}`, deps.BuilderImage, deps.RepoDir, deps.RepoDir, deps.CacheRepo)
38+
resource.Test(t, resource.TestCase{
39+
PreCheck: func() { testAccPreCheck(t) },
40+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
41+
Steps: []resource.TestStep{
42+
{
43+
Config: tfCfg,
44+
Check: resource.ComposeAggregateTestCheckFunc(
45+
// Inputs should still be present.
46+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", deps.CacheRepo),
47+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.FOO", "bar"),
48+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", deps.RepoDir),
49+
// Should be empty
50+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_username"),
51+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_password"),
52+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "cache_ttl_days"),
53+
// Computed
54+
resource.TestCheckResourceAttrWith("data.envbuilder_cached_image.test", "id", func(value string) error {
55+
// value is enclosed in quotes
56+
value = strings.Trim(value, `"`)
57+
if !strings.HasPrefix(value, "sha256:") {
58+
return fmt.Errorf("expected image %q to have prefix %q", value, deps.CacheRepo)
59+
}
60+
return nil
61+
}),
62+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "true"),
63+
resource.TestCheckResourceAttrSet("data.envbuilder_cached_image.test", "image"),
64+
resource.TestCheckResourceAttrWith("data.envbuilder_cached_image.test", "image", func(value string) error {
65+
// value is enclosed in quotes
66+
value = strings.Trim(value, `"`)
67+
if !strings.HasPrefix(value, deps.CacheRepo) {
68+
return fmt.Errorf("expected image %q to have prefix %q", value, deps.CacheRepo)
69+
}
70+
return nil
71+
}),
72+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "env.0", "FOO=\"bar\""),
73+
),
74+
},
75+
},
76+
})
77+
})
78+
79+
t.Run("NotFound", func(t *testing.T) {
80+
files := map[string]string{
81+
"devcontainer.json": `{"build": { "dockerfile": "Dockerfile" }}`,
82+
"Dockerfile": `FROM localhost:5000/test-ubuntu:latest
83+
RUN apt-get update && apt-get install -y cowsay`,
84+
}
85+
deps := setup(t, files)
86+
// We do not seed the cache.
87+
tfCfg := fmt.Sprintf(`data "envbuilder_cached_image" "test" {
2888
builder_image = %q
2989
devcontainer_dir = %q
3090
git_url = %q
@@ -33,37 +93,29 @@ func TestAccCachedImageDataSource(t *testing.T) {
3393
}
3494
cache_repo = %q
3595
}`, deps.BuilderImage, deps.RepoDir, deps.RepoDir, deps.CacheRepo)
36-
resource.Test(t, resource.TestCase{
37-
PreCheck: func() { testAccPreCheck(t) },
38-
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
39-
Steps: []resource.TestStep{
40-
// Read testing
41-
{
42-
Config: tfCfg,
43-
Check: resource.ComposeAggregateTestCheckFunc(
44-
// Input
45-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", deps.CacheRepo),
46-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.FOO", "bar"),
47-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", deps.RepoDir),
48-
// Should be empty
49-
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_username"),
50-
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_password"),
51-
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "cache_ttl_days"),
52-
// Computed
53-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "id", "cached-image-id"),
54-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "true"),
55-
resource.TestCheckResourceAttrSet("data.envbuilder_cached_image.test", "image"),
56-
resource.TestCheckResourceAttrWith("data.envbuilder_cached_image.test", "image", func(value string) error {
57-
// value is enclosed in quotes
58-
value = strings.Trim(value, `"`)
59-
if !strings.HasPrefix(value, deps.CacheRepo) {
60-
return fmt.Errorf("expected image %q to have prefix %q", value, deps.CacheRepo)
61-
}
62-
return nil
63-
}),
64-
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "env.0", "FOO=\"bar\""),
65-
),
96+
resource.Test(t, resource.TestCase{
97+
PreCheck: func() { testAccPreCheck(t) },
98+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
99+
Steps: []resource.TestStep{
100+
{
101+
Config: tfCfg,
102+
Check: resource.ComposeAggregateTestCheckFunc(
103+
// Inputs should still be present.
104+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "cache_repo", deps.CacheRepo),
105+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "extra_env.FOO", "bar"),
106+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "git_url", deps.RepoDir),
107+
// Should be empty
108+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_username"),
109+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "git_password"),
110+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "cache_ttl_days"),
111+
// Computed values should be empty.
112+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "id"),
113+
resource.TestCheckResourceAttr("data.envbuilder_cached_image.test", "exists", "false"),
114+
resource.TestCheckNoResourceAttr("data.envbuilder_cached_image.test", "image"),
115+
resource.TestCheckResourceAttrSet("data.envbuilder_cached_image.test", "env.0"),
116+
),
117+
},
66118
},
67-
},
119+
})
68120
})
69121
}

internal/provider/provider_test.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,28 +50,37 @@ type testDependencies struct {
5050
CacheRepo string
5151
}
5252

53-
func setup(ctx context.Context, t testing.TB, files map[string]string) testDependencies {
53+
func setup(t testing.TB, files map[string]string) testDependencies {
5454
t.Helper()
55-
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
56-
require.NoError(t, err, "init docker client")
57-
t.Cleanup(func() { _ = cli.Close() })
55+
56+
envbuilderImage := getEnvOrDefault("ENVBUILDER_IMAGE", "ghcr.io/coder/envbuilder-preview")
57+
envbuilderVersion := getEnvOrDefault("ENVBUILDER_VERSION", "latest")
58+
envbuilderImageRef := envbuilderImage + ":" + envbuilderVersion
5859

5960
// TODO: envbuilder creates /.envbuilder/bin/envbuilder owned by root:root which we are unable to clean up.
6061
// This causes tests to fail.
6162
repoDir := t.TempDir()
6263
cacheRepo := runLocalRegistry(t)
6364
writeFiles(t, files, repoDir)
65+
return testDependencies{
66+
BuilderImage: envbuilderImageRef,
67+
CacheRepo: cacheRepo,
68+
RepoDir: repoDir,
69+
}
70+
}
6471

65-
envbuilderImage := getEnvOrDefault("ENVBUILDER_IMAGE", "ghcr.io/coder/envbuilder-preview")
66-
envbuilderVersion := getEnvOrDefault("ENVBUILDER_VERSION", "latest")
67-
refStr := envbuilderImage + ":" + envbuilderVersion
68-
ensureImage(ctx, t, cli, refStr)
72+
73+
func seedCache(ctx context.Context, t testing.TB, deps testDependencies) {
74+
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
75+
require.NoError(t, err, "init docker client")
76+
t.Cleanup(func() { _ = cli.Close() })
77+
ensureImage(ctx, t, cli, deps.BuilderImage)
6978
// Run envbuilder using this dir as a local layer cache
7079
ctr, err := cli.ContainerCreate(ctx, &container.Config{
71-
Image: refStr,
80+
Image: deps.BuilderImage,
7281
Env: []string{
73-
"ENVBUILDER_CACHE_REPO=" + cacheRepo,
74-
"ENVBUILDER_DEVCONTAINER_DIR=" + repoDir,
82+
"ENVBUILDER_CACHE_REPO=" + deps.CacheRepo,
83+
"ENVBUILDER_DEVCONTAINER_DIR=" + deps.RepoDir,
7584
"ENVBUILDER_EXIT_ON_BUILD_FAILURE=true",
7685
"ENVBUILDER_INIT_SCRIPT=exit",
7786
// FIXME: Enabling this options causes envbuilder to add its binary to the image under the path
@@ -83,7 +92,7 @@ func setup(ctx context.Context, t testing.TB, files map[string]string) testDepen
8392
testContainerLabel: "true",
8493
}}, &container.HostConfig{
8594
NetworkMode: container.NetworkMode("host"),
86-
Binds: []string{repoDir + ":" + repoDir},
95+
Binds: []string{deps.RepoDir+ ":" + deps.RepoDir},
8796
}, nil, nil, "")
8897
require.NoError(t, err, "failed to run envbuilder to seed cache")
8998
t.Cleanup(func() {
@@ -121,11 +130,6 @@ SCANLOGS:
121130
}
122131
}
123132

124-
return testDependencies{
125-
BuilderImage: refStr,
126-
CacheRepo: cacheRepo,
127-
RepoDir: repoDir,
128-
}
129133
}
130134

131135
func getEnvOrDefault(env, defVal string) string {

0 commit comments

Comments
 (0)