github.com/SAP/jenkins-library@v1.362.0/cmd/cnbBuild_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package cmd 5 6 import ( 7 "fmt" 8 "net/http" 9 "path/filepath" 10 "testing" 11 12 "github.com/SAP/jenkins-library/pkg/cnbutils" 13 piperconf "github.com/SAP/jenkins-library/pkg/config" 14 piperhttp "github.com/SAP/jenkins-library/pkg/http" 15 "github.com/SAP/jenkins-library/pkg/mock" 16 "github.com/SAP/jenkins-library/pkg/telemetry" 17 v1 "github.com/google/go-containerregistry/pkg/v1" 18 "github.com/google/go-containerregistry/pkg/v1/fake" 19 "github.com/jarcoal/httpmock" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 const imageRegistry = "some-registry" 25 26 func newCnbBuildTestsUtils() cnbutils.MockUtils { 27 imageStub := func(imageRef, target string) (v1.Image, error) { 28 fakeImage := &fake.FakeImage{} 29 var imageConfig v1.Config 30 switch imageRef { 31 case "pre-test": 32 imageConfig = v1.Config{ 33 Labels: map[string]string{ 34 "io.buildpacks.buildpackage.metadata": "{\"id\": \"pre-testbuildpack\", \"version\": \"0.0.1\"}", 35 }, 36 } 37 case "post-test": 38 imageConfig = v1.Config{ 39 Labels: map[string]string{ 40 "io.buildpacks.buildpackage.metadata": "{\"id\": \"post-testbuildpack\", \"version\": \"0.0.1\"}", 41 }, 42 } 43 default: 44 imageConfig = v1.Config{ 45 Labels: map[string]string{ 46 "io.buildpacks.buildpackage.metadata": "{\"id\": \"testbuildpack\", \"version\": \"0.0.1\"}", 47 }, 48 } 49 } 50 51 fakeImage.ConfigFileReturns(&v1.ConfigFile{ 52 Config: imageConfig, 53 }, nil) 54 55 return fakeImage, nil 56 } 57 58 utils := cnbutils.MockUtils{ 59 ExecMockRunner: &mock.ExecMockRunner{}, 60 FilesMock: &mock.FilesMock{}, 61 DownloadMock: &mock.DownloadMock{ 62 ImageContentStub: imageStub, 63 ImageInfoStub: func(imageRef string) (v1.Image, error) { 64 return imageStub(imageRef, "") 65 }, 66 }, 67 } 68 69 utils.AddFile("/cnb/order.toml", []byte(`[[order]] 70 [[order.group]] 71 id = "buildpacks/java" 72 version = "1.8.0" 73 [[order]] 74 [[order.group]] 75 id = "buildpacks/nodejs" 76 version = "1.6.0"`)) 77 utils.AddFile("/layers/report.toml", []byte(`[build] 78 [image] 79 tags = ["localhost:5000/not-found:0.0.1"] 80 digest = "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec" 81 manifest-size = 2388`)) 82 return utils 83 } 84 85 func addBuilderFiles(utils *cnbutils.MockUtils) { 86 utils.FilesMock.AddFile(creatorPath, []byte(`xyz`)) 87 } 88 89 func assertLifecycleCalls(t *testing.T, runner *mock.ExecMockRunner, callNo int) { 90 require.GreaterOrEqual(t, len(runner.Calls), callNo) 91 assert.Equal(t, creatorPath, runner.Calls[callNo-1].Exec) 92 for _, arg := range []string{"-no-color", "-buildpacks", "/cnb/buildpacks", "-order", "/cnb/order.toml", "-platform", "/tmp/platform"} { 93 assert.Contains(t, runner.Calls[callNo-1].Params, arg) 94 } 95 } 96 97 func assetBuildEnv(t *testing.T, utils cnbutils.MockUtils, key, value string) bool { 98 env, err := utils.FilesMock.ReadFile(filepath.Join("/tmp/platform/env/", key)) 99 if !assert.NoError(t, err) { 100 return false 101 } 102 return assert.Equal(t, value, string(env)) 103 } 104 105 func TestRunCnbBuild(t *testing.T) { 106 configOptions.OpenFile = piperconf.OpenPiperFile 107 108 t.Setenv("CNB_USER_ID", "1000") 109 t.Setenv("CNB_GROUP_ID", "1000") 110 111 t.Run("prefers direct configuration", func(t *testing.T) { 112 t.Parallel() 113 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 114 config := cnbBuildOptions{ 115 ContainerImageName: "my-image", 116 ContainerImageTag: "0.0.1", 117 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 118 DockerConfigJSON: "/path/to/config.json", 119 RunImage: "my-run-image", 120 DefaultProcess: "my-process", 121 } 122 123 projectToml := `[project] 124 id = "io.buildpacks.my-app" 125 ` 126 127 utils := newCnbBuildTestsUtils() 128 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 129 utils.FilesMock.AddFile("project.toml", []byte(projectToml)) 130 addBuilderFiles(&utils) 131 132 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 133 134 require.NoError(t, err) 135 runner := utils.ExecMockRunner 136 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 137 assertLifecycleCalls(t, runner, 2) 138 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 139 assert.Contains(t, runner.Calls[1].Params, "-run-image") 140 assert.Contains(t, runner.Calls[1].Params, "my-run-image") 141 assert.Contains(t, runner.Calls[1].Params, "-process-type") 142 assert.Contains(t, runner.Calls[1].Params, "my-process") 143 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 144 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 145 assert.Equal(t, `{"cnbBuild":[{"dockerImage":"paketobuildpacks/builder-jammy-base:latest"}]}`, commonPipelineEnvironment.custom.buildSettingsInfo) 146 }) 147 148 t.Run("prefers project descriptor", func(t *testing.T) { 149 t.Parallel() 150 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 151 config := cnbBuildOptions{ 152 ContainerImageTag: "0.0.1", 153 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 154 DockerConfigJSON: "/path/to/config.json", 155 ProjectDescriptor: "project.toml", 156 } 157 158 projectToml := `[project] 159 id = "io.buildpacks.my-app" 160 ` 161 162 utils := newCnbBuildTestsUtils() 163 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 164 utils.FilesMock.AddFile("project.toml", []byte(projectToml)) 165 addBuilderFiles(&utils) 166 167 telemetryData := &telemetry.CustomData{} 168 err := callCnbBuild(&config, telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 169 170 require.NoError(t, err) 171 runner := utils.ExecMockRunner 172 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 173 assertLifecycleCalls(t, runner, 2) 174 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, "io-buildpacks-my-app", config.ContainerImageTag)) 175 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 176 assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag) 177 178 assert.Equal(t, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec", commonPipelineEnvironment.container.imageDigest) 179 assert.Contains(t, commonPipelineEnvironment.container.imageDigests, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec") 180 }) 181 182 t.Run("success case (registry with https)", func(t *testing.T) { 183 t.Parallel() 184 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 185 config := cnbBuildOptions{ 186 ContainerImageName: "my-image", 187 ContainerImageTag: "0.0.1", 188 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 189 DockerConfigJSON: "/path/to/config.json", 190 } 191 192 utils := newCnbBuildTestsUtils() 193 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 194 addBuilderFiles(&utils) 195 196 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 197 198 require.NoError(t, err) 199 runner := utils.ExecMockRunner 200 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 201 assertLifecycleCalls(t, runner, 2) 202 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 203 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 204 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 205 }) 206 207 t.Run("success case (registry without https)", func(t *testing.T) { 208 t.Parallel() 209 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 210 config := cnbBuildOptions{ 211 ContainerImageName: "my-image", 212 ContainerImageTag: "0.0.1", 213 ContainerRegistryURL: imageRegistry, 214 DockerConfigJSON: "/path/to/config.json", 215 } 216 217 utils := newCnbBuildTestsUtils() 218 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 219 addBuilderFiles(&utils) 220 221 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 222 223 require.NoError(t, err) 224 runner := utils.ExecMockRunner 225 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 226 assertLifecycleCalls(t, runner, 2) 227 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 228 assert.Equal(t, fmt.Sprintf("https://%s", config.ContainerRegistryURL), commonPipelineEnvironment.container.registryURL) 229 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 230 }) 231 232 t.Run("success case (custom buildpacks and custom env variables with expand, renaming docker conf file, additional tag)", func(t *testing.T) { 233 t.Setenv("BAR", "BAZZ") 234 config := cnbBuildOptions{ 235 ContainerImageName: "my-image", 236 ContainerImageTag: "0.0.1", 237 ContainerRegistryURL: imageRegistry, 238 DockerConfigJSON: "/path/to/test.json", 239 Buildpacks: []string{"test"}, 240 ExpandBuildEnvVars: true, 241 BuildEnvVars: map[string]interface{}{ 242 "FOO": "${BAR}", 243 }, 244 AdditionalTags: []string{"latest"}, 245 } 246 247 utils := newCnbBuildTestsUtils() 248 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 249 addBuilderFiles(&utils) 250 251 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 252 253 require.NoError(t, err) 254 runner := utils.ExecMockRunner 255 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 256 assert.Equal(t, creatorPath, runner.Calls[1].Exec) 257 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks") 258 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks/order.toml") 259 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 260 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) 261 262 copiedFileExists, _ := utils.FileExists("/tmp/config.json") 263 assert.True(t, copiedFileExists) 264 265 assetBuildEnv(t, utils, "FOO", "BAZZ") 266 }) 267 268 t.Run("success case (custom buildpacks, pre and post buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { 269 t.Parallel() 270 config := cnbBuildOptions{ 271 ContainerImageName: "my-image", 272 ContainerImageTag: "0.0.1", 273 ContainerRegistryURL: imageRegistry, 274 DockerConfigJSON: "/path/to/test.json", 275 PreBuildpacks: []string{"pre-test"}, 276 PostBuildpacks: []string{"post-test"}, 277 Buildpacks: []string{"test"}, 278 ExpandBuildEnvVars: false, 279 BuildEnvVars: map[string]interface{}{ 280 "FOO": "${BAR}", 281 }, 282 AdditionalTags: []string{"latest"}, 283 } 284 285 utils := newCnbBuildTestsUtils() 286 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 287 addBuilderFiles(&utils) 288 289 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 290 291 require.NoError(t, err) 292 runner := utils.ExecMockRunner 293 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 294 assert.Equal(t, creatorPath, runner.Calls[1].Exec) 295 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks") 296 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks/order.toml") 297 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 298 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) 299 300 copiedFileExists, _ := utils.FileExists("/tmp/config.json") 301 assert.True(t, copiedFileExists) 302 303 assetBuildEnv(t, utils, "FOO", "${BAR}") 304 }) 305 306 t.Run("success case (custom pre and post buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { 307 t.Parallel() 308 config := cnbBuildOptions{ 309 ContainerImageName: "my-image", 310 ContainerImageTag: "0.0.1", 311 ContainerRegistryURL: imageRegistry, 312 DockerConfigJSON: "/path/to/test.json", 313 PostBuildpacks: []string{"post-test"}, 314 PreBuildpacks: []string{"pre-test"}, 315 BuildEnvVars: map[string]interface{}{ 316 "FOO": "BAR", 317 }, 318 AdditionalTags: []string{"latest"}, 319 } 320 321 utils := newCnbBuildTestsUtils() 322 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 323 addBuilderFiles(&utils) 324 325 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 326 327 require.NoError(t, err) 328 runner := utils.ExecMockRunner 329 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 330 assert.Equal(t, creatorPath, runner.Calls[1].Exec) 331 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks") 332 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks/order.toml") 333 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 334 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) 335 336 copiedFileExists, _ := utils.FileExists("/tmp/config.json") 337 assert.True(t, copiedFileExists) 338 }) 339 340 t.Run("success case (customTlsCertificates)", func(t *testing.T) { 341 t.Parallel() 342 httpmock.Activate() 343 defer httpmock.DeactivateAndReset() 344 httpmock.RegisterResponder(http.MethodGet, "https://test-cert.com/cert.crt", httpmock.NewStringResponder(200, "testCert")) 345 client := &piperhttp.Client{} 346 client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true}) 347 348 caCertsFile := "/etc/ssl/certs/ca-certificates.crt" 349 caCertsTmpFile := "/tmp/ca-certificates.crt" 350 registry := "some-registry" 351 config := cnbBuildOptions{ 352 ContainerImageName: "my-image", 353 ContainerImageTag: "0.0.1", 354 ContainerRegistryURL: registry, 355 DockerConfigJSON: "/path/to/config.json", 356 CustomTLSCertificateLinks: []string{"https://test-cert.com/cert.crt", "https://test-cert.com/cert.crt"}, 357 } 358 359 utils := newCnbBuildTestsUtils() 360 utils.FilesMock.AddFile(caCertsFile, []byte("test\n")) 361 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 362 addBuilderFiles(&utils) 363 364 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, client) 365 require.NoError(t, err) 366 367 result, err := utils.FilesMock.FileRead(caCertsTmpFile) 368 require.NoError(t, err) 369 assert.Equal(t, "test\ntestCert\ntestCert\n", string(result)) 370 371 require.NoError(t, err) 372 runner := utils.ExecMockRunner 373 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 374 assert.Contains(t, runner.Env, fmt.Sprintf("SSL_CERT_FILE=%s", caCertsTmpFile)) 375 assertLifecycleCalls(t, runner, 2) 376 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 377 }) 378 379 t.Run("success case (additionalTags)", func(t *testing.T) { 380 t.Parallel() 381 config := cnbBuildOptions{ 382 ContainerImageName: "my-image", 383 ContainerImageTag: "3.1.5", 384 ContainerRegistryURL: imageRegistry, 385 DockerConfigJSON: "/path/to/config.json", 386 AdditionalTags: []string{"3", "3.1", "3.1", "3.1.5"}, 387 } 388 389 utils := newCnbBuildTestsUtils() 390 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 391 addBuilderFiles(&utils) 392 393 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 394 require.NoError(t, err) 395 396 runner := utils.ExecMockRunner 397 assertLifecycleCalls(t, runner, 2) 398 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 399 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, config.ContainerImageName)) 400 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, config.ContainerImageName)) 401 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, config.ContainerImageName)) 402 }) 403 404 t.Run("success case: build environment variables", func(t *testing.T) { 405 t.Parallel() 406 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 407 config := cnbBuildOptions{ 408 ContainerImageTag: "0.0.1", 409 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 410 ProjectDescriptor: "project.toml", 411 BuildEnvVars: map[string]interface{}{ 412 "OPTIONS_KEY": "OPTIONS_VALUE", 413 "OVERWRITE": "this should win", 414 }, 415 } 416 417 projectToml := `[project] 418 id = "io.buildpacks.my-app" 419 420 [[build.env]] 421 name="PROJECT_DESCRIPTOR_KEY" 422 value="PROJECT_DESCRIPTOR_VALUE" 423 424 [[build.env]] 425 name="OVERWRITE" 426 value="this should be overwritten" 427 ` 428 429 utils := newCnbBuildTestsUtils() 430 utils.FilesMock.AddFile("project.toml", []byte(projectToml)) 431 addBuilderFiles(&utils) 432 433 telemetryData := telemetry.CustomData{} 434 err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 435 436 require.NoError(t, err) 437 assertLifecycleCalls(t, utils.ExecMockRunner, 2) 438 439 assetBuildEnv(t, utils, "OPTIONS_KEY", "OPTIONS_VALUE") 440 assetBuildEnv(t, utils, "PROJECT_DESCRIPTOR_KEY", "PROJECT_DESCRIPTOR_VALUE") 441 assetBuildEnv(t, utils, "OVERWRITE", "this should win") 442 }) 443 444 t.Run("pom.xml exists (symlink for the target folder)", func(t *testing.T) { 445 t.Parallel() 446 config := cnbBuildOptions{ 447 ContainerImageName: "my-image", 448 ContainerImageTag: "3.1.5", 449 ContainerRegistryURL: imageRegistry, 450 DockerConfigJSON: "/path/to/config.json", 451 } 452 453 utils := newCnbBuildTestsUtils() 454 utils.FilesMock.CurrentDir = "/jenkins" 455 utils.FilesMock.AddDir("/jenkins") 456 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 457 utils.FilesMock.AddFile("/workspace/pom.xml", []byte("test")) 458 addBuilderFiles(&utils) 459 460 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 461 require.NoError(t, err) 462 463 runner := utils.ExecMockRunner 464 assertLifecycleCalls(t, runner, 2) 465 466 assert.True(t, utils.FilesMock.HasCreatedSymlink("/jenkins/target", "/workspace/target")) 467 }) 468 469 t.Run("no pom.xml exists (no symlink for the target folder)", func(t *testing.T) { 470 t.Parallel() 471 config := cnbBuildOptions{ 472 ContainerImageName: "my-image", 473 ContainerImageTag: "3.1.5", 474 ContainerRegistryURL: imageRegistry, 475 DockerConfigJSON: "/path/to/config.json", 476 } 477 478 utils := newCnbBuildTestsUtils() 479 utils.FilesMock.CurrentDir = "/jenkins" 480 utils.FilesMock.AddDir("/jenkins") 481 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 482 addBuilderFiles(&utils) 483 484 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 485 require.NoError(t, err) 486 487 runner := utils.ExecMockRunner 488 assertLifecycleCalls(t, runner, 2) 489 490 assert.False(t, utils.FilesMock.HasCreatedSymlink("/jenkins/target", "/workspace/target")) 491 }) 492 493 t.Run("error case: Invalid DockerConfigJSON file", func(t *testing.T) { 494 t.Parallel() 495 config := cnbBuildOptions{ 496 ContainerImageTag: "0.0.1", 497 ContainerRegistryURL: imageRegistry, 498 ContainerImageName: "my-image", 499 DockerConfigJSON: "/path/to/config.json", 500 } 501 502 utils := newCnbBuildTestsUtils() 503 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":"dXNlcjpwYXNz"}}`)) 504 addBuilderFiles(&utils) 505 506 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 507 assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") 508 }) 509 510 t.Run("error case: DockerConfigJSON file not there (config.json)", func(t *testing.T) { 511 t.Parallel() 512 config := cnbBuildOptions{ 513 ContainerImageTag: "0.0.1", 514 ContainerRegistryURL: imageRegistry, 515 ContainerImageName: "my-image", 516 DockerConfigJSON: "not-there/config.json", 517 } 518 519 utils := newCnbBuildTestsUtils() 520 addBuilderFiles(&utils) 521 522 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 523 assert.EqualError(t, err, "failed to create/rename DockerConfigJSON file: cannot copy 'not-there/config.json': file does not exist") 524 }) 525 526 t.Run("error case: DockerConfigJSON file not there (not config.json)", func(t *testing.T) { 527 t.Parallel() 528 config := cnbBuildOptions{ 529 ContainerImageTag: "0.0.1", 530 ContainerRegistryURL: imageRegistry, 531 ContainerImageName: "my-image", 532 DockerConfigJSON: "not-there", 533 } 534 535 utils := newCnbBuildTestsUtils() 536 addBuilderFiles(&utils) 537 538 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 539 assert.EqualError(t, err, "failed to create/rename DockerConfigJSON file: cannot copy 'not-there': file does not exist") 540 }) 541 542 t.Run("error case: dockerImage is not a valid builder", func(t *testing.T) { 543 t.Parallel() 544 config := cnbBuildOptions{} 545 546 utils := newCnbBuildTestsUtils() 547 548 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 549 assert.EqualError(t, err, "the provided dockerImage is not a valid builder: binary '/cnb/lifecycle/creator' not found") 550 }) 551 552 t.Run("error case: builder image does not contain tls certificates", func(t *testing.T) { 553 t.Parallel() 554 config := cnbBuildOptions{ 555 ContainerImageName: "my-image", 556 ContainerImageTag: "0.0.1", 557 ContainerRegistryURL: imageRegistry, 558 DockerConfigJSON: "/path/to/config.json", 559 Buildpacks: []string{"test"}, 560 CustomTLSCertificateLinks: []string{"http://example.com/certs.pem"}, 561 } 562 563 utils := newCnbBuildTestsUtils() 564 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 565 addBuilderFiles(&utils) 566 567 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 568 assert.EqualError(t, err, "failed to copy certificates: cannot copy '/etc/ssl/certs/ca-certificates.crt': file does not exist") 569 }) 570 571 t.Run("success case (telemetry was added)", func(t *testing.T) { 572 t.Parallel() 573 registry := "some-registry" 574 config := cnbBuildOptions{ 575 ContainerImageName: "my-image", 576 ContainerImageTag: "3.1.5", 577 ContainerRegistryURL: registry, 578 MultipleImages: []map[string]interface{}{ 579 { 580 "runImage": "foo", 581 }, 582 { 583 "runImage": "bar", 584 }, 585 }, 586 } 587 588 utils := newCnbBuildTestsUtils() 589 addBuilderFiles(&utils) 590 591 telemetryData := &telemetry.CustomData{} 592 err := callCnbBuild(&config, telemetryData, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 593 require.NoError(t, err) 594 595 assert.Equal(t, "paketobuildpacks/builder-jammy-base:latest", telemetryData.CnbBuilder) 596 assert.Equal(t, "foo,bar", telemetryData.CnbRunImage) 597 }) 598 599 t.Run("error case, multiple artifacts in path", func(t *testing.T) { 600 t.Parallel() 601 config := cnbBuildOptions{ 602 ContainerImageName: "my-image", 603 ContainerImageTag: "3.1.5", 604 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 605 DockerConfigJSON: "/path/to/config.json", 606 ProjectDescriptor: "project.toml", 607 AdditionalTags: []string{"latest"}, 608 Buildpacks: []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"}, 609 Path: "target/*.jar", 610 } 611 612 utils := newCnbBuildTestsUtils() 613 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 614 utils.FilesMock.AddDir("target") 615 utils.FilesMock.AddFile("target/app.jar", []byte(`FFFFFF`)) 616 utils.FilesMock.AddFile("target/app-src.jar", []byte(`FFFFFF`)) 617 618 addBuilderFiles(&utils) 619 620 telemetryData := telemetry.CustomData{} 621 err := callCnbBuild(&config, &telemetryData, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 622 require.EqualError(t, err, "could not resolve path: Failed to resolve glob for 'target/*.jar', matching 2 file(s)") 623 }) 624 625 t.Run("success case, artifacts found by glob", func(t *testing.T) { 626 t.Parallel() 627 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 628 config := cnbBuildOptions{ 629 ContainerImageName: "my-image", 630 ContainerImageTag: "3.1.5", 631 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 632 DockerConfigJSON: "/path/to/config.json", 633 ProjectDescriptor: "project.toml", 634 AdditionalTags: []string{"latest"}, 635 Buildpacks: []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"}, 636 Path: "**/target", 637 } 638 639 utils := newCnbBuildTestsUtils() 640 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 641 utils.FilesMock.AddDir("target") 642 utils.FilesMock.AddFile("target/app.jar", []byte(`FFFFFF`)) 643 644 addBuilderFiles(&utils) 645 646 telemetryData := telemetry.CustomData{} 647 err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 648 649 require.NoError(t, err) 650 runner := utils.ExecMockRunner 651 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 652 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 653 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 654 assert.Equal(t, "my-image:3.1.5", commonPipelineEnvironment.container.imageNameTag) 655 }) 656 657 t.Run("success case (multiple images configured)", func(t *testing.T) { 658 t.Parallel() 659 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 660 config := cnbBuildOptions{ 661 ContainerImageTag: "3.1.5", 662 ContainerRegistryURL: imageRegistry, 663 DockerConfigJSON: "/path/to/my-config.json", 664 AdditionalTags: []string{"3", "3.1", "3.1", "3.1.5"}, 665 MultipleImages: []map[string]interface{}{{"ContainerImageName": "my-image-0", "ContainerImageAlias": "simple"}, {"ContainerImageName": "my-image-1"}}, 666 } 667 668 expectedImageCount := len(config.MultipleImages) 669 670 utils := newCnbBuildTestsUtils() 671 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 672 addBuilderFiles(&utils) 673 674 telemetryData := &telemetry.CustomData{} 675 err := callCnbBuild(&config, telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 676 require.NoError(t, err) 677 678 runner := utils.ExecMockRunner 679 require.Equal(t, expectedImageCount, len(runner.Calls)-1) 680 for i, call := range runner.Calls { 681 if i == 0 { // first call is -version 682 continue 683 } 684 lifecycleCall := i - 1 685 assertLifecycleCalls(t, runner, i+1) 686 containerImageName := fmt.Sprintf("my-image-%d", lifecycleCall) 687 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, containerImageName, config.ContainerImageTag)) 688 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, containerImageName)) 689 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, containerImageName)) 690 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, containerImageName)) 691 } 692 693 assert.Equal(t, "my-image-0:3.1.5", commonPipelineEnvironment.container.imageNameTag) 694 assert.Equal(t, []string{"simple", "my-image-1"}, commonPipelineEnvironment.container.imageNames) 695 }) 696 }