github.com/xgoffin/jenkins-library@v1.154.0/cmd/cnbBuild_test.go (about)

     1  package cmd
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"testing"
     8  
     9  	"github.com/SAP/jenkins-library/pkg/cnbutils"
    10  	piperconf "github.com/SAP/jenkins-library/pkg/config"
    11  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    12  	"github.com/SAP/jenkins-library/pkg/mock"
    13  	"github.com/SAP/jenkins-library/pkg/telemetry"
    14  	"github.com/jarcoal/httpmock"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/require"
    17  )
    18  
    19  const imageRegistry = "some-registry"
    20  
    21  func newCnbBuildTestsUtils() cnbutils.MockUtils {
    22  	utils := cnbutils.MockUtils{
    23  		ExecMockRunner: &mock.ExecMockRunner{},
    24  		FilesMock:      &mock.FilesMock{},
    25  	}
    26  	utils.AddFile("/layers/report.toml", []byte(`[build]
    27  [image]
    28  tags = ["localhost:5000/not-found:0.0.1"]
    29  digest = "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec"
    30  manifest-size = 2388`))
    31  	return utils
    32  }
    33  
    34  func addBuilderFiles(utils *cnbutils.MockUtils) {
    35  	utils.FilesMock.AddFile(creatorPath, []byte(`xyz`))
    36  }
    37  
    38  func assertLifecycleCalls(t *testing.T, runner *mock.ExecMockRunner, callNo int) {
    39  	require.GreaterOrEqual(t, len(runner.Calls), callNo)
    40  	assert.Equal(t, creatorPath, runner.Calls[callNo-1].Exec)
    41  	for _, arg := range []string{"-no-color", "-buildpacks", "/cnb/buildpacks", "-order", "/cnb/order.toml", "-platform", "/tmp/platform"} {
    42  		assert.Contains(t, runner.Calls[callNo-1].Params, arg)
    43  	}
    44  }
    45  
    46  func TestRunCnbBuild(t *testing.T) {
    47  	configOptions.openFile = piperconf.OpenPiperFile
    48  
    49  	t.Run("prefers direct configuration", func(t *testing.T) {
    50  		t.Parallel()
    51  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
    52  		config := cnbBuildOptions{
    53  			ContainerImageName:   "my-image",
    54  			ContainerImageTag:    "0.0.1",
    55  			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
    56  			DockerConfigJSON:     "/path/to/config.json",
    57  		}
    58  
    59  		projectToml := `[project]
    60  		id = "io.buildpacks.my-app"
    61  		`
    62  
    63  		utils := newCnbBuildTestsUtils()
    64  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
    65  		utils.FilesMock.AddFile("project.toml", []byte(projectToml))
    66  		addBuilderFiles(&utils)
    67  
    68  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
    69  
    70  		require.NoError(t, err)
    71  		runner := utils.ExecMockRunner
    72  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
    73  		assertLifecycleCalls(t, runner, 1)
    74  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag))
    75  		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
    76  		assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
    77  	})
    78  
    79  	t.Run("prefers project descriptor", func(t *testing.T) {
    80  		t.Parallel()
    81  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
    82  		config := cnbBuildOptions{
    83  			ContainerImageTag:    "0.0.1",
    84  			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
    85  			DockerConfigJSON:     "/path/to/config.json",
    86  			ProjectDescriptor:    "project.toml",
    87  		}
    88  
    89  		projectToml := `[project]
    90  		id = "io.buildpacks.my-app"
    91  		`
    92  
    93  		utils := newCnbBuildTestsUtils()
    94  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
    95  		utils.FilesMock.AddFile("project.toml", []byte(projectToml))
    96  		addBuilderFiles(&utils)
    97  
    98  		telemetryData := telemetry.CustomData{}
    99  		err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   100  
   101  		require.NoError(t, err)
   102  		runner := utils.ExecMockRunner
   103  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
   104  		assertLifecycleCalls(t, runner, 1)
   105  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, "io-buildpacks-my-app", config.ContainerImageTag))
   106  		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
   107  		assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag)
   108  
   109  		assert.Equal(t, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec", commonPipelineEnvironment.container.imageDigest)
   110  		assert.Contains(t, commonPipelineEnvironment.container.imageDigests, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec")
   111  
   112  		customDataAsString := telemetryData.Custom1
   113  		customData := cnbBuildTelemetry{}
   114  		err = json.Unmarshal([]byte(customDataAsString), &customData)
   115  		require.NoError(t, err)
   116  		assert.Equal(t, 1, len(customData.Data))
   117  		assert.Equal(t, "root", string(customData.Data[0].Path))
   118  	})
   119  
   120  	t.Run("success case (registry with https)", func(t *testing.T) {
   121  		t.Parallel()
   122  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   123  		config := cnbBuildOptions{
   124  			ContainerImageName:   "my-image",
   125  			ContainerImageTag:    "0.0.1",
   126  			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry),
   127  			DockerConfigJSON:     "/path/to/config.json",
   128  		}
   129  
   130  		utils := newCnbBuildTestsUtils()
   131  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   132  		addBuilderFiles(&utils)
   133  
   134  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   135  
   136  		require.NoError(t, err)
   137  		runner := utils.ExecMockRunner
   138  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
   139  		assertLifecycleCalls(t, runner, 1)
   140  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag))
   141  		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL)
   142  		assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
   143  	})
   144  
   145  	t.Run("success case (registry without https)", func(t *testing.T) {
   146  		t.Parallel()
   147  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   148  		config := cnbBuildOptions{
   149  			ContainerImageName:   "my-image",
   150  			ContainerImageTag:    "0.0.1",
   151  			ContainerRegistryURL: imageRegistry,
   152  			DockerConfigJSON:     "/path/to/config.json",
   153  		}
   154  
   155  		utils := newCnbBuildTestsUtils()
   156  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   157  		addBuilderFiles(&utils)
   158  
   159  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   160  
   161  		require.NoError(t, err)
   162  		runner := utils.ExecMockRunner
   163  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
   164  		assertLifecycleCalls(t, runner, 1)
   165  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
   166  		assert.Equal(t, fmt.Sprintf("https://%s", config.ContainerRegistryURL), commonPipelineEnvironment.container.registryURL)
   167  		assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag)
   168  	})
   169  
   170  	t.Run("success case (custom buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) {
   171  		t.Parallel()
   172  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   173  		config := cnbBuildOptions{
   174  			ContainerImageName:   "my-image",
   175  			ContainerImageTag:    "0.0.1",
   176  			ContainerRegistryURL: imageRegistry,
   177  			DockerConfigJSON:     "/path/to/test.json",
   178  			Buildpacks:           []string{"test"},
   179  			BuildEnvVars: map[string]interface{}{
   180  				"FOO": "BAR",
   181  			},
   182  			AdditionalTags: []string{"latest"},
   183  		}
   184  
   185  		utils := newCnbBuildTestsUtils()
   186  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   187  		addBuilderFiles(&utils)
   188  
   189  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   190  
   191  		require.NoError(t, err)
   192  		runner := utils.ExecMockRunner
   193  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
   194  		assert.Equal(t, creatorPath, runner.Calls[0].Exec)
   195  		assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks")
   196  		assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks/order.toml")
   197  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
   198  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName))
   199  
   200  		initialFileExists, _ := utils.FileExists("/path/to/test.json")
   201  		renamedFileExists, _ := utils.FileExists("/path/to/config.json")
   202  
   203  		assert.False(t, initialFileExists)
   204  		assert.True(t, renamedFileExists)
   205  	})
   206  
   207  	t.Run("success case (customTlsCertificates)", func(t *testing.T) {
   208  		t.Parallel()
   209  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   210  		httpmock.Activate()
   211  		defer httpmock.DeactivateAndReset()
   212  		httpmock.RegisterResponder(http.MethodGet, "https://test-cert.com/cert.crt", httpmock.NewStringResponder(200, "testCert"))
   213  		client := &piperhttp.Client{}
   214  		client.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
   215  
   216  		caCertsFile := "/etc/ssl/certs/ca-certificates.crt"
   217  		caCertsTmpFile := "/tmp/ca-certificates.crt"
   218  		registry := "some-registry"
   219  		config := cnbBuildOptions{
   220  			ContainerImageName:        "my-image",
   221  			ContainerImageTag:         "0.0.1",
   222  			ContainerRegistryURL:      registry,
   223  			DockerConfigJSON:          "/path/to/config.json",
   224  			CustomTLSCertificateLinks: []string{"https://test-cert.com/cert.crt", "https://test-cert.com/cert.crt"},
   225  		}
   226  
   227  		utils := newCnbBuildTestsUtils()
   228  		utils.FilesMock.AddFile(caCertsFile, []byte("test\n"))
   229  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   230  		addBuilderFiles(&utils)
   231  
   232  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, client)
   233  		require.NoError(t, err)
   234  
   235  		result, err := utils.FilesMock.FileRead(caCertsTmpFile)
   236  		require.NoError(t, err)
   237  		assert.Equal(t, "test\ntestCert\ntestCert\n", string(result))
   238  
   239  		require.NoError(t, err)
   240  		runner := utils.ExecMockRunner
   241  		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}")
   242  		assert.Contains(t, runner.Env, fmt.Sprintf("SSL_CERT_FILE=%s", caCertsTmpFile))
   243  		assertLifecycleCalls(t, runner, 1)
   244  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
   245  	})
   246  
   247  	t.Run("success case (additionalTags)", func(t *testing.T) {
   248  		t.Parallel()
   249  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   250  		config := cnbBuildOptions{
   251  			ContainerImageName:   "my-image",
   252  			ContainerImageTag:    "3.1.5",
   253  			ContainerRegistryURL: imageRegistry,
   254  			DockerConfigJSON:     "/path/to/config.json",
   255  			AdditionalTags:       []string{"3", "3.1", "3.1", "3.1.5"},
   256  		}
   257  
   258  		utils := newCnbBuildTestsUtils()
   259  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   260  		addBuilderFiles(&utils)
   261  
   262  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   263  		require.NoError(t, err)
   264  
   265  		runner := utils.ExecMockRunner
   266  		assertLifecycleCalls(t, runner, 1)
   267  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag))
   268  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, config.ContainerImageName))
   269  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, config.ContainerImageName))
   270  		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, config.ContainerImageName))
   271  	})
   272  
   273  	t.Run("pom.xml exists (symlink for the target folder)", func(t *testing.T) {
   274  		t.Parallel()
   275  		config := cnbBuildOptions{
   276  			ContainerImageName:   "my-image",
   277  			ContainerImageTag:    "3.1.5",
   278  			ContainerRegistryURL: imageRegistry,
   279  			DockerConfigJSON:     "/path/to/config.json",
   280  		}
   281  
   282  		utils := newCnbBuildTestsUtils()
   283  		utils.FilesMock.CurrentDir = "/jenkins"
   284  		utils.FilesMock.AddDir("/jenkins")
   285  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   286  		utils.FilesMock.AddFile("/workspace/pom.xml", []byte("test"))
   287  		addBuilderFiles(&utils)
   288  
   289  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{})
   290  		require.NoError(t, err)
   291  
   292  		runner := utils.ExecMockRunner
   293  		assertLifecycleCalls(t, runner, 1)
   294  
   295  		assert.True(t, utils.FilesMock.HasCreatedSymlink("/jenkins/target", "/workspace/target"))
   296  	})
   297  
   298  	t.Run("no pom.xml exists (no symlink for the target folder)", func(t *testing.T) {
   299  		t.Parallel()
   300  		config := cnbBuildOptions{
   301  			ContainerImageName:   "my-image",
   302  			ContainerImageTag:    "3.1.5",
   303  			ContainerRegistryURL: imageRegistry,
   304  			DockerConfigJSON:     "/path/to/config.json",
   305  		}
   306  
   307  		utils := newCnbBuildTestsUtils()
   308  		utils.FilesMock.CurrentDir = "/jenkins"
   309  		utils.FilesMock.AddDir("/jenkins")
   310  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   311  		addBuilderFiles(&utils)
   312  
   313  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{})
   314  		require.NoError(t, err)
   315  
   316  		runner := utils.ExecMockRunner
   317  		assertLifecycleCalls(t, runner, 1)
   318  
   319  		assert.False(t, utils.FilesMock.HasCreatedSymlink("/jenkins/target", "/workspace/target"))
   320  	})
   321  
   322  	t.Run("error case: Invalid DockerConfigJSON file", func(t *testing.T) {
   323  		t.Parallel()
   324  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   325  		config := cnbBuildOptions{
   326  			ContainerImageTag:    "0.0.1",
   327  			ContainerRegistryURL: imageRegistry,
   328  			ContainerImageName:   "my-image",
   329  			DockerConfigJSON:     "/path/to/config.json",
   330  		}
   331  
   332  		utils := newCnbBuildTestsUtils()
   333  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":"dXNlcjpwYXNz"}}`))
   334  		addBuilderFiles(&utils)
   335  
   336  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   337  		assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig")
   338  	})
   339  
   340  	t.Run("error case: DockerConfigJSON file not there (config.json)", func(t *testing.T) {
   341  		t.Parallel()
   342  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   343  		config := cnbBuildOptions{
   344  			ContainerImageTag:    "0.0.1",
   345  			ContainerRegistryURL: imageRegistry,
   346  			ContainerImageName:   "my-image",
   347  			DockerConfigJSON:     "not-there/config.json",
   348  		}
   349  
   350  		utils := newCnbBuildTestsUtils()
   351  		addBuilderFiles(&utils)
   352  
   353  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   354  		assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: could not read 'not-there/config.json'")
   355  	})
   356  
   357  	t.Run("error case: DockerConfigJSON file not there (not config.json)", func(t *testing.T) {
   358  		t.Parallel()
   359  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   360  		config := cnbBuildOptions{
   361  			ContainerImageTag:    "0.0.1",
   362  			ContainerRegistryURL: imageRegistry,
   363  			ContainerImageName:   "my-image",
   364  			DockerConfigJSON:     "not-there",
   365  		}
   366  
   367  		utils := newCnbBuildTestsUtils()
   368  		addBuilderFiles(&utils)
   369  
   370  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   371  		assert.EqualError(t, err, "failed to rename DockerConfigJSON file 'not-there': renaming file 'not-there' is not supported, since it does not exist, or is not a leaf-entry")
   372  	})
   373  
   374  	t.Run("error case: dockerImage is not a valid builder", func(t *testing.T) {
   375  		t.Parallel()
   376  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   377  		config := cnbBuildOptions{}
   378  
   379  		utils := newCnbBuildTestsUtils()
   380  
   381  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   382  		assert.EqualError(t, err, "the provided dockerImage is not a valid builder: binary '/cnb/lifecycle/creator' not found")
   383  	})
   384  
   385  	t.Run("error case: builder image does not contain tls certificates", func(t *testing.T) {
   386  		t.Parallel()
   387  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   388  		config := cnbBuildOptions{
   389  			ContainerImageName:        "my-image",
   390  			ContainerImageTag:         "0.0.1",
   391  			ContainerRegistryURL:      imageRegistry,
   392  			DockerConfigJSON:          "/path/to/config.json",
   393  			Buildpacks:                []string{"test"},
   394  			CustomTLSCertificateLinks: []string{"http://example.com/certs.pem"},
   395  		}
   396  
   397  		utils := newCnbBuildTestsUtils()
   398  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   399  		addBuilderFiles(&utils)
   400  
   401  		err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   402  		assert.EqualError(t, err, "failed to copy certificates: cannot copy '/etc/ssl/certs/ca-certificates.crt': file does not exist")
   403  	})
   404  
   405  	t.Run("success case (telemetry was added)", func(t *testing.T) {
   406  		t.Parallel()
   407  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   408  		registry := "some-registry"
   409  		config := cnbBuildOptions{
   410  			ContainerImageName:   "my-image",
   411  			ContainerImageTag:    "3.1.5",
   412  			ContainerRegistryURL: registry,
   413  			DockerConfigJSON:     "/path/to/config.json",
   414  			ProjectDescriptor:    "project.toml",
   415  			AdditionalTags:       []string{"latest"},
   416  			Buildpacks:           []string{"paketobuildpacks/java", "gcr.io/paketo-buildpacks/node"},
   417  			Bindings:             map[string]interface{}{"SECRET": map[string]string{"key": "KEY", "file": "a_file"}},
   418  			Path:                 "target",
   419  		}
   420  
   421  		utils := newCnbBuildTestsUtils()
   422  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   423  		utils.FilesMock.AddDir("target")
   424  		utils.FilesMock.AddFile("target/project.toml", []byte(`[project]
   425  id = "test"
   426  name = "test"
   427  version = "1.0.0"
   428  
   429  [build]
   430  include = []
   431  exclude = ["*.tar"]
   432  
   433  [[build.buildpacks]]
   434  uri = "some-buildpack"`))
   435  		utils.FilesMock.AddFile("a_file", []byte(`{}`))
   436  		utils.FilesMock.AddFile("target/somelib.jar", []byte(`FFFFFF`))
   437  
   438  		addBuilderFiles(&utils)
   439  
   440  		telemetryData := telemetry.CustomData{}
   441  		err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   442  		require.NoError(t, err)
   443  
   444  		customDataAsString := telemetryData.Custom1
   445  		customData := cnbBuildTelemetry{}
   446  		err = json.Unmarshal([]byte(customDataAsString), &customData)
   447  
   448  		require.NoError(t, err)
   449  		assert.Equal(t, 3, customData.Version)
   450  		require.Equal(t, 1, len(customData.Data))
   451  		assert.Equal(t, "3.1.5", customData.Data[0].ImageTag)
   452  		assert.Equal(t, "folder", string(customData.Data[0].Path))
   453  		assert.Contains(t, customData.Data[0].AdditionalTags, "latest")
   454  		assert.Contains(t, customData.Data[0].BindingKeys, "SECRET")
   455  		assert.Equal(t, "paketobuildpacks/builder:full", customData.Data[0].Builder)
   456  
   457  		assert.Contains(t, customData.Data[0].Buildpacks.FromConfig, "paketobuildpacks/java")
   458  		assert.NotContains(t, customData.Data[0].Buildpacks.FromProjectDescriptor, "paketobuildpacks/java")
   459  		assert.Contains(t, customData.Data[0].Buildpacks.FromProjectDescriptor, "<redacted>")
   460  		assert.NotContains(t, customData.Data[0].Buildpacks.Overall, "<redacted>")
   461  		assert.Contains(t, customData.Data[0].Buildpacks.Overall, "paketobuildpacks/java")
   462  
   463  		assert.True(t, customData.Data[0].ProjectDescriptor.Used)
   464  		assert.False(t, customData.Data[0].ProjectDescriptor.IncludeUsed)
   465  		assert.True(t, customData.Data[0].ProjectDescriptor.ExcludeUsed)
   466  	})
   467  
   468  	t.Run("success case (build env telemetry was added)", func(t *testing.T) {
   469  		t.Parallel()
   470  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   471  		registry := "some-registry"
   472  		config := cnbBuildOptions{
   473  			ContainerImageName:   "my-image",
   474  			ContainerImageTag:    "3.1.5",
   475  			ContainerRegistryURL: registry,
   476  			ProjectDescriptor:    "project.toml",
   477  			BuildEnvVars:         map[string]interface{}{"CONFIG_KEY": "var", "BP_JVM_VERSION": "8"},
   478  		}
   479  
   480  		utils := newCnbBuildTestsUtils()
   481  		utils.FilesMock.AddFile("project.toml", []byte(`[project]
   482  id = "test"
   483  
   484  [build]
   485  include = []
   486  
   487  [[build.env]]
   488  name='PROJECT_KEY'
   489  value='var'
   490  
   491  [[build.env]]
   492  name='BP_NODE_VERSION'
   493  value='11'
   494  
   495  [[build.buildpacks]]
   496  uri = "some-buildpack"
   497  `))
   498  
   499  		addBuilderFiles(&utils)
   500  
   501  		telemetryData := telemetry.CustomData{}
   502  		err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   503  		require.NoError(t, err)
   504  
   505  		customDataAsString := telemetryData.Custom1
   506  		customData := cnbBuildTelemetry{}
   507  		err = json.Unmarshal([]byte(customDataAsString), &customData)
   508  
   509  		require.NoError(t, err)
   510  		require.Equal(t, 1, len(customData.Data))
   511  		assert.Contains(t, customData.Data[0].BuildEnv.KeysFromConfig, "CONFIG_KEY")
   512  		assert.NotContains(t, customData.Data[0].BuildEnv.KeysFromProjectDescriptor, "CONFIG_KEY")
   513  		assert.Contains(t, customData.Data[0].BuildEnv.KeysOverall, "CONFIG_KEY")
   514  
   515  		assert.NotContains(t, customData.Data[0].BuildEnv.KeysFromConfig, "PROJECT_KEY")
   516  		assert.Contains(t, customData.Data[0].BuildEnv.KeysFromProjectDescriptor, "PROJECT_KEY")
   517  		assert.Contains(t, customData.Data[0].BuildEnv.KeysOverall, "PROJECT_KEY")
   518  
   519  		assert.Equal(t, "8", customData.Data[0].BuildEnv.KeyValues["BP_JVM_VERSION"])
   520  		assert.Equal(t, "11", customData.Data[0].BuildEnv.KeyValues["BP_NODE_VERSION"])
   521  		assert.NotContains(t, customData.Data[0].BuildEnv.KeyValues, "PROJECT_KEY")
   522  
   523  		assert.Contains(t, customData.Data[0].Buildpacks.Overall, "<redacted>")
   524  	})
   525  
   526  	t.Run("success case (multiple images configured)", func(t *testing.T) {
   527  		t.Parallel()
   528  		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{}
   529  		config := cnbBuildOptions{
   530  			ContainerImageTag:    "3.1.5",
   531  			ContainerRegistryURL: imageRegistry,
   532  			DockerConfigJSON:     "/path/to/my-config.json",
   533  			AdditionalTags:       []string{"3", "3.1", "3.1", "3.1.5"},
   534  			MultipleImages:       []map[string]interface{}{{"ContainerImageName": "my-image-0"}, {"ContainerImageName": "my-image-1"}},
   535  		}
   536  
   537  		expectedImageCount := len(config.MultipleImages)
   538  
   539  		utils := newCnbBuildTestsUtils()
   540  		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`))
   541  		addBuilderFiles(&utils)
   542  
   543  		telemetryData := telemetry.CustomData{}
   544  		err := callCnbBuild(&config, &telemetryData, &utils, &commonPipelineEnvironment, &piperhttp.Client{})
   545  		require.NoError(t, err)
   546  
   547  		customDataAsString := telemetryData.Custom1
   548  		customData := cnbBuildTelemetry{}
   549  		err = json.Unmarshal([]byte(customDataAsString), &customData)
   550  		assert.NoError(t, err)
   551  		require.Equal(t, expectedImageCount, len(customData.Data))
   552  
   553  		runner := utils.ExecMockRunner
   554  		require.Equal(t, expectedImageCount, len(runner.Calls))
   555  		for i, call := range runner.Calls {
   556  			assert.Equal(t, 4, len(customData.Data[i].AdditionalTags))
   557  			assertLifecycleCalls(t, runner, i+1)
   558  			containerImageName := fmt.Sprintf("my-image-%d", i)
   559  			assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, containerImageName, config.ContainerImageTag))
   560  			assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, containerImageName))
   561  			assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, containerImageName))
   562  			assert.Contains(t, call.Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, containerImageName))
   563  		}
   564  
   565  		assert.Equal(t, "my-image-0:3.1.5", commonPipelineEnvironment.container.imageNameTag)
   566  	})
   567  
   568  }