sigs.k8s.io/cluster-api@v1.7.1/util/container/image_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package container 18 19 import ( 20 "strings" 21 "testing" 22 23 "github.com/distribution/reference" 24 . "github.com/onsi/gomega" 25 ) 26 27 func TestParseImageName(t *testing.T) { 28 testCases := []struct { 29 name string 30 input string 31 repo string 32 imageName string 33 tag string 34 digest string 35 wantError bool 36 }{ 37 { 38 name: "input with path and tag", 39 input: "registry.k8s.io/dev/coredns:1.6.2", 40 repo: "registry.k8s.io/dev", 41 imageName: "coredns", 42 tag: "1.6.2", 43 wantError: false, 44 }, 45 { 46 name: "input with name only", 47 input: "example.com/root", 48 repo: "example.com", 49 imageName: "root", 50 wantError: false, 51 }, 52 { 53 name: "input with name and tag without path", 54 input: "example.com/root:tag", 55 repo: "example.com", 56 imageName: "root", 57 tag: "tag", 58 wantError: false, 59 }, 60 { 61 name: "input with name and digest without tag", 62 input: "example.com/root@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 63 repo: "example.com", 64 imageName: "root", 65 digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 66 wantError: false, 67 }, 68 { 69 name: "input with path and name", 70 input: "example.com/user/repo", 71 repo: "example.com/user", 72 imageName: "repo", 73 wantError: false, 74 }, 75 { 76 name: "input with path, name and tag", 77 input: "example.com/user/repo:tag", 78 repo: "example.com/user", 79 imageName: "repo", 80 tag: "tag", 81 wantError: false, 82 }, 83 { 84 name: "input with path, name, tag and digest", 85 input: "example.com/user/repo:tag@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 86 repo: "example.com/user", 87 imageName: "repo", 88 tag: "tag", 89 digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 90 wantError: false, 91 }, 92 { 93 name: "input with url with port", 94 input: "url:5000/repo", 95 repo: "url:5000", 96 imageName: "repo", 97 wantError: false, 98 }, 99 { 100 name: "input with url with port and tag", 101 input: "url:5000/repo:tag", 102 repo: "url:5000", 103 imageName: "repo", 104 tag: "tag", 105 wantError: false, 106 }, 107 { 108 name: "input with url with port and digest", 109 input: "url:5000/repo@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 110 repo: "url:5000", 111 imageName: "repo", 112 digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", 113 wantError: false, 114 }, 115 { 116 name: "input with invalid image name", 117 input: "url$#", 118 repo: "", 119 imageName: "", 120 tag: "", 121 wantError: true, 122 }, 123 { 124 name: "input with a docker.io/ image name", 125 input: "docker.io/dev/kube-proxy:v1.99.99", 126 repo: "docker.io/dev", 127 imageName: "kube-proxy", 128 tag: "v1.99.99", 129 wantError: false, 130 }, 131 { 132 name: "input with a docker.io/ image name that is not canonical", 133 input: "dev/kube-proxy:v1.99.99", 134 repo: "dev", 135 imageName: "kube-proxy", 136 tag: "v1.99.99", 137 wantError: true, 138 }, 139 } 140 for _, tc := range testCases { 141 g := NewWithT(t) 142 143 t.Run(tc.name, func(*testing.T) { 144 image, err := ImageFromString(tc.input) 145 if tc.wantError { 146 g.Expect(err).To(HaveOccurred()) 147 } else { 148 g.Expect(err).ToNot(HaveOccurred()) 149 g.Expect(image.Repository).To(Equal(tc.repo)) 150 g.Expect(image.Name).To(Equal(tc.imageName)) 151 g.Expect(image.Tag).To(Equal(tc.tag)) 152 g.Expect(image.Digest).To(Equal(tc.digest)) 153 g.Expect(image.String()).To(Equal(tc.input)) 154 } 155 }) 156 } 157 } 158 159 func TestModifyImageRepository(t *testing.T) { 160 const testRepository = "example.com/new" 161 162 testCases := []struct { 163 name string 164 image string 165 repo string 166 want string 167 wantError bool 168 wantErrMessage string 169 }{ 170 { 171 name: "updates the repository of the image", 172 image: "example.com/subpaths/are/okay/image:1.17.3", 173 repo: testRepository, 174 want: "example.com/new/image:1.17.3", 175 wantError: false, 176 wantErrMessage: "", 177 }, 178 { 179 name: "errors if the repository name is too long", 180 image: "example.com/image:1.17.3", 181 repo: strings.Repeat("a", 255), 182 want: "", 183 wantError: true, 184 wantErrMessage: reference.ErrNameTooLong.Error(), 185 }, 186 { 187 name: "errors if the image name is not canonical", 188 image: "image:1.17.3", 189 repo: testRepository, 190 want: "", 191 wantError: true, 192 wantErrMessage: reference.ErrNameNotCanonical.Error(), 193 }, 194 { 195 name: "errors if the image name is not tagged", 196 image: "example.com/image", 197 repo: testRepository, 198 want: "", 199 wantError: true, 200 wantErrMessage: "image must be tagged", 201 }, 202 { 203 name: "errors if the image name is not valid", 204 image: "example.com/image:$@$(*", 205 repo: testRepository, 206 want: "", 207 wantError: true, 208 wantErrMessage: "failed to parse image name", 209 }, 210 } 211 for _, tc := range testCases { 212 g := NewWithT(t) 213 214 t.Run(tc.name, func(*testing.T) { 215 res, err := ModifyImageRepository(tc.image, tc.repo) 216 if tc.wantError { 217 g.Expect(err).To(HaveOccurred()) 218 g.Expect(err).To(MatchError(ContainSubstring(tc.wantErrMessage))) 219 } else { 220 g.Expect(err).ToNot(HaveOccurred()) 221 g.Expect(res).To(Equal(tc.want)) 222 } 223 }) 224 } 225 } 226 227 func TestModifyImageTag(t *testing.T) { 228 g := NewWithT(t) 229 t.Run("should ensure image is a docker compatible tag", func(*testing.T) { 230 testTag := "v1.17.4+build1" 231 image := "example.com/image:1.17.3" 232 res, err := ModifyImageTag(image, testTag) 233 g.Expect(err).ToNot(HaveOccurred()) 234 g.Expect(res).To(Equal("example.com/image:v1.17.4_build1")) 235 }) 236 t.Run("should ensure image is a docker compatible tag with docker.io", func(*testing.T) { 237 testTag := "v1.17.4+build1" 238 image := "docker.io/dev/image:1.17.3" 239 res, err := ModifyImageTag(image, testTag) 240 g.Expect(err).ToNot(HaveOccurred()) 241 g.Expect(res).To(Equal("docker.io/dev/image:v1.17.4_build1")) 242 }) 243 }