github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/initializer/build/builders_test.go (about) 1 /* 2 Copyright 2020 The Skaffold 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 build 18 19 import ( 20 "testing" 21 22 "github.com/google/go-cmp/cmp" 23 24 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/buildpacks" 25 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/jib" 26 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" 27 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/prompt" 28 tag "github.com/GoogleContainerTools/skaffold/pkg/skaffold/tag/util" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings" 30 "github.com/GoogleContainerTools/skaffold/testutil" 31 ) 32 33 func TestResolveBuilderImages(t *testing.T) { 34 tests := []struct { 35 description string 36 buildConfigs []InitBuilder 37 images []string 38 force bool 39 shouldMakeChoice bool 40 shouldErr bool 41 expectedInfos []ArtifactInfo 42 expectedGeneratedInfos []GeneratedArtifactInfo 43 }{ 44 { 45 description: "nothing to choose from", 46 buildConfigs: []InitBuilder{}, 47 images: []string{}, 48 shouldMakeChoice: false, 49 expectedInfos: nil, 50 }, 51 { 52 description: "don't prompt for single dockerfile and image", 53 buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "Dockerfile1"}}, 54 images: []string{"image1"}, 55 shouldMakeChoice: false, 56 expectedInfos: []ArtifactInfo{ 57 { 58 Builder: docker.ArtifactConfig{File: "Dockerfile1"}, 59 ImageName: "image1", 60 }, 61 }, 62 }, 63 { 64 description: "prompt for multiple builders and images", 65 buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "Dockerfile1"}, jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}, jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), Project: "project", File: "pom.xml"}}, 66 images: []string{"image1", "image2"}, 67 shouldMakeChoice: true, 68 expectedInfos: []ArtifactInfo{ 69 { 70 Builder: docker.ArtifactConfig{File: "Dockerfile1"}, 71 ImageName: "image1", 72 }, 73 { 74 Builder: jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}, 75 ImageName: "image2", 76 }, 77 }, 78 expectedGeneratedInfos: []GeneratedArtifactInfo{ 79 { 80 ArtifactInfo: ArtifactInfo{ 81 Builder: jib.ArtifactConfig{BuilderName: "Jib Maven Plugin", File: "pom.xml", Project: "project"}, 82 ImageName: "pom-xml-image", 83 }, 84 ManifestPath: "deployment.yaml", 85 }, 86 }, 87 }, 88 { 89 description: "successful force", 90 buildConfigs: []InitBuilder{jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}}, 91 images: []string{"image1"}, 92 shouldMakeChoice: false, 93 force: true, 94 expectedInfos: []ArtifactInfo{ 95 { 96 Builder: jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}, 97 ImageName: "image1", 98 }, 99 }, 100 }, 101 { 102 description: "successful force - 1 image 2 builders", 103 buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "Dockerfile1"}, jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}}, 104 images: []string{"image1"}, 105 shouldMakeChoice: true, 106 force: true, 107 expectedInfos: []ArtifactInfo{ 108 { 109 Builder: docker.ArtifactConfig{File: "Dockerfile1"}, 110 ImageName: "image1", 111 }, 112 }, 113 }, 114 { 115 description: "error with ambiguous force", 116 buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "Dockerfile1"}, jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}}, 117 images: []string{"image1", "image2"}, 118 shouldMakeChoice: false, 119 force: true, 120 shouldErr: true, 121 }, 122 { 123 description: "one unresolved image", 124 buildConfigs: []InitBuilder{docker.ArtifactConfig{File: "foo"}}, 125 images: []string{}, 126 expectedGeneratedInfos: []GeneratedArtifactInfo{ 127 { 128 ArtifactInfo: ArtifactInfo{ 129 Builder: docker.ArtifactConfig{File: "foo"}, 130 ImageName: "foo-image", 131 }, 132 ManifestPath: "deployment.yaml", 133 }, 134 }, 135 shouldMakeChoice: false, 136 force: false, 137 shouldErr: false, 138 }, 139 } 140 for _, test := range tests { 141 testutil.Run(t, test.description, func(t *testutil.T) { 142 t.Override(&prompt.ChooseBuildersFunc, func(choices []string) ([]string, error) { 143 return choices, nil 144 }) 145 // Overrides prompt.BuildConfigFunc to choose first option rather than using the interactive menu 146 t.Override(&prompt.BuildConfigFunc, func(image string, choices []string) (string, error) { 147 if !test.shouldMakeChoice { 148 t.FailNow() 149 } 150 return choices[0], nil 151 }) 152 153 initializer := &defaultBuildInitializer{ 154 builders: test.buildConfigs, 155 force: test.force, 156 unresolvedImages: test.images, 157 } 158 err := initializer.resolveBuilderImages() 159 t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expectedInfos, initializer.artifactInfos, cmp.AllowUnexported()) 160 t.CheckDeepEqual(test.expectedGeneratedInfos, initializer.generatedArtifactInfos, cmp.AllowUnexported()) 161 }) 162 } 163 } 164 165 func TestAutoSelectBuilders(t *testing.T) { 166 tests := []struct { 167 description string 168 builderConfigs []InitBuilder 169 images []string 170 expectedInfos []ArtifactInfo 171 expectedBuildersLeft []InitBuilder 172 expectedUnresolvedImages []string 173 }{ 174 { 175 description: "no automatic matches", 176 builderConfigs: []InitBuilder{ 177 docker.ArtifactConfig{File: "Dockerfile"}, 178 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}, 179 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "not a k8s image"}, 180 }, 181 images: []string{"image1", "image2"}, 182 expectedInfos: nil, 183 expectedBuildersLeft: []InitBuilder{ 184 docker.ArtifactConfig{File: "Dockerfile"}, 185 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle"}, 186 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "not a k8s image"}, 187 }, 188 expectedUnresolvedImages: []string{"image1", "image2"}, 189 }, 190 { 191 description: "automatic jib matches", 192 builderConfigs: []InitBuilder{ 193 docker.ArtifactConfig{File: "Dockerfile"}, 194 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle", Image: "image1"}, 195 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "image2"}, 196 }, 197 images: []string{"image1", "image2", "image3"}, 198 expectedInfos: []ArtifactInfo{ 199 { 200 Builder: jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle", Image: "image1"}, 201 ImageName: "image1", 202 }, 203 { 204 Builder: jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "image2"}, 205 ImageName: "image2", 206 }, 207 }, 208 expectedBuildersLeft: []InitBuilder{docker.ArtifactConfig{File: "Dockerfile"}}, 209 expectedUnresolvedImages: []string{"image3"}, 210 }, 211 { 212 description: "multiple matches for one image", 213 builderConfigs: []InitBuilder{ 214 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle", Image: "image1"}, 215 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "image1"}, 216 }, 217 images: []string{"image1", "image2"}, 218 expectedInfos: nil, 219 expectedBuildersLeft: []InitBuilder{ 220 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibGradle), File: "build.gradle", Image: "image1"}, 221 jib.ArtifactConfig{BuilderName: jib.PluginName(jib.JibMaven), File: "pom.xml", Image: "image1"}, 222 }, 223 expectedUnresolvedImages: []string{"image1", "image2"}, 224 }, 225 { 226 description: "show unique image names", 227 builderConfigs: nil, 228 images: []string{"image1", "image1"}, 229 expectedInfos: nil, 230 expectedBuildersLeft: nil, 231 expectedUnresolvedImages: []string{"image1"}, 232 }, 233 } 234 235 for _, test := range tests { 236 testutil.Run(t, test.description, func(t *testutil.T) { 237 pairs, builderConfigs, unresolvedImages := matchBuildersToImages(test.builderConfigs, test.images) 238 239 t.CheckDeepEqual(test.expectedInfos, pairs) 240 t.CheckDeepEqual(test.expectedBuildersLeft, builderConfigs) 241 t.CheckDeepEqual(test.expectedUnresolvedImages, unresolvedImages) 242 }) 243 } 244 } 245 246 func TestProcessCliArtifacts(t *testing.T) { 247 tests := []struct { 248 description string 249 artifacts []string 250 shouldErr bool 251 expectedInfos []ArtifactInfo 252 expectedWorkspaces []string 253 }{ 254 { 255 description: "Invalid pairs", 256 artifacts: []string{"invalid"}, 257 shouldErr: true, 258 }, 259 { 260 description: "Invalid builder", 261 artifacts: []string{`{"builder":"Not real","payload":{},"image":"image"}`}, 262 shouldErr: true, 263 }, 264 { 265 description: "Valid (backwards compatibility)", 266 artifacts: []string{ 267 `/path/to/Dockerfile=image1`, 268 `/path/to/Dockerfile2=image2`, 269 }, 270 expectedInfos: []ArtifactInfo{ 271 { 272 Builder: docker.ArtifactConfig{File: "/path/to/Dockerfile"}, 273 ImageName: "image1", 274 }, 275 { 276 Builder: docker.ArtifactConfig{File: "/path/to/Dockerfile2"}, 277 ImageName: "image2", 278 }, 279 }, 280 }, 281 { 282 description: "Valid", 283 artifacts: []string{ 284 `{"builder":"Docker","payload":{"path":"/path/to/Dockerfile"},"image":"image1", "context": "path/to/docker/workspace"}`, 285 `{"builder":"Jib Gradle Plugin","payload":{"path":"/path/to/build.gradle"},"image":"image2", "context":"path/to/jib/workspace"}`, 286 `{"builder":"Jib Maven Plugin","payload":{"path":"/path/to/pom.xml","project":"project-name","image":"testImage"},"image":"image3"}`, 287 `{"builder":"Buildpacks","payload":{"path":"/path/to/package.json"},"image":"image4"}`, 288 }, 289 expectedInfos: []ArtifactInfo{ 290 { 291 Builder: docker.ArtifactConfig{File: "/path/to/Dockerfile"}, 292 ImageName: "image1", 293 Workspace: "path/to/docker/workspace", 294 }, 295 { 296 Builder: jib.ArtifactConfig{BuilderName: "Jib Gradle Plugin", File: "/path/to/build.gradle"}, 297 ImageName: "image2", 298 Workspace: "path/to/jib/workspace", 299 }, 300 { 301 Builder: jib.ArtifactConfig{BuilderName: "Jib Maven Plugin", File: "/path/to/pom.xml", Project: "project-name", Image: "testImage"}, 302 ImageName: "image3", 303 }, 304 { 305 Builder: buildpacks.ArtifactConfig{File: "/path/to/package.json"}, 306 ImageName: "image4", 307 }, 308 }, 309 }, 310 } 311 312 for _, test := range tests { 313 testutil.Run(t, test.description, func(t *testutil.T) { 314 pairs, err := processCliArtifacts(test.artifacts) 315 316 t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expectedInfos, pairs) 317 }) 318 } 319 } 320 321 func TestStripImageTags(t *testing.T) { 322 tests := []struct { 323 description string 324 taggedImages []string 325 expectedImages []string 326 expectedWarnings []string 327 }{ 328 { 329 description: "empty", 330 taggedImages: nil, 331 expectedImages: nil, 332 expectedWarnings: nil, 333 }, 334 { 335 description: "tags are removed", 336 taggedImages: []string{ 337 "gcr.io/testproject/testimage:latest", 338 "testdockerhublib/bla:v1.0", 339 "registrywithport:5000/image:v2.3", 340 }, 341 expectedImages: []string{ 342 "gcr.io/testproject/testimage", 343 "testdockerhublib/bla", 344 "registrywithport:5000/image", 345 }, 346 expectedWarnings: nil, 347 }, 348 { 349 description: "invalid image names are skipped with warning", 350 taggedImages: []string{ 351 "gcr.io/testproject/testimage:latest", 352 "{{ REPOSITORY }}/{{IMAGE}}", 353 }, 354 expectedImages: []string{ 355 "gcr.io/testproject/testimage", 356 }, 357 expectedWarnings: nil, 358 }, 359 { 360 description: "images with digest are ignored", 361 taggedImages: []string{ 362 "gcr.io/testregistry/testimage@sha256:16a019b0fa168b31fbecb3f909f55a5342e39f346cae919b7ff0b22f40029876", 363 }, 364 expectedImages: nil, 365 expectedWarnings: []string{ 366 "Ignoring image referenced by digest: [gcr.io/testregistry/testimage@sha256:16a019b0fa168b31fbecb3f909f55a5342e39f346cae919b7ff0b22f40029876]", 367 }, 368 }, 369 } 370 371 for _, test := range tests { 372 testutil.Run(t, test.description, func(t *testutil.T) { 373 fakeWarner := &warnings.Collect{} 374 t.Override(&warnings.Printf, fakeWarner.Warnf) 375 376 images := tag.StripTags(test.taggedImages, true) 377 378 t.CheckDeepEqual(test.expectedImages, images) 379 t.CheckDeepEqual(test.expectedWarnings, fakeWarner.Warnings) 380 }) 381 } 382 }