github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/cmd/cnbBuild_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package cmd 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net/http" 10 "path/filepath" 11 "testing" 12 13 "github.com/SAP/jenkins-library/pkg/buildpacks" 14 "github.com/SAP/jenkins-library/pkg/cnbutils" 15 piperconf "github.com/SAP/jenkins-library/pkg/config" 16 piperhttp "github.com/SAP/jenkins-library/pkg/http" 17 "github.com/SAP/jenkins-library/pkg/mock" 18 "github.com/SAP/jenkins-library/pkg/telemetry" 19 v1 "github.com/google/go-containerregistry/pkg/v1" 20 "github.com/google/go-containerregistry/pkg/v1/fake" 21 "github.com/jarcoal/httpmock" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 const imageRegistry = "some-registry" 27 28 func newCnbBuildTestsUtils() cnbutils.MockUtils { 29 imageStub := func(imageRef, target string) (v1.Image, error) { 30 fakeImage := &fake.FakeImage{} 31 var imageConfig v1.Config 32 switch imageRef { 33 case "pre-test": 34 imageConfig = v1.Config{ 35 Labels: map[string]string{ 36 "io.buildpacks.buildpackage.metadata": "{\"id\": \"pre-testbuildpack\", \"version\": \"0.0.1\"}", 37 }, 38 } 39 case "post-test": 40 imageConfig = v1.Config{ 41 Labels: map[string]string{ 42 "io.buildpacks.buildpackage.metadata": "{\"id\": \"post-testbuildpack\", \"version\": \"0.0.1\"}", 43 }, 44 } 45 default: 46 imageConfig = v1.Config{ 47 Labels: map[string]string{ 48 "io.buildpacks.buildpackage.metadata": "{\"id\": \"testbuildpack\", \"version\": \"0.0.1\"}", 49 }, 50 } 51 } 52 53 fakeImage.ConfigFileReturns(&v1.ConfigFile{ 54 Config: imageConfig, 55 }, nil) 56 57 return fakeImage, nil 58 } 59 60 utils := cnbutils.MockUtils{ 61 ExecMockRunner: &mock.ExecMockRunner{}, 62 FilesMock: &mock.FilesMock{}, 63 DownloadMock: &mock.DownloadMock{ 64 ImageContentStub: imageStub, 65 ImageInfoStub: func(imageRef string) (v1.Image, error) { 66 return imageStub(imageRef, "") 67 }, 68 }, 69 } 70 71 utils.AddFile("/cnb/order.toml", []byte(`[[order]] 72 [[order.group]] 73 id = "buildpacks/java" 74 version = "1.8.0" 75 [[order]] 76 [[order.group]] 77 id = "buildpacks/nodejs" 78 version = "1.6.0"`)) 79 utils.AddFile("/layers/report.toml", []byte(`[build] 80 [image] 81 tags = ["localhost:5000/not-found:0.0.1"] 82 digest = "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec" 83 manifest-size = 2388`)) 84 return utils 85 } 86 87 func addBuilderFiles(utils *cnbutils.MockUtils) { 88 utils.FilesMock.AddFile(creatorPath, []byte(`xyz`)) 89 } 90 91 func assertLifecycleCalls(t *testing.T, runner *mock.ExecMockRunner, callNo int) { 92 require.GreaterOrEqual(t, len(runner.Calls), callNo) 93 assert.Equal(t, creatorPath, runner.Calls[callNo-1].Exec) 94 for _, arg := range []string{"-no-color", "-buildpacks", "/cnb/buildpacks", "-order", "/cnb/order.toml", "-platform", "/tmp/platform"} { 95 assert.Contains(t, runner.Calls[callNo-1].Params, arg) 96 } 97 } 98 99 func assetBuildEnv(t *testing.T, utils cnbutils.MockUtils, key, value string) bool { 100 env, err := utils.FilesMock.ReadFile(filepath.Join("/tmp/platform/env/", key)) 101 if !assert.NoError(t, err) { 102 return false 103 } 104 return assert.Equal(t, value, string(env)) 105 } 106 107 func TestRunCnbBuild(t *testing.T) { 108 configOptions.OpenFile = piperconf.OpenPiperFile 109 110 t.Run("prefers direct configuration", func(t *testing.T) { 111 t.Parallel() 112 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 113 config := cnbBuildOptions{ 114 ContainerImageName: "my-image", 115 ContainerImageTag: "0.0.1", 116 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 117 DockerConfigJSON: "/path/to/config.json", 118 RunImage: "my-run-image", 119 DefaultProcess: "my-process", 120 } 121 122 projectToml := `[project] 123 id = "io.buildpacks.my-app" 124 ` 125 126 utils := newCnbBuildTestsUtils() 127 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 128 utils.FilesMock.AddFile("project.toml", []byte(projectToml)) 129 addBuilderFiles(&utils) 130 131 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 132 133 require.NoError(t, err) 134 runner := utils.ExecMockRunner 135 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 136 assertLifecycleCalls(t, runner, 2) 137 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 138 assert.Contains(t, runner.Calls[1].Params, "-run-image") 139 assert.Contains(t, runner.Calls[1].Params, "my-run-image") 140 assert.Contains(t, runner.Calls[1].Params, "-process-type") 141 assert.Contains(t, runner.Calls[1].Params, "my-process") 142 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 143 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 144 assert.Equal(t, `{"cnbBuild":[{"dockerImage":"paketobuildpacks/builder:base"}]}`, commonPipelineEnvironment.custom.buildSettingsInfo) 145 }) 146 147 t.Run("prefers project descriptor", func(t *testing.T) { 148 t.Parallel() 149 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 150 config := cnbBuildOptions{ 151 ContainerImageTag: "0.0.1", 152 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 153 DockerConfigJSON: "/path/to/config.json", 154 ProjectDescriptor: "project.toml", 155 } 156 157 projectToml := `[project] 158 id = "io.buildpacks.my-app" 159 ` 160 161 utils := newCnbBuildTestsUtils() 162 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 163 utils.FilesMock.AddFile("project.toml", []byte(projectToml)) 164 addBuilderFiles(&utils) 165 166 telemetryData := &telemetry.CustomData{} 167 err := callCnbBuild(&config, telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 168 169 require.NoError(t, err) 170 runner := utils.ExecMockRunner 171 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 172 assertLifecycleCalls(t, runner, 2) 173 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, "io-buildpacks-my-app", config.ContainerImageTag)) 174 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 175 assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag) 176 177 assert.Equal(t, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec", commonPipelineEnvironment.container.imageDigest) 178 assert.Contains(t, commonPipelineEnvironment.container.imageDigests, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec") 179 180 customDataAsString := telemetryData.Custom1 181 customData := &buildpacks.BuildpacksTelemetry{} 182 err = json.Unmarshal([]byte(customDataAsString), customData) 183 require.NoError(t, err) 184 assert.Equal(t, 1, len(customData.Data)) 185 assert.Equal(t, "root", string(customData.Data[0].Path)) 186 }) 187 188 t.Run("success case (registry with https)", func(t *testing.T) { 189 t.Parallel() 190 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 191 config := cnbBuildOptions{ 192 ContainerImageName: "my-image", 193 ContainerImageTag: "0.0.1", 194 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 195 DockerConfigJSON: "/path/to/config.json", 196 } 197 198 utils := newCnbBuildTestsUtils() 199 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 200 addBuilderFiles(&utils) 201 202 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 203 204 require.NoError(t, err) 205 runner := utils.ExecMockRunner 206 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 207 assertLifecycleCalls(t, runner, 2) 208 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 209 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 210 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 211 }) 212 213 t.Run("success case (registry without https)", func(t *testing.T) { 214 t.Parallel() 215 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 216 config := cnbBuildOptions{ 217 ContainerImageName: "my-image", 218 ContainerImageTag: "0.0.1", 219 ContainerRegistryURL: imageRegistry, 220 DockerConfigJSON: "/path/to/config.json", 221 } 222 223 utils := newCnbBuildTestsUtils() 224 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 225 addBuilderFiles(&utils) 226 227 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 228 229 require.NoError(t, err) 230 runner := utils.ExecMockRunner 231 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 232 assertLifecycleCalls(t, runner, 2) 233 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 234 assert.Equal(t, fmt.Sprintf("https://%s", config.ContainerRegistryURL), commonPipelineEnvironment.container.registryURL) 235 assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) 236 }) 237 238 t.Run("success case (custom buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { 239 t.Parallel() 240 config := cnbBuildOptions{ 241 ContainerImageName: "my-image", 242 ContainerImageTag: "0.0.1", 243 ContainerRegistryURL: imageRegistry, 244 DockerConfigJSON: "/path/to/test.json", 245 Buildpacks: []string{"test"}, 246 BuildEnvVars: map[string]interface{}{ 247 "FOO": "BAR", 248 }, 249 AdditionalTags: []string{"latest"}, 250 } 251 252 utils := newCnbBuildTestsUtils() 253 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 254 addBuilderFiles(&utils) 255 256 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 257 258 require.NoError(t, err) 259 runner := utils.ExecMockRunner 260 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 261 assert.Equal(t, creatorPath, runner.Calls[1].Exec) 262 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks") 263 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks/order.toml") 264 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 265 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) 266 267 copiedFileExists, _ := utils.FileExists("/tmp/config.json") 268 assert.True(t, copiedFileExists) 269 }) 270 271 t.Run("success case (custom buildpacks, pre and post buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { 272 t.Parallel() 273 config := cnbBuildOptions{ 274 ContainerImageName: "my-image", 275 ContainerImageTag: "0.0.1", 276 ContainerRegistryURL: imageRegistry, 277 DockerConfigJSON: "/path/to/test.json", 278 PreBuildpacks: []string{"pre-test"}, 279 PostBuildpacks: []string{"post-test"}, 280 Buildpacks: []string{"test"}, 281 BuildEnvVars: map[string]interface{}{ 282 "FOO": "BAR", 283 }, 284 AdditionalTags: []string{"latest"}, 285 } 286 287 utils := newCnbBuildTestsUtils() 288 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 289 addBuilderFiles(&utils) 290 291 err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 292 293 require.NoError(t, err) 294 runner := utils.ExecMockRunner 295 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 296 assert.Equal(t, creatorPath, runner.Calls[1].Exec) 297 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks") 298 assert.Contains(t, runner.Calls[1].Params, "/tmp/buildpacks/order.toml") 299 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) 300 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) 301 302 copiedFileExists, _ := utils.FileExists("/tmp/config.json") 303 assert.True(t, copiedFileExists) 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 DockerConfigJSON: "/path/to/config.json", 579 ProjectDescriptor: "project.toml", 580 AdditionalTags: []string{"latest"}, 581 Buildpacks: []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"}, 582 Bindings: map[string]interface{}{"SECRET": map[string]string{"key": "KEY", "file": "a_file"}}, 583 Path: "target", 584 } 585 586 utils := newCnbBuildTestsUtils() 587 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 588 utils.FilesMock.AddDir("target") 589 utils.FilesMock.AddFile("target/project.toml", []byte(`[project] 590 id = "test" 591 name = "test" 592 version = "1.0.0" 593 594 [build] 595 include = [] 596 exclude = ["*.tar"] 597 598 [[build.buildpacks]] 599 uri = "some-buildpack"`)) 600 utils.FilesMock.AddFile("a_file", []byte(`{}`)) 601 utils.FilesMock.AddFile("target/somelib.jar", []byte(`FFFFFF`)) 602 603 addBuilderFiles(&utils) 604 605 telemetryData := &telemetry.CustomData{} 606 err := callCnbBuild(&config, telemetryData, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 607 require.NoError(t, err) 608 609 customDataAsString := telemetryData.Custom1 610 customData := &buildpacks.BuildpacksTelemetry{} 611 err = json.Unmarshal([]byte(customDataAsString), customData) 612 613 require.NoError(t, err) 614 assert.Equal(t, 3, customData.Version) 615 require.Equal(t, 1, len(customData.Data)) 616 assert.Equal(t, "3.1.5", customData.Data[0].ImageTag) 617 assert.Equal(t, "folder", string(customData.Data[0].Path)) 618 assert.Contains(t, customData.Data[0].AdditionalTags, "latest") 619 assert.Contains(t, customData.Data[0].BindingKeys, "SECRET") 620 assert.Equal(t, "paketobuildpacks/builder:base", customData.Data[0].Builder) 621 622 assert.Contains(t, customData.Data[0].Buildpacks.FromConfig, "paketobuildpacks/java") 623 assert.NotContains(t, customData.Data[0].Buildpacks.FromProjectDescriptor, "paketobuildpacks/java") 624 assert.Contains(t, customData.Data[0].Buildpacks.FromProjectDescriptor, "bcc73ab1f0a0d3fb0d1bf2b6df5510a25ccd14a761dbc0f5044ea24ead30452b") 625 assert.Contains(t, customData.Data[0].Buildpacks.Overall, "paketobuildpacks/java") 626 627 assert.True(t, customData.Data[0].ProjectDescriptor.Used) 628 assert.False(t, customData.Data[0].ProjectDescriptor.IncludeUsed) 629 assert.True(t, customData.Data[0].ProjectDescriptor.ExcludeUsed) 630 }) 631 632 t.Run("error case, multiple artifacts in path", func(t *testing.T) { 633 t.Parallel() 634 config := cnbBuildOptions{ 635 ContainerImageName: "my-image", 636 ContainerImageTag: "3.1.5", 637 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 638 DockerConfigJSON: "/path/to/config.json", 639 ProjectDescriptor: "project.toml", 640 AdditionalTags: []string{"latest"}, 641 Buildpacks: []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"}, 642 Path: "target/*.jar", 643 } 644 645 utils := newCnbBuildTestsUtils() 646 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 647 utils.FilesMock.AddDir("target") 648 utils.FilesMock.AddFile("target/app.jar", []byte(`FFFFFF`)) 649 utils.FilesMock.AddFile("target/app-src.jar", []byte(`FFFFFF`)) 650 651 addBuilderFiles(&utils) 652 653 telemetryData := telemetry.CustomData{} 654 err := callCnbBuild(&config, &telemetryData, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 655 require.EqualError(t, err, "could not resolve path: Failed to resolve glob for 'target/*.jar', matching 2 file(s)") 656 }) 657 658 t.Run("success case, artifacts found by glob", func(t *testing.T) { 659 t.Parallel() 660 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 661 config := cnbBuildOptions{ 662 ContainerImageName: "my-image", 663 ContainerImageTag: "3.1.5", 664 ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), 665 DockerConfigJSON: "/path/to/config.json", 666 ProjectDescriptor: "project.toml", 667 AdditionalTags: []string{"latest"}, 668 Buildpacks: []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"}, 669 Path: "**/target", 670 } 671 672 utils := newCnbBuildTestsUtils() 673 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 674 utils.FilesMock.AddDir("target") 675 utils.FilesMock.AddFile("target/app.jar", []byte(`FFFFFF`)) 676 677 addBuilderFiles(&utils) 678 679 telemetryData := telemetry.CustomData{} 680 err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 681 682 require.NoError(t, err) 683 runner := utils.ExecMockRunner 684 assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") 685 assert.Contains(t, runner.Calls[1].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) 686 assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) 687 assert.Equal(t, "my-image:3.1.5", commonPipelineEnvironment.container.imageNameTag) 688 }) 689 690 t.Run("success case (build env telemetry was added)", func(t *testing.T) { 691 t.Parallel() 692 registry := "some-registry" 693 config := cnbBuildOptions{ 694 ContainerImageName: "my-image", 695 ContainerImageTag: "3.1.5", 696 ContainerRegistryURL: registry, 697 ProjectDescriptor: "project.toml", 698 BuildEnvVars: map[string]interface{}{"CONFIG_KEY": "var", "BP_JVM_VERSION": "8"}, 699 } 700 701 utils := newCnbBuildTestsUtils() 702 utils.FilesMock.AddFile("project.toml", []byte(`[project] 703 id = "test" 704 705 [build] 706 include = [] 707 708 [[build.env]] 709 name='PROJECT_KEY' 710 value='var' 711 712 [[build.env]] 713 name='BP_NODE_VERSION' 714 value='11' 715 716 [[build.buildpacks]] 717 uri = "some-buildpack" 718 `)) 719 720 addBuilderFiles(&utils) 721 722 telemetryData := &telemetry.CustomData{} 723 err := callCnbBuild(&config, telemetryData, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) 724 require.NoError(t, err) 725 726 customDataAsString := telemetryData.Custom1 727 customData := &buildpacks.BuildpacksTelemetry{} 728 err = json.Unmarshal([]byte(customDataAsString), customData) 729 730 require.NoError(t, err) 731 require.Equal(t, 1, len(customData.Data)) 732 assert.Contains(t, customData.Data[0].BuildEnv.KeysFromConfig, "CONFIG_KEY") 733 assert.NotContains(t, customData.Data[0].BuildEnv.KeysFromProjectDescriptor, "CONFIG_KEY") 734 assert.Contains(t, customData.Data[0].BuildEnv.KeysOverall, "CONFIG_KEY") 735 736 assert.NotContains(t, customData.Data[0].BuildEnv.KeysFromConfig, "PROJECT_KEY") 737 assert.Contains(t, customData.Data[0].BuildEnv.KeysFromProjectDescriptor, "PROJECT_KEY") 738 assert.Contains(t, customData.Data[0].BuildEnv.KeysOverall, "PROJECT_KEY") 739 740 assert.Equal(t, "8", customData.Data[0].BuildEnv.KeyValues["BP_JVM_VERSION"]) 741 assert.Equal(t, "11", customData.Data[0].BuildEnv.KeyValues["BP_NODE_VERSION"]) 742 assert.NotContains(t, customData.Data[0].BuildEnv.KeyValues, "PROJECT_KEY") 743 744 assert.Contains(t, customData.Data[0].Buildpacks.Overall, "bcc73ab1f0a0d3fb0d1bf2b6df5510a25ccd14a761dbc0f5044ea24ead30452b") 745 }) 746 747 t.Run("success case (multiple images configured)", func(t *testing.T) { 748 t.Parallel() 749 commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} 750 config := cnbBuildOptions{ 751 ContainerImageTag: "3.1.5", 752 ContainerRegistryURL: imageRegistry, 753 DockerConfigJSON: "/path/to/my-config.json", 754 AdditionalTags: []string{"3", "3.1", "3.1", "3.1.5"}, 755 MultipleImages: []map[string]interface{}{{"ContainerImageName": "my-image-0", "ContainerImageAlias": "simple"}, {"ContainerImageName": "my-image-1"}}, 756 } 757 758 expectedImageCount := len(config.MultipleImages) 759 760 utils := newCnbBuildTestsUtils() 761 utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) 762 addBuilderFiles(&utils) 763 764 telemetryData := &telemetry.CustomData{} 765 err := callCnbBuild(&config, telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) 766 require.NoError(t, err) 767 768 customDataAsString := telemetryData.Custom1 769 customData := &buildpacks.BuildpacksTelemetry{} 770 err = json.Unmarshal([]byte(customDataAsString), customData) 771 assert.NoError(t, err) 772 require.Equal(t, expectedImageCount, len(customData.Data)) 773 774 runner := utils.ExecMockRunner 775 require.Equal(t, expectedImageCount, len(runner.Calls)-1) 776 for i, call := range runner.Calls { 777 if i == 0 { // first call is -version 778 continue 779 } 780 lifecycleCall := i - 1 781 assert.Equal(t, 4, len(customData.Data[lifecycleCall].AdditionalTags)) 782 assertLifecycleCalls(t, runner, i+1) 783 containerImageName := fmt.Sprintf("my-image-%d", lifecycleCall) 784 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, containerImageName, config.ContainerImageTag)) 785 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, containerImageName)) 786 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, containerImageName)) 787 assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, containerImageName)) 788 } 789 790 assert.Equal(t, "my-image-0:3.1.5", commonPipelineEnvironment.container.imageNameTag) 791 assert.Equal(t, []string{"simple", "my-image-1"}, commonPipelineEnvironment.container.imageNames) 792 }) 793 }