Skip to content

Commit 98befa8

Browse files
committed
tests: Add unit tests to image-updater pkg/image
Signed-off-by: Cheng Fang <[email protected]>
1 parent f9b5d95 commit 98befa8

File tree

5 files changed

+351
-6
lines changed

5 files changed

+351
-6
lines changed

pkg/image/credentials_test.go

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package image
22

33
import (
4+
"fmt"
45
"os"
56
"path"
7+
"strings"
68
"testing"
79

810
"github.com/argoproj-labs/argocd-image-updater/pkg/kube"
9-
1011
"github.com/argoproj-labs/argocd-image-updater/test/fake"
1112
"github.com/argoproj-labs/argocd-image-updater/test/fixture"
12-
1313
"github.com/stretchr/testify/assert"
1414
"github.com/stretchr/testify/require"
1515
)
@@ -101,6 +101,12 @@ func Test_ParseCredentialAnnotation(t *testing.T) {
101101
assert.Equal(t, "DUMMY_SECRET", src.EnvName)
102102
})
103103

104+
t.Run("Parse external script credentials", func(t *testing.T) {
105+
src, err := ParseCredentialSource("ext:/tmp/a.sh", false)
106+
require.NoError(t, err)
107+
assert.Equal(t, CredentialSourceExt, src.Type)
108+
assert.Equal(t, "/tmp/a.sh", src.ScriptPath)
109+
})
104110
}
105111

106112
func Test_ParseCredentialReference(t *testing.T) {
@@ -130,6 +136,53 @@ func Test_ParseCredentialReference(t *testing.T) {
130136

131137
}
132138

139+
func Test_FetchCredentialsFromSecret(t *testing.T) {
140+
t.Run("Fetch credentials from secret", func(t *testing.T) {
141+
secretData := make(map[string][]byte)
142+
secretData["username_password"] = []byte(fmt.Sprintf("%s:%s", "foo", "bar"))
143+
secret := fixture.NewSecret("test", "test", secretData)
144+
clientset := fake.NewFakeClientsetWithResources(secret)
145+
credSrc := &CredentialSource{
146+
Type: CredentialSourceSecret,
147+
SecretNamespace: "test",
148+
SecretName: "test",
149+
SecretField: "username_password",
150+
}
151+
creds, err := credSrc.FetchCredentials("NA", &kube.KubernetesClient{Clientset: clientset})
152+
require.NoError(t, err)
153+
require.NotNil(t, creds)
154+
assert.Equal(t, "foo", creds.Username)
155+
assert.Equal(t, "bar", creds.Password)
156+
157+
credSrc.SecretNamespace = "test1" // test with a wrong SecretNamespace
158+
creds, err = credSrc.FetchCredentials("NA", &kube.KubernetesClient{Clientset: clientset})
159+
require.Error(t, err)
160+
require.Nil(t, creds)
161+
})
162+
163+
t.Run("Fetch credentials from secret with invalid config", func(t *testing.T) {
164+
secretData := make(map[string][]byte)
165+
secretData["username_password"] = []byte(fmt.Sprintf("%s:%s", "foo", "bar"))
166+
secret := fixture.NewSecret("test", "test", secretData)
167+
clientset := fake.NewFakeClientsetWithResources(secret)
168+
credSrc := &CredentialSource{
169+
Type: CredentialSourceSecret,
170+
SecretNamespace: "test",
171+
SecretName: "test",
172+
SecretField: "username_password",
173+
}
174+
creds, err := credSrc.FetchCredentials("NA", nil)
175+
require.Error(t, err) // should fail with "could not fetch credentials: no Kubernetes client given"
176+
require.Nil(t, creds)
177+
178+
credSrc.SecretField = "BAD" // test with a wrong SecretField
179+
creds, err = credSrc.FetchCredentials("NA", &kube.KubernetesClient{Clientset: clientset})
180+
require.Error(t, err)
181+
require.Nil(t, creds)
182+
183+
})
184+
}
185+
133186
func Test_FetchCredentialsFromPullSecret(t *testing.T) {
134187
t.Run("Fetch credentials from pull secret", func(t *testing.T) {
135188
dockerJson := fixture.MustReadFile("../../test/testdata/docker/valid-config.json")
@@ -148,6 +201,33 @@ func Test_FetchCredentialsFromPullSecret(t *testing.T) {
148201
require.NotNil(t, creds)
149202
assert.Equal(t, "foo", creds.Username)
150203
assert.Equal(t, "bar", creds.Password)
204+
205+
credSrc.SecretNamespace = "test1" // test with a wrong SecretNamespace
206+
creds, err = credSrc.FetchCredentials("https://registry-1.docker.io", &kube.KubernetesClient{Clientset: clientset})
207+
require.Error(t, err)
208+
require.Nil(t, creds)
209+
})
210+
211+
t.Run("Fetch credentials from pull secret with invalid config", func(t *testing.T) {
212+
dockerJson := fixture.MustReadFile("../../test/testdata/docker/valid-config.json")
213+
dockerJson = strings.ReplaceAll(dockerJson, "auths", "BAD-KEY")
214+
secretData := make(map[string][]byte)
215+
secretData[pullSecretField] = []byte(dockerJson)
216+
pullSecret := fixture.NewSecret("test", "test", secretData)
217+
clientset := fake.NewFakeClientsetWithResources(pullSecret)
218+
credSrc := &CredentialSource{
219+
Type: CredentialSourcePullSecret,
220+
Registry: "https://registry-1.docker.io/v2",
221+
SecretNamespace: "test",
222+
SecretName: "test",
223+
}
224+
creds, err := credSrc.FetchCredentials("https://registry-1.docker.io", &kube.KubernetesClient{Clientset: clientset})
225+
require.Error(t, err) // should fail with "no credentials in image pull secret"
226+
require.Nil(t, creds)
227+
228+
creds, err = credSrc.FetchCredentials("https://registry-1.docker.io", nil)
229+
require.Error(t, err) // should fail with "could not fetch credentials: no Kubernetes client given"
230+
require.Nil(t, creds)
151231
})
152232

153233
t.Run("Fetch credentials from pull secret with protocol stripped", func(t *testing.T) {
@@ -266,6 +346,18 @@ func Test_FetchCredentialsFromExt(t *testing.T) {
266346
})
267347
}
268348

349+
func Test_FetchCredentialsFromUnknown(t *testing.T) {
350+
t.Run("Fetch credentials from unknown type", func(t *testing.T) {
351+
credSrc := &CredentialSource{
352+
Type: CredentialSourceType(-1),
353+
Registry: "https://registry-1.docker.io/v2",
354+
}
355+
creds, err := credSrc.FetchCredentials("https://registry-1.docker.io", nil)
356+
require.Error(t, err) // should fail with "unknown credential type"
357+
require.Nil(t, creds)
358+
})
359+
}
360+
269361
func Test_ParseDockerConfig(t *testing.T) {
270362
t.Run("Parse valid Docker configuration with matching registry", func(t *testing.T) {
271363
config := fixture.MustReadFile("../../test/testdata/docker/valid-config.json")
@@ -283,6 +375,22 @@ func Test_ParseDockerConfig(t *testing.T) {
283375
assert.Equal(t, "bar", password)
284376
})
285377

378+
t.Run("Parse valid Docker configuration with matching http registry as prefix", func(t *testing.T) {
379+
config := fixture.MustReadFile("../../test/testdata/docker/valid-config-noproto.json")
380+
username, password, err := parseDockerConfigJson("http://registry-1.docker.io", config)
381+
require.NoError(t, err)
382+
assert.Equal(t, "foo", username)
383+
assert.Equal(t, "bar", password)
384+
})
385+
386+
t.Run("Parse valid Docker configuration with matching no-protocol registry as prefix", func(t *testing.T) {
387+
config := fixture.MustReadFile("../../test/testdata/docker/valid-config-noproto.json")
388+
username, password, err := parseDockerConfigJson("registry-1.docker.io", config)
389+
require.NoError(t, err)
390+
assert.Equal(t, "foo", username)
391+
assert.Equal(t, "bar", password)
392+
})
393+
286394
t.Run("Parse valid Docker configuration with matching registry as prefix with / in the end", func(t *testing.T) {
287395
config := fixture.MustReadFile("../../test/testdata/docker/valid-config-noproto.json")
288396
username, password, err := parseDockerConfigJson("https://registry-1.docker.io/", config)

pkg/image/image_test.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import (
55
"time"
66

77
"github.com/argoproj-labs/argocd-image-updater/pkg/tag"
8-
98
"github.com/stretchr/testify/assert"
109
"github.com/stretchr/testify/require"
10+
"golang.org/x/exp/slices"
1111
)
1212

1313
func Test_ParseImageTags(t *testing.T) {
@@ -160,9 +160,65 @@ func Test_ContainerList(t *testing.T) {
160160
for _, n := range image_names {
161161
images = append(images, NewFromIdentifier(n))
162162
}
163+
withKustomizeOverride := NewFromIdentifier("k1/k2:k3")
164+
withKustomizeOverride.KustomizeImage = images[0]
165+
images = append(images, withKustomizeOverride)
166+
163167
assert.NotNil(t, images.ContainsImage(NewFromIdentifier(image_names[0]), false))
164168
assert.NotNil(t, images.ContainsImage(NewFromIdentifier(image_names[1]), false))
165169
assert.NotNil(t, images.ContainsImage(NewFromIdentifier(image_names[2]), false))
166170
assert.Nil(t, images.ContainsImage(NewFromIdentifier("foo/bar"), false))
171+
172+
imageMatch := images.ContainsImage(withKustomizeOverride, false)
173+
assert.Equal(t, images[0], imageMatch)
167174
})
168175
}
176+
177+
func Test_getImageDigestFromTag(t *testing.T) {
178+
tagAndDigest := "test-tag@sha256:abcde"
179+
tagName, tagDigest := getImageDigestFromTag(tagAndDigest)
180+
assert.Equal(t, "test-tag", tagName)
181+
assert.Equal(t, "sha256:abcde", tagDigest)
182+
183+
tagAndDigest = "test-tag"
184+
tagName, tagDigest = getImageDigestFromTag(tagAndDigest)
185+
assert.Equal(t, "test-tag", tagName)
186+
assert.Empty(t, tagDigest)
187+
}
188+
189+
func Test_ContainerImageList_String_Originals(t *testing.T) {
190+
images := make(ContainerImageList, 0)
191+
originals := []string{}
192+
193+
assert.Equal(t, "", images.String())
194+
assert.True(t, slices.Equal(originals, images.Originals()))
195+
196+
images = append(images, NewFromIdentifier("foo/bar:0.1"))
197+
originals = append(originals, "foo/bar:0.1")
198+
assert.Equal(t, "foo/bar:0.1", images.String())
199+
assert.True(t, slices.Equal(originals, images.Originals()))
200+
201+
images = append(images, NewFromIdentifier("alias=foo/bar:0.2"))
202+
originals = append(originals, "alias=foo/bar:0.2")
203+
assert.Equal(t, "foo/bar:0.1,alias=foo/bar:0.2", images.String())
204+
assert.True(t, slices.Equal(originals, images.Originals()))
205+
}
206+
207+
func TestContainerImage_DiffersFrom(t *testing.T) {
208+
foo1 := NewFromIdentifier("x/foo:1")
209+
foo2 := NewFromIdentifier("x/foo:2")
210+
bar1 := NewFromIdentifier("x/bar:1")
211+
bar1WithRegistry := NewFromIdentifier("docker.io/x/bar:1")
212+
213+
assert.False(t, foo1.DiffersFrom(foo1, true))
214+
assert.False(t, foo1.DiffersFrom(foo2, false))
215+
assert.True(t, foo1.DiffersFrom(foo2, true))
216+
217+
assert.True(t, foo1.DiffersFrom(bar1, false))
218+
assert.True(t, bar1.DiffersFrom(foo1, false))
219+
assert.True(t, foo1.DiffersFrom(bar1, true))
220+
assert.True(t, bar1.DiffersFrom(foo1, true))
221+
assert.True(t, bar1.DiffersFrom(bar1WithRegistry, false))
222+
223+
assert.False(t, foo1.IsUpdatable("0.1", "^1.0"))
224+
}

pkg/image/kustomize_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package image
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func Test_KustomizeImages_Find(t *testing.T) {
10+
images := KustomizeImages{
11+
"a/b:1.0",
12+
"a/b@sha256:aabb",
13+
"a/b:latest@sha256:aabb",
14+
"x/y=busybox",
15+
"x/y=foo.bar/a/c:0.23",
16+
}
17+
for _, image := range images {
18+
assert.True(t, images.Find(image) >= 0)
19+
}
20+
for _, image := range []string{"a/b:2", "x/y=foo.bar"} {
21+
assert.True(t, images.Find(KustomizeImage(image)) >= 0)
22+
}
23+
for _, image := range []string{"a/b", "x", "x/y"} {
24+
assert.Equal(t, -1, images.Find(KustomizeImage(image)))
25+
}
26+
}

pkg/image/options_test.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88

99
"github.com/argoproj-labs/argocd-image-updater/pkg/common"
1010
"github.com/argoproj-labs/argocd-image-updater/pkg/options"
11-
1211
"github.com/stretchr/testify/assert"
1312
"github.com/stretchr/testify/require"
1413
)
@@ -64,14 +63,18 @@ func Test_GetHelmOptions(t *testing.T) {
6463
}
6564

6665
func Test_GetKustomizeOptions(t *testing.T) {
67-
t.Run("Get Helm parameter for configured application", func(t *testing.T) {
66+
t.Run("Get Kustomize parameter for configured application", func(t *testing.T) {
6867
annotations := map[string]string{
6968
fmt.Sprintf(common.KustomizeApplicationNameAnnotation, "dummy"): "argoproj/argo-cd",
7069
}
7170

7271
img := NewFromIdentifier("dummy=foo/bar:1.12")
7372
paramName := img.GetParameterKustomizeImageName(annotations)
7473
assert.Equal(t, "argoproj/argo-cd", paramName)
74+
75+
img = NewFromIdentifier("dummy2=foo2/bar2:1.12")
76+
paramName = img.GetParameterKustomizeImageName(annotations)
77+
assert.Equal(t, "", paramName)
7578
})
7679
}
7780

@@ -155,6 +158,15 @@ func Test_GetSortOption(t *testing.T) {
155158
sortMode := img.GetParameterUpdateStrategy(annotations)
156159
assert.Equal(t, StrategyNewestBuild, sortMode)
157160
})
161+
162+
t.Run("Get update strategy option digest from application-wide annotation", func(t *testing.T) {
163+
annotations := map[string]string{
164+
common.ApplicationWideUpdateStrategyAnnotation: "digest",
165+
}
166+
img := NewFromIdentifier("dummy=foo/bar:1.12")
167+
sortMode := img.GetParameterUpdateStrategy(annotations)
168+
assert.Equal(t, StrategyDigest, sortMode)
169+
})
158170
}
159171

160172
func Test_GetMatchOption(t *testing.T) {
@@ -190,6 +202,15 @@ func Test_GetMatchOption(t *testing.T) {
190202
assert.Nil(t, matchArgs)
191203
})
192204

205+
t.Run("No match option for configured application", func(t *testing.T) {
206+
annotations := map[string]string{}
207+
img := NewFromIdentifier("dummy=foo/bar:1.12")
208+
matchFunc, matchArgs := img.GetParameterMatch(annotations)
209+
require.NotNil(t, matchFunc)
210+
require.Equal(t, true, matchFunc("", nil))
211+
assert.Equal(t, "", matchArgs)
212+
})
213+
193214
t.Run("Prefer match option from image-specific annotation", func(t *testing.T) {
194215
annotations := map[string]string{
195216
fmt.Sprintf(common.AllowTagsOptionAnnotation, "dummy"): "regexp:^[0-9]",
@@ -241,6 +262,13 @@ func Test_GetSecretOption(t *testing.T) {
241262
require.Nil(t, credSrc)
242263
})
243264

265+
t.Run("Missing pull secret in annotation", func(t *testing.T) {
266+
annotations := map[string]string{}
267+
img := NewFromIdentifier("dummy=foo/bar:1.12")
268+
credSrc := img.GetParameterPullSecret(annotations)
269+
require.Nil(t, credSrc)
270+
})
271+
244272
t.Run("Prefer cred source from image-specific annotation", func(t *testing.T) {
245273
annotations := map[string]string{
246274
fmt.Sprintf(common.PullSecretAnnotation, "dummy"): "pullsecret:image/specific",
@@ -283,6 +311,13 @@ func Test_GetIgnoreTags(t *testing.T) {
283311
assert.Equal(t, "tag4", tags[3])
284312
})
285313

314+
t.Run("No tags to ignore from image-specific annotation", func(t *testing.T) {
315+
annotations := map[string]string{}
316+
img := NewFromIdentifier("dummy=foo/bar:1.12")
317+
tags := img.GetParameterIgnoreTags(annotations)
318+
require.Nil(t, tags)
319+
})
320+
286321
t.Run("Prefer list of tags to ignore from image-specific annotation", func(t *testing.T) {
287322
annotations := map[string]string{
288323
fmt.Sprintf(common.IgnoreTagsOptionAnnotation, "dummy"): "tag1, tag2",
@@ -412,3 +447,36 @@ func Test_GetPlatformOptions(t *testing.T) {
412447
assert.False(t, opts.WantsPlatform(runtime.GOOS, runtime.GOARCH, variant))
413448
})
414449
}
450+
451+
func Test_ContainerImage_ParseMatchfunc(t *testing.T) {
452+
img := NewFromIdentifier("dummy=foo/bar:1.12")
453+
matchFunc, pattern := img.ParseMatchfunc("any")
454+
assert.True(t, matchFunc("MatchFuncAny any tag name", pattern))
455+
assert.Nil(t, pattern)
456+
457+
matchFunc, pattern = img.ParseMatchfunc("ANY")
458+
assert.True(t, matchFunc("MatchFuncAny any tag name", pattern))
459+
assert.Nil(t, pattern)
460+
461+
matchFunc, pattern = img.ParseMatchfunc("other")
462+
assert.False(t, matchFunc("MatchFuncNone any tag name", pattern))
463+
assert.Nil(t, pattern)
464+
465+
matchFunc, pattern = img.ParseMatchfunc("not-regexp:a-z")
466+
assert.False(t, matchFunc("MatchFuncNone any tag name", pattern))
467+
assert.Nil(t, pattern)
468+
469+
matchFunc, pattern = img.ParseMatchfunc("regexp:[aA-zZ]")
470+
assert.True(t, matchFunc("MatchFuncRegexp-tag-name", pattern))
471+
compiledRegexp, _ := regexp.Compile("[aA-zZ]")
472+
assert.Equal(t, compiledRegexp, pattern)
473+
474+
matchFunc, pattern = img.ParseMatchfunc("RegExp:[aA-zZ]")
475+
assert.True(t, matchFunc("MatchFuncRegexp-tag-name", pattern))
476+
compiledRegexp, _ = regexp.Compile("[aA-zZ]")
477+
assert.Equal(t, compiledRegexp, pattern)
478+
479+
matchFunc, pattern = img.ParseMatchfunc("regexp:[aA-zZ") //invalid regexp: missing end ]
480+
assert.False(t, matchFunc("MatchFuncNone-tag-name", pattern))
481+
assert.Nil(t, pattern)
482+
}

0 commit comments

Comments
 (0)