github.com/SAP/jenkins-library@v1.362.0/cmd/golangBuild_test.go (about)

     1  //go:build unit
     2  // +build unit
     3  
     4  package cmd
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"net/http"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  
    14  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    15  	"github.com/SAP/jenkins-library/pkg/mock"
    16  	"github.com/SAP/jenkins-library/pkg/multiarch"
    17  	"github.com/SAP/jenkins-library/pkg/telemetry"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  
    21  	"golang.org/x/mod/modfile"
    22  	"golang.org/x/mod/module"
    23  )
    24  
    25  type golangBuildMockUtils struct {
    26  	*mock.ExecMockRunner
    27  	*mock.FilesMock
    28  
    29  	returnFileUploadStatus  int   // expected to be set upfront
    30  	returnFileUploadError   error // expected to be set upfront
    31  	returnFileDownloadError error // expected to be set upfront
    32  	returnFileUntarError    error // expected to be set upfront
    33  
    34  	clientOptions  []piperhttp.ClientOptions // set by mock
    35  	fileUploads    map[string]string         // set by mock
    36  	untarFileNames []string
    37  }
    38  
    39  func (g *golangBuildMockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error {
    40  	if g.returnFileDownloadError != nil {
    41  		return g.returnFileDownloadError
    42  	}
    43  	g.AddFile(filename, []byte("content"))
    44  	return nil
    45  }
    46  
    47  func (g *golangBuildMockUtils) GetRepositoryURL(module string) (string, error) {
    48  	return fmt.Sprintf("https://%s.git", module), nil
    49  }
    50  
    51  func (g *golangBuildMockUtils) SendRequest(method string, url string, r io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
    52  	return nil, fmt.Errorf("not implemented")
    53  }
    54  
    55  func (g *golangBuildMockUtils) SetOptions(options piperhttp.ClientOptions) {
    56  	g.clientOptions = append(g.clientOptions, options)
    57  }
    58  
    59  func (g *golangBuildMockUtils) UploadRequest(method, url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) {
    60  	g.fileUploads[file] = url
    61  
    62  	response := http.Response{
    63  		StatusCode: g.returnFileUploadStatus,
    64  	}
    65  
    66  	return &response, g.returnFileUploadError
    67  }
    68  
    69  func (g *golangBuildMockUtils) UploadFile(url, file, fieldName string, header http.Header, cookies []*http.Cookie, uploadType string) (*http.Response, error) {
    70  	return g.UploadRequest(http.MethodPut, url, file, fieldName, header, cookies, uploadType)
    71  }
    72  
    73  func (g *golangBuildMockUtils) Upload(data piperhttp.UploadRequestData) (*http.Response, error) {
    74  	return nil, fmt.Errorf("not implemented")
    75  }
    76  
    77  func (g *golangBuildMockUtils) getDockerImageValue(stepName string) (string, error) {
    78  	return "golang:latest", nil
    79  }
    80  
    81  func (g *golangBuildMockUtils) Untar(src string, dest string, stripComponentLevel int) error {
    82  	if g.returnFileUntarError != nil {
    83  		return g.returnFileUntarError
    84  	}
    85  	for _, file := range g.untarFileNames {
    86  		g.AddFile(filepath.Join(dest, file), []byte("test content"))
    87  	}
    88  	return nil
    89  }
    90  
    91  func newGolangBuildTestsUtils() *golangBuildMockUtils {
    92  	utils := golangBuildMockUtils{
    93  		ExecMockRunner: &mock.ExecMockRunner{},
    94  		FilesMock:      &mock.FilesMock{},
    95  		// clientOptions:  []piperhttp.ClientOptions{},
    96  		fileUploads: map[string]string{},
    97  	}
    98  	return &utils
    99  }
   100  
   101  func TestRunGolangBuild(t *testing.T) {
   102  	cpe := golangBuildCommonPipelineEnvironment{}
   103  	modTestFile := `module private.example.com/test
   104  
   105  require (
   106  		example.com/public/module v1.0.0
   107  		private1.example.com/private/repo v0.1.0
   108  		private2.example.com/another/repo v0.2.0
   109  )
   110  
   111  go 1.17`
   112  
   113  	t.Run("success - no tests", func(t *testing.T) {
   114  		config := golangBuildOptions{
   115  			TargetArchitectures: []string{"linux,amd64"},
   116  		}
   117  
   118  		utils := newGolangBuildTestsUtils()
   119  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   120  		telemetryData := telemetry.CustomData{}
   121  
   122  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   123  		assert.NoError(t, err)
   124  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   125  		assert.Equal(t, []string{"build", "-trimpath"}, utils.ExecMockRunner.Calls[0].Params)
   126  	})
   127  
   128  	t.Run("success - tests & ldflags", func(t *testing.T) {
   129  		config := golangBuildOptions{
   130  			RunTests:            true,
   131  			LdflagsTemplate:     "test",
   132  			Packages:            []string{"package/foo"},
   133  			TargetArchitectures: []string{"linux,amd64"},
   134  		}
   135  		utils := newGolangBuildTestsUtils()
   136  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   137  		telemetryData := telemetry.CustomData{}
   138  
   139  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   140  		assert.NoError(t, err)
   141  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   142  		assert.Equal(t, []string{"install", "gotest.tools/gotestsum@latest"}, utils.ExecMockRunner.Calls[0].Params)
   143  		assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[1].Exec)
   144  		assert.Equal(t, []string{"--junitfile", "TEST-go.xml", "--jsonfile", "unit-report.out", "--", fmt.Sprintf("-coverprofile=%v", coverageFile), "-tags=unit", "./..."}, utils.ExecMockRunner.Calls[1].Params)
   145  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
   146  		assert.Equal(t, []string{"build", "-trimpath", "-ldflags", "test", "package/foo"}, utils.ExecMockRunner.Calls[2].Params)
   147  	})
   148  
   149  	t.Run("success - test flags", func(t *testing.T) {
   150  		config := golangBuildOptions{
   151  			RunTests:            true,
   152  			Packages:            []string{"package/foo"},
   153  			TargetArchitectures: []string{"linux,amd64"},
   154  			TestOptions:         []string{"--foo", "--bar"},
   155  		}
   156  		utils := newGolangBuildTestsUtils()
   157  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   158  		telemetryData := telemetry.CustomData{}
   159  
   160  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   161  		assert.NoError(t, err)
   162  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   163  		assert.Equal(t, []string{"install", "gotest.tools/gotestsum@latest"}, utils.ExecMockRunner.Calls[0].Params)
   164  		assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[1].Exec)
   165  		assert.Equal(t, []string{"--junitfile", "TEST-go.xml", "--jsonfile", "unit-report.out", "--", fmt.Sprintf("-coverprofile=%v", coverageFile), "-tags=unit", "./...", "--foo", "--bar"}, utils.ExecMockRunner.Calls[1].Params)
   166  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
   167  		assert.Equal(t, []string{"build", "-trimpath", "package/foo"}, utils.ExecMockRunner.Calls[2].Params)
   168  	})
   169  
   170  	t.Run("success - tests with coverage", func(t *testing.T) {
   171  		config := golangBuildOptions{
   172  			RunTests:            true,
   173  			ReportCoverage:      true,
   174  			TargetArchitectures: []string{"linux,amd64"},
   175  		}
   176  		utils := newGolangBuildTestsUtils()
   177  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   178  		telemetryData := telemetry.CustomData{}
   179  
   180  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   181  		assert.NoError(t, err)
   182  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
   183  		assert.Equal(t, []string{"tool", "cover", "-html", coverageFile, "-o", "coverage.html"}, utils.ExecMockRunner.Calls[2].Params)
   184  	})
   185  
   186  	t.Run("success - integration tests", func(t *testing.T) {
   187  		config := golangBuildOptions{
   188  			RunIntegrationTests: true,
   189  			TargetArchitectures: []string{"linux,amd64"},
   190  		}
   191  		utils := newGolangBuildTestsUtils()
   192  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   193  		telemetryData := telemetry.CustomData{}
   194  
   195  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   196  		assert.NoError(t, err)
   197  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   198  		assert.Equal(t, []string{"install", "gotest.tools/gotestsum@latest"}, utils.ExecMockRunner.Calls[0].Params)
   199  		assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[1].Exec)
   200  		assert.Equal(t, []string{"--junitfile", "TEST-integration.xml", "--jsonfile", "integration-report.out", "--", "-tags=integration", "./..."}, utils.ExecMockRunner.Calls[1].Params)
   201  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
   202  		assert.Equal(t, []string{"build", "-trimpath"}, utils.ExecMockRunner.Calls[2].Params)
   203  	})
   204  
   205  	t.Run("success - simple publish", func(t *testing.T) {
   206  		config := golangBuildOptions{
   207  			TargetArchitectures: []string{"linux,amd64"},
   208  			Publish:             true,
   209  			TargetRepositoryURL: "https://my.target.repository.local/",
   210  			ArtifactVersion:     "1.0.0",
   211  		}
   212  
   213  		utils := newGolangBuildTestsUtils()
   214  		utils.returnFileUploadStatus = 201
   215  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   216  		telemetryData := telemetry.CustomData{}
   217  
   218  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   219  		assert.NoError(t, err)
   220  		assert.Equal(t, "test", cpe.custom.artifacts[0].Name)
   221  	})
   222  
   223  	t.Run("success - publishes binaries", func(t *testing.T) {
   224  		config := golangBuildOptions{
   225  			TargetArchitectures:      []string{"linux,amd64"},
   226  			Output:                   "testBin",
   227  			Publish:                  true,
   228  			TargetRepositoryURL:      "https://my.target.repository.local",
   229  			TargetRepositoryUser:     "user",
   230  			TargetRepositoryPassword: "password",
   231  			ArtifactVersion:          "1.0.0",
   232  		}
   233  		utils := newGolangBuildTestsUtils()
   234  		utils.returnFileUploadStatus = 201
   235  		utils.FilesMock.AddFile("go.mod", []byte("module example.com/my/module"))
   236  		telemetryData := telemetry.CustomData{}
   237  
   238  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   239  		if assert.NoError(t, err) {
   240  			assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   241  			assert.Equal(t, []string{"build", "-trimpath", "-o", "testBin-linux.amd64"}, utils.ExecMockRunner.Calls[0].Params)
   242  
   243  			assert.Equal(t, 1, len(utils.fileUploads))
   244  			assert.Equal(t, "https://my.target.repository.local/go/example.com/my/module/1.0.0/testBin-linux.amd64", utils.fileUploads["testBin-linux.amd64"])
   245  		}
   246  	})
   247  
   248  	t.Run("success - publishes binaries (when TargetRepositoryURL ends with slash)", func(t *testing.T) {
   249  		config := golangBuildOptions{
   250  			TargetArchitectures:      []string{"linux,amd64"},
   251  			Output:                   "testBin",
   252  			Publish:                  true,
   253  			TargetRepositoryURL:      "https://my.target.repository.local/",
   254  			TargetRepositoryUser:     "user",
   255  			TargetRepositoryPassword: "password",
   256  			ArtifactVersion:          "1.0.0",
   257  		}
   258  		utils := newGolangBuildTestsUtils()
   259  		utils.returnFileUploadStatus = 200
   260  		utils.FilesMock.AddFile("go.mod", []byte("module example.com/my/module"))
   261  		telemetryData := telemetry.CustomData{}
   262  
   263  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   264  		if assert.NoError(t, err) {
   265  			assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   266  			assert.Equal(t, []string{"build", "-trimpath", "-o", "testBin-linux.amd64"}, utils.ExecMockRunner.Calls[0].Params)
   267  
   268  			assert.Equal(t, 1, len(utils.fileUploads))
   269  			assert.Equal(t, "https://my.target.repository.local/go/example.com/my/module/1.0.0/testBin-linux.amd64", utils.fileUploads["testBin-linux.amd64"])
   270  		}
   271  	})
   272  
   273  	t.Run("success - create BOM", func(t *testing.T) {
   274  		config := golangBuildOptions{
   275  			CreateBOM:           true,
   276  			TargetArchitectures: []string{"linux,amd64"},
   277  		}
   278  		utils := newGolangBuildTestsUtils()
   279  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   280  		telemetryData := telemetry.CustomData{}
   281  
   282  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   283  		assert.NoError(t, err)
   284  		assert.Equal(t, 3, len(utils.ExecMockRunner.Calls))
   285  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   286  		assert.Equal(t, []string{"install", "github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1.4.0"}, utils.ExecMockRunner.Calls[0].Params)
   287  		assert.Equal(t, "cyclonedx-gomod", utils.ExecMockRunner.Calls[1].Exec)
   288  		assert.Equal(t, []string{"mod", "-licenses", "-verbose=false", "-test", "-output", "bom-golang.xml", "-output-version", "1.4"}, utils.ExecMockRunner.Calls[1].Params)
   289  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
   290  		assert.Equal(t, []string{"build", "-trimpath"}, utils.ExecMockRunner.Calls[2].Params)
   291  	})
   292  
   293  	t.Run("success - RunLint", func(t *testing.T) {
   294  		goPath := os.Getenv("GOPATH")
   295  		golangciLintDir := filepath.Join(goPath, "bin")
   296  		binaryPath := filepath.Join(golangciLintDir, "golangci-lint")
   297  
   298  		config := golangBuildOptions{
   299  			RunLint: true,
   300  		}
   301  		utils := newGolangBuildTestsUtils()
   302  		utils.AddFile("go.mod", []byte(modTestFile))
   303  		telemetry := telemetry.CustomData{}
   304  		err := runGolangBuild(&config, &telemetry, utils, &cpe)
   305  		assert.NoError(t, err)
   306  
   307  		b, err := utils.FileRead("golangci-lint.tar.gz")
   308  		assert.NoError(t, err)
   309  
   310  		assert.Equal(t, []byte("content"), b)
   311  		assert.Equal(t, binaryPath, utils.Calls[0].Exec)
   312  		assert.Equal(t, []string{"run", "--out-format", "checkstyle"}, utils.Calls[0].Params)
   313  	})
   314  
   315  	t.Run("failure - install pre-requisites for testing", func(t *testing.T) {
   316  		config := golangBuildOptions{
   317  			RunTests: true,
   318  		}
   319  		utils := newGolangBuildTestsUtils()
   320  		utils.ShouldFailOnCommand = map[string]error{"go install gotest.tools/gotestsum": fmt.Errorf("install failure")}
   321  		telemetryData := telemetry.CustomData{}
   322  
   323  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   324  		assert.EqualError(t, err, "failed to install pre-requisite: install failure")
   325  	})
   326  
   327  	t.Run("failure - install pre-requisites for BOM creation", func(t *testing.T) {
   328  		config := golangBuildOptions{
   329  			CreateBOM: true,
   330  		}
   331  		utils := newGolangBuildTestsUtils()
   332  		utils.ShouldFailOnCommand = map[string]error{"go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1.4.0": fmt.Errorf("install failure")}
   333  		telemetryData := telemetry.CustomData{}
   334  
   335  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   336  		assert.EqualError(t, err, "failed to install pre-requisite: install failure")
   337  	})
   338  
   339  	t.Run("failure - test run failure", func(t *testing.T) {
   340  		config := golangBuildOptions{
   341  			RunTests: true,
   342  		}
   343  		utils := newGolangBuildTestsUtils()
   344  		utils.ShouldFailOnCommand = map[string]error{"gotestsum --junitfile": fmt.Errorf("test failure")}
   345  		telemetryData := telemetry.CustomData{}
   346  
   347  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   348  		assert.EqualError(t, err, "running tests failed - junit result missing: test failure")
   349  	})
   350  
   351  	t.Run("failure - test failure", func(t *testing.T) {
   352  		config := golangBuildOptions{
   353  			RunTests: true,
   354  		}
   355  		utils := newGolangBuildTestsUtils()
   356  		utils.ShouldFailOnCommand = map[string]error{"gotestsum --junitfile": fmt.Errorf("test failure")}
   357  		utils.AddFile("TEST-go.xml", []byte("some content"))
   358  		utils.AddFile(coverageFile, []byte("some content"))
   359  		telemetryData := telemetry.CustomData{}
   360  
   361  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   362  		assert.EqualError(t, err, "some tests failed")
   363  	})
   364  
   365  	t.Run("failure - prepareLdflags", func(t *testing.T) {
   366  		config := golangBuildOptions{
   367  			RunTests:            true,
   368  			LdflagsTemplate:     "{{.CPE.test",
   369  			TargetArchitectures: []string{"linux,amd64"},
   370  		}
   371  		utils := newGolangBuildTestsUtils()
   372  		telemetryData := telemetry.CustomData{}
   373  
   374  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   375  		assert.Contains(t, fmt.Sprint(err), "failed to parse cpe template")
   376  	})
   377  
   378  	t.Run("failure - build failure", func(t *testing.T) {
   379  		config := golangBuildOptions{
   380  			RunIntegrationTests: true,
   381  			TargetArchitectures: []string{"linux,amd64"},
   382  		}
   383  		utils := newGolangBuildTestsUtils()
   384  		utils.FilesMock.AddFile("go.mod", []byte(modTestFile))
   385  		utils.ShouldFailOnCommand = map[string]error{"go build": fmt.Errorf("build failure")}
   386  		telemetryData := telemetry.CustomData{}
   387  
   388  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   389  		assert.EqualError(t, err, "failed to run build for linux.amd64: build failure")
   390  	})
   391  
   392  	t.Run("failure - publish - no target repository defined", func(t *testing.T) {
   393  		config := golangBuildOptions{
   394  			TargetArchitectures: []string{"linux,amd64"},
   395  			Output:              "testBin",
   396  			Publish:             true,
   397  		}
   398  		utils := newGolangBuildTestsUtils()
   399  		telemetryData := telemetry.CustomData{}
   400  
   401  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   402  		assert.EqualError(t, err, "there's no target repository for binary publishing configured")
   403  	})
   404  
   405  	t.Run("failure - publish - no go.mod file found", func(t *testing.T) {
   406  		config := golangBuildOptions{
   407  			TargetArchitectures:      []string{"linux,amd64"},
   408  			Output:                   "testBin",
   409  			Publish:                  true,
   410  			TargetRepositoryURL:      "https://my.target.repository.local",
   411  			TargetRepositoryUser:     "user",
   412  			TargetRepositoryPassword: "password",
   413  			ArtifactVersion:          "1.0.0",
   414  		}
   415  		utils := newGolangBuildTestsUtils()
   416  		telemetryData := telemetry.CustomData{}
   417  
   418  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   419  		assert.EqualError(t, err, "go.mod file not found")
   420  	})
   421  
   422  	t.Run("failure - publish - go.mod file without module path", func(t *testing.T) {
   423  		config := golangBuildOptions{
   424  			TargetArchitectures:      []string{"linux,amd64"},
   425  			Output:                   "testBin",
   426  			Publish:                  true,
   427  			TargetRepositoryURL:      "https://my.target.repository.local",
   428  			TargetRepositoryUser:     "user",
   429  			TargetRepositoryPassword: "password",
   430  			ArtifactVersion:          "1.0.0",
   431  		}
   432  		utils := newGolangBuildTestsUtils()
   433  		utils.FilesMock.AddFile("go.mod", []byte(""))
   434  		telemetryData := telemetry.CustomData{}
   435  
   436  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   437  		assert.EqualError(t, err, "go.mod doesn't declare a module path")
   438  	})
   439  
   440  	t.Run("failure - publish - no artifactVersion set", func(t *testing.T) {
   441  		config := golangBuildOptions{
   442  			TargetArchitectures:      []string{"linux,amd64"},
   443  			Output:                   "testBin",
   444  			Publish:                  true,
   445  			TargetRepositoryURL:      "https://my.target.repository.local",
   446  			TargetRepositoryUser:     "user",
   447  			TargetRepositoryPassword: "password",
   448  		}
   449  		utils := newGolangBuildTestsUtils()
   450  		utils.FilesMock.AddFile("go.mod", []byte("module example.com/my/module"))
   451  		telemetryData := telemetry.CustomData{}
   452  
   453  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   454  		assert.EqualError(t, err, "no build descriptor available, supported: [go.mod VERSION version.txt]")
   455  	})
   456  
   457  	t.Run("failure - publish - received unexpected status code", func(t *testing.T) {
   458  		config := golangBuildOptions{
   459  			TargetArchitectures:      []string{"linux,amd64"},
   460  			Output:                   "testBin",
   461  			Publish:                  true,
   462  			TargetRepositoryURL:      "https://my.target.repository.local",
   463  			TargetRepositoryUser:     "user",
   464  			TargetRepositoryPassword: "password",
   465  			ArtifactVersion:          "1.0.0",
   466  		}
   467  		utils := newGolangBuildTestsUtils()
   468  		utils.returnFileUploadStatus = 500
   469  		utils.FilesMock.AddFile("go.mod", []byte("module example.com/my/module"))
   470  		telemetryData := telemetry.CustomData{}
   471  
   472  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   473  		assert.EqualError(t, err, "couldn't upload artifact, received status code 500")
   474  	})
   475  
   476  	t.Run("failure - create BOM", func(t *testing.T) {
   477  		config := golangBuildOptions{
   478  			CreateBOM:           true,
   479  			TargetArchitectures: []string{"linux,amd64"},
   480  		}
   481  		GeneralConfig.Verbose = false
   482  		utils := newGolangBuildTestsUtils()
   483  		utils.ShouldFailOnCommand = map[string]error{"cyclonedx-gomod mod -licenses -verbose=false -test -output bom-golang.xml -output-version 1.4": fmt.Errorf("BOM creation failure")}
   484  		telemetryData := telemetry.CustomData{}
   485  
   486  		err := runGolangBuild(&config, &telemetryData, utils, &cpe)
   487  		assert.EqualError(t, err, "BOM creation failed: BOM creation failure")
   488  	})
   489  
   490  	t.Run("failure - RunLint: retrieveGolangciLint failed", func(t *testing.T) {
   491  		config := golangBuildOptions{
   492  			RunLint: true,
   493  		}
   494  
   495  		utils := newGolangBuildTestsUtils()
   496  		utils.AddFile("go.mod", []byte(modTestFile))
   497  		utils.returnFileDownloadError = fmt.Errorf("downloading error")
   498  		telemetry := telemetry.CustomData{}
   499  		err := runGolangBuild(&config, &telemetry, utils, &cpe)
   500  		assert.EqualError(t, err, "failed to download golangci-lint: downloading error")
   501  	})
   502  
   503  	t.Run("failure - RunLint: runGolangciLint failed", func(t *testing.T) {
   504  		goPath := os.Getenv("GOPATH")
   505  		golangciLintDir := filepath.Join(goPath, "bin")
   506  		binaryPath := filepath.Join(golangciLintDir, "golangci-lint")
   507  
   508  		config := golangBuildOptions{
   509  			RunLint: true,
   510  		}
   511  		utils := newGolangBuildTestsUtils()
   512  		utils.AddFile("go.mod", []byte(modTestFile))
   513  		utils.ShouldFailOnCommand = map[string]error{fmt.Sprintf("%s run --out-format checkstyle", binaryPath): fmt.Errorf("err")}
   514  		telemetry := telemetry.CustomData{}
   515  		err := runGolangBuild(&config, &telemetry, utils, &cpe)
   516  		assert.EqualError(t, err, "running golangci-lint failed: err")
   517  	})
   518  }
   519  
   520  func TestRunGolangTests(t *testing.T) {
   521  	t.Parallel()
   522  
   523  	t.Run("success", func(t *testing.T) {
   524  		t.Parallel()
   525  		config := golangBuildOptions{}
   526  		utils := newGolangBuildTestsUtils()
   527  		utils.AddFile("TEST-go.xml", []byte("some content"))
   528  		utils.AddFile(coverageFile, []byte("some content"))
   529  
   530  		success, err := runGolangTests(&config, utils)
   531  		assert.NoError(t, err)
   532  		assert.True(t, success)
   533  		assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[0].Exec)
   534  		assert.Equal(t, []string{"--junitfile", "TEST-go.xml", "--jsonfile", "unit-report.out", "--", fmt.Sprintf("-coverprofile=%v", coverageFile), "-tags=unit", "./..."}, utils.ExecMockRunner.Calls[0].Params)
   535  	})
   536  
   537  	t.Run("success - failed tests", func(t *testing.T) {
   538  		t.Parallel()
   539  		config := golangBuildOptions{}
   540  		utils := newGolangBuildTestsUtils()
   541  		utils.AddFile("TEST-go.xml", []byte("some content"))
   542  		utils.AddFile(coverageFile, []byte("some content"))
   543  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
   544  
   545  		success, err := runGolangTests(&config, utils)
   546  		assert.NoError(t, err)
   547  		assert.False(t, success)
   548  	})
   549  
   550  	t.Run("error - run failed, no junit", func(t *testing.T) {
   551  		t.Parallel()
   552  		config := golangBuildOptions{}
   553  		utils := newGolangBuildTestsUtils()
   554  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
   555  
   556  		_, err := runGolangTests(&config, utils)
   557  		assert.EqualError(t, err, "running tests failed - junit result missing: execution error")
   558  	})
   559  
   560  	t.Run("error - run failed, no coverage", func(t *testing.T) {
   561  		t.Parallel()
   562  		config := golangBuildOptions{}
   563  		utils := newGolangBuildTestsUtils()
   564  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
   565  		utils.AddFile("TEST-go.xml", []byte("some content"))
   566  
   567  		_, err := runGolangTests(&config, utils)
   568  		assert.EqualError(t, err, "running tests failed - coverage output missing: execution error")
   569  	})
   570  }
   571  
   572  func TestRunGolangIntegrationTests(t *testing.T) {
   573  	t.Parallel()
   574  
   575  	t.Run("success", func(t *testing.T) {
   576  		t.Parallel()
   577  		config := golangBuildOptions{}
   578  		utils := newGolangBuildTestsUtils()
   579  		utils.AddFile("TEST-integration.xml", []byte("some content"))
   580  
   581  		success, err := runGolangIntegrationTests(&config, utils)
   582  		assert.NoError(t, err)
   583  		assert.True(t, success)
   584  		assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[0].Exec)
   585  		assert.Equal(t, []string{"--junitfile", "TEST-integration.xml", "--jsonfile", "integration-report.out", "--", "-tags=integration", "./..."}, utils.ExecMockRunner.Calls[0].Params)
   586  	})
   587  
   588  	t.Run("success - failed tests", func(t *testing.T) {
   589  		t.Parallel()
   590  		config := golangBuildOptions{}
   591  		utils := newGolangBuildTestsUtils()
   592  		utils.AddFile("TEST-integration.xml", []byte("some content"))
   593  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
   594  
   595  		success, err := runGolangIntegrationTests(&config, utils)
   596  		assert.NoError(t, err)
   597  		assert.False(t, success)
   598  	})
   599  
   600  	t.Run("error - run failed", func(t *testing.T) {
   601  		t.Parallel()
   602  		config := golangBuildOptions{}
   603  		utils := newGolangBuildTestsUtils()
   604  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
   605  
   606  		_, err := runGolangIntegrationTests(&config, utils)
   607  		assert.EqualError(t, err, "running tests failed: execution error")
   608  	})
   609  }
   610  
   611  func TestReportGolangTestCoverage(t *testing.T) {
   612  	t.Parallel()
   613  
   614  	t.Run("success - cobertura", func(t *testing.T) {
   615  		t.Parallel()
   616  		config := golangBuildOptions{CoverageFormat: "cobertura"}
   617  		utils := newGolangBuildTestsUtils()
   618  		utils.AddFile(coverageFile, []byte("some content"))
   619  
   620  		err := reportGolangTestCoverage(&config, utils)
   621  		assert.NoError(t, err)
   622  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   623  		assert.Equal(t, []string{"install", "github.com/boumenot/gocover-cobertura@latest"}, utils.ExecMockRunner.Calls[0].Params)
   624  		assert.Equal(t, "gocover-cobertura", utils.ExecMockRunner.Calls[1].Exec)
   625  		exists, err := utils.FileExists("cobertura-coverage.xml")
   626  		assert.NoError(t, err)
   627  		assert.True(t, exists)
   628  	})
   629  
   630  	t.Run("success - cobertura exclude generated", func(t *testing.T) {
   631  		t.Parallel()
   632  		config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
   633  		utils := newGolangBuildTestsUtils()
   634  		utils.AddFile(coverageFile, []byte("some content"))
   635  
   636  		err := reportGolangTestCoverage(&config, utils)
   637  		assert.NoError(t, err)
   638  		assert.Equal(t, "gocover-cobertura", utils.ExecMockRunner.Calls[1].Exec)
   639  		assert.Equal(t, []string{"-ignore-gen-files"}, utils.ExecMockRunner.Calls[1].Params)
   640  	})
   641  
   642  	t.Run("error - cobertura installation", func(t *testing.T) {
   643  		t.Parallel()
   644  		config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
   645  		utils := newGolangBuildTestsUtils()
   646  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"go install github.com/boumenot/gocover-cobertura": fmt.Errorf("install error")}
   647  
   648  		err := reportGolangTestCoverage(&config, utils)
   649  		assert.EqualError(t, err, "failed to install pre-requisite: install error")
   650  	})
   651  
   652  	t.Run("error - cobertura missing coverage file", func(t *testing.T) {
   653  		t.Parallel()
   654  		config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
   655  		utils := newGolangBuildTestsUtils()
   656  
   657  		err := reportGolangTestCoverage(&config, utils)
   658  		assert.Contains(t, fmt.Sprint(err), "failed to read coverage file")
   659  	})
   660  
   661  	t.Run("error - cobertura coversion", func(t *testing.T) {
   662  		t.Parallel()
   663  		config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
   664  		utils := newGolangBuildTestsUtils()
   665  		utils.AddFile(coverageFile, []byte("some content"))
   666  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gocover-cobertura -ignore-gen-files": fmt.Errorf("execution error")}
   667  
   668  		err := reportGolangTestCoverage(&config, utils)
   669  		assert.EqualError(t, err, "failed to convert coverage data to cobertura format: execution error")
   670  	})
   671  
   672  	t.Run("error - writing cobertura file", func(t *testing.T) {
   673  		t.Parallel()
   674  		config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
   675  		utils := newGolangBuildTestsUtils()
   676  		utils.AddFile(coverageFile, []byte("some content"))
   677  		utils.FileWriteError = fmt.Errorf("write failure")
   678  
   679  		err := reportGolangTestCoverage(&config, utils)
   680  		assert.EqualError(t, err, "failed to create cobertura coverage file: write failure")
   681  	})
   682  
   683  	t.Run("success - html", func(t *testing.T) {
   684  		t.Parallel()
   685  		config := golangBuildOptions{}
   686  		utils := newGolangBuildTestsUtils()
   687  
   688  		err := reportGolangTestCoverage(&config, utils)
   689  		assert.NoError(t, err)
   690  		assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
   691  		assert.Equal(t, []string{"tool", "cover", "-html", coverageFile, "-o", "coverage.html"}, utils.ExecMockRunner.Calls[0].Params)
   692  	})
   693  
   694  	t.Run("error - html", func(t *testing.T) {
   695  		t.Parallel()
   696  		config := golangBuildOptions{}
   697  		utils := newGolangBuildTestsUtils()
   698  		utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"go tool cover -html cover.out -o coverage.html": fmt.Errorf("execution error")}
   699  		utils.AddFile(coverageFile, []byte("some content"))
   700  
   701  		err := reportGolangTestCoverage(&config, utils)
   702  		assert.EqualError(t, err, "failed to create html coverage file: execution error")
   703  	})
   704  }
   705  
   706  func TestPrepareLdflags(t *testing.T) {
   707  	t.Parallel()
   708  	dir := t.TempDir()
   709  
   710  	err := os.Mkdir(filepath.Join(dir, "commonPipelineEnvironment"), 0o777)
   711  	assert.NoError(t, err, "Error when creating folder structure")
   712  
   713  	err = os.WriteFile(filepath.Join(dir, "commonPipelineEnvironment", "artifactVersion"), []byte("1.2.3"), 0666)
   714  	assert.NoError(t, err, "Error when creating cpe file")
   715  
   716  	t.Run("success - default", func(t *testing.T) {
   717  		config := golangBuildOptions{LdflagsTemplate: "-X version={{ .CPE.artifactVersion }}"}
   718  		utils := newGolangBuildTestsUtils()
   719  		result, err := prepareLdflags(&config, utils, dir)
   720  		assert.NoError(t, err)
   721  		assert.Equal(t, "-X version=1.2.3", (*result).String())
   722  	})
   723  
   724  	t.Run("error - template parsing", func(t *testing.T) {
   725  		config := golangBuildOptions{LdflagsTemplate: "-X version={{ .CPE.artifactVersion "}
   726  		utils := newGolangBuildTestsUtils()
   727  		_, err := prepareLdflags(&config, utils, dir)
   728  		assert.Contains(t, fmt.Sprint(err), "failed to parse cpe template")
   729  	})
   730  }
   731  
   732  func TestRunGolangBuildPerArchitecture(t *testing.T) {
   733  	t.Parallel()
   734  
   735  	t.Run("success - default", func(t *testing.T) {
   736  		t.Parallel()
   737  		config := golangBuildOptions{}
   738  		utils := newGolangBuildTestsUtils()
   739  		ldflags := ""
   740  		architecture, _ := multiarch.ParsePlatformString("linux,amd64")
   741  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   742  
   743  		binaryName, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   744  		assert.NoError(t, err)
   745  		assert.Greater(t, len(utils.Env), 3)
   746  		assert.Contains(t, utils.Env, "CGO_ENABLED=0")
   747  		assert.Contains(t, utils.Env, "GOOS=linux")
   748  		assert.Contains(t, utils.Env, "GOARCH=amd64")
   749  		assert.Equal(t, utils.Calls[0].Exec, "go")
   750  		assert.Equal(t, utils.Calls[0].Params[0], "build")
   751  		assert.Equal(t, binaryName[0], "testBinary")
   752  	})
   753  
   754  	t.Run("success - custom params", func(t *testing.T) {
   755  		t.Parallel()
   756  		config := golangBuildOptions{BuildFlags: []string{"--flag1", "val1", "--flag2", "val2"}, Output: "testBin", Packages: []string{"./test/.."}}
   757  		utils := newGolangBuildTestsUtils()
   758  		ldflags := "-X test=test"
   759  		architecture, _ := multiarch.ParsePlatformString("linux,amd64")
   760  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   761  
   762  		binaryNames, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   763  		assert.NoError(t, err)
   764  		assert.Contains(t, utils.Calls[0].Params, "-o")
   765  		assert.Contains(t, utils.Calls[0].Params, "testBin-linux.amd64")
   766  		assert.Contains(t, utils.Calls[0].Params, "./test/..")
   767  		assert.Contains(t, utils.Calls[0].Params, "-ldflags")
   768  		assert.Contains(t, utils.Calls[0].Params, "-X test=test")
   769  		assert.Len(t, binaryNames, 1)
   770  		assert.Contains(t, binaryNames, "testBin-linux.amd64")
   771  	})
   772  
   773  	t.Run("success - windows", func(t *testing.T) {
   774  		t.Parallel()
   775  		config := golangBuildOptions{Output: "testBin"}
   776  		utils := newGolangBuildTestsUtils()
   777  		ldflags := ""
   778  		architecture, _ := multiarch.ParsePlatformString("windows,amd64")
   779  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   780  
   781  		binaryNames, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   782  		assert.NoError(t, err)
   783  		assert.Contains(t, utils.Calls[0].Params, "-o")
   784  		assert.Contains(t, utils.Calls[0].Params, "testBin-windows.amd64.exe")
   785  		assert.Len(t, binaryNames, 1)
   786  		assert.Contains(t, binaryNames, "testBin-windows.amd64.exe")
   787  	})
   788  
   789  	t.Run("success - multiple main packages (linux)", func(t *testing.T) {
   790  		t.Parallel()
   791  		config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
   792  		utils := newGolangBuildTestsUtils()
   793  		utils.StdoutReturn = map[string]string{
   794  			"go list -f {{ .Name }} package/foo": "main",
   795  			"go list -f {{ .Name }} package/bar": "main",
   796  		}
   797  		ldflags := ""
   798  		architecture, _ := multiarch.ParsePlatformString("linux,amd64")
   799  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   800  
   801  		binaryNames, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   802  		assert.NoError(t, err)
   803  		assert.Contains(t, utils.Calls[0].Params, "list")
   804  		assert.Contains(t, utils.Calls[0].Params, "package/foo")
   805  		assert.Contains(t, utils.Calls[1].Params, "list")
   806  		assert.Contains(t, utils.Calls[1].Params, "package/bar")
   807  
   808  		assert.Len(t, binaryNames, 2)
   809  		assert.Contains(t, binaryNames, "test-linux-amd64/foo")
   810  		assert.Contains(t, binaryNames, "test-linux-amd64/bar")
   811  	})
   812  
   813  	t.Run("success - multiple main packages (windows)", func(t *testing.T) {
   814  		t.Parallel()
   815  		config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
   816  		utils := newGolangBuildTestsUtils()
   817  		utils.StdoutReturn = map[string]string{
   818  			"go list -f {{ .Name }} package/foo": "main",
   819  			"go list -f {{ .Name }} package/bar": "main",
   820  		}
   821  		ldflags := ""
   822  		architecture, _ := multiarch.ParsePlatformString("windows,amd64")
   823  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   824  
   825  		binaryNames, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   826  		assert.NoError(t, err)
   827  		assert.Contains(t, utils.Calls[0].Params, "list")
   828  		assert.Contains(t, utils.Calls[0].Params, "package/foo")
   829  		assert.Contains(t, utils.Calls[1].Params, "list")
   830  		assert.Contains(t, utils.Calls[1].Params, "package/bar")
   831  
   832  		assert.Len(t, binaryNames, 2)
   833  		assert.Contains(t, binaryNames, "test-windows-amd64/foo.exe")
   834  		assert.Contains(t, binaryNames, "test-windows-amd64/bar.exe")
   835  	})
   836  
   837  	t.Run("success - multiple mixed packages", func(t *testing.T) {
   838  		t.Parallel()
   839  		config := golangBuildOptions{Output: "test/", Packages: []string{"package/foo", "package/bar"}}
   840  		utils := newGolangBuildTestsUtils()
   841  		utils.StdoutReturn = map[string]string{
   842  			"go list -f {{ .Name }} package/foo": "main",
   843  			"go list -f {{ .Name }} package/bar": "bar",
   844  		}
   845  		ldflags := ""
   846  		architecture, _ := multiarch.ParsePlatformString("linux,amd64")
   847  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   848  
   849  		binaryNames, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   850  		assert.NoError(t, err)
   851  		assert.Contains(t, utils.Calls[0].Params, "list")
   852  		assert.Contains(t, utils.Calls[0].Params, "package/foo")
   853  		assert.Contains(t, utils.Calls[1].Params, "list")
   854  		assert.Contains(t, utils.Calls[1].Params, "package/bar")
   855  
   856  		assert.Len(t, binaryNames, 1)
   857  		assert.Contains(t, binaryNames, "test-linux-amd64/foo")
   858  	})
   859  
   860  	t.Run("execution error", func(t *testing.T) {
   861  		t.Parallel()
   862  		config := golangBuildOptions{}
   863  		utils := newGolangBuildTestsUtils()
   864  		utils.ShouldFailOnCommand = map[string]error{"go build": fmt.Errorf("execution error")}
   865  		ldflags := ""
   866  		architecture, _ := multiarch.ParsePlatformString("linux,amd64")
   867  		goModFile := modfile.File{Module: &modfile.Module{Mod: module.Version{Path: "test/testBinary"}}}
   868  
   869  		_, err := runGolangBuildPerArchitecture(&config, &goModFile, utils, ldflags, architecture)
   870  		assert.EqualError(t, err, "failed to run build for linux.amd64: execution error")
   871  	})
   872  }
   873  
   874  func TestPrepareGolangEnvironment(t *testing.T) {
   875  	modTestFile := `
   876  module private.example.com/m
   877  
   878  require (
   879          example.com/public/module v1.0.0
   880          private1.example.com/private/repo v0.1.0
   881          private2.example.com/another/repo v0.2.0
   882  )
   883  
   884  go 1.17`
   885  
   886  	type expectations struct {
   887  		envVars          []string
   888  		commandsExecuted [][]string
   889  	}
   890  	tests := []struct {
   891  		name           string
   892  		modFileContent string
   893  		globPattern    string
   894  		gitToken       string
   895  		expect         expectations
   896  	}{
   897  		{
   898  			name:           "success - does nothing if privateModules is not set",
   899  			modFileContent: modTestFile,
   900  			globPattern:    "",
   901  			gitToken:       "secret",
   902  			expect:         expectations{},
   903  		},
   904  		{
   905  			name:           "success - goprivate is set and authentication properly configured",
   906  			modFileContent: modTestFile,
   907  			globPattern:    "*.example.com",
   908  			gitToken:       "secret",
   909  			expect: expectations{
   910  				envVars: []string{"GOPRIVATE=*.example.com"},
   911  				commandsExecuted: [][]string{
   912  					{"git", "config", "--global", "url.https://secret@example.com.insteadOf", "https://example.com"},
   913  				},
   914  			},
   915  		},
   916  	}
   917  
   918  	for _, tt := range tests {
   919  		t.Run(tt.name, func(t *testing.T) {
   920  			utils := newGolangBuildTestsUtils()
   921  
   922  			goModFile, _ := modfile.Parse("go.mod", []byte(tt.modFileContent), nil)
   923  
   924  			config := golangBuildOptions{}
   925  			config.PrivateModules = tt.globPattern
   926  			config.PrivateModulesGitToken = tt.gitToken
   927  
   928  			err := prepareGolangEnvironment(&config, goModFile, utils)
   929  
   930  			if assert.NoError(t, err) {
   931  				assert.Subset(t, os.Environ(), tt.expect.envVars)
   932  				assert.Equal(t, len(tt.expect.commandsExecuted), len(utils.Calls))
   933  
   934  				for i, expectedCommand := range tt.expect.commandsExecuted {
   935  					assert.Equal(t, expectedCommand[0], utils.Calls[i].Exec)
   936  					assert.Equal(t, expectedCommand[1:], utils.Calls[i].Params)
   937  				}
   938  			}
   939  		})
   940  	}
   941  }
   942  
   943  func TestRunGolangciLint(t *testing.T) {
   944  	t.Parallel()
   945  
   946  	goPath := os.Getenv("GOPATH")
   947  	golangciLintDir := filepath.Join(goPath, "bin")
   948  	binaryPath := filepath.Join(golangciLintDir, "golangci-lint")
   949  
   950  	lintSettings := map[string]string{
   951  		"reportStyle":      "checkstyle",
   952  		"reportOutputPath": "golangci-lint-report.xml",
   953  		"additionalParams": "",
   954  	}
   955  
   956  	tt := []struct {
   957  		name                string
   958  		shouldFailOnCommand map[string]error
   959  		fileWriteError      error
   960  		exitCode            int
   961  		expectedCommand     []string
   962  		expectedErr         error
   963  		failOnLintingError  bool
   964  	}{
   965  		{
   966  			name:                "success",
   967  			shouldFailOnCommand: map[string]error{},
   968  			fileWriteError:      nil,
   969  			exitCode:            0,
   970  			expectedCommand:     []string{binaryPath, "run", "--out-format", lintSettings["reportStyle"]},
   971  			expectedErr:         nil,
   972  		},
   973  		{
   974  			name:                "failure - failed to run golangci-lint",
   975  			shouldFailOnCommand: map[string]error{fmt.Sprintf("%s run --out-format %s", binaryPath, lintSettings["reportStyle"]): fmt.Errorf("err")},
   976  			fileWriteError:      nil,
   977  			exitCode:            0,
   978  			expectedCommand:     []string{},
   979  			expectedErr:         fmt.Errorf("running golangci-lint failed: err"),
   980  		},
   981  		{
   982  			name:                "failure - failed to write golangci-lint report",
   983  			shouldFailOnCommand: map[string]error{},
   984  			fileWriteError:      fmt.Errorf("failed to write golangci-lint report"),
   985  			exitCode:            0,
   986  			expectedCommand:     []string{},
   987  			expectedErr:         fmt.Errorf("writing golangci-lint report failed: failed to write golangci-lint report"),
   988  		},
   989  		{
   990  			name:                "failure - failed with ExitCode == 1",
   991  			shouldFailOnCommand: map[string]error{},
   992  			exitCode:            1,
   993  			expectedCommand:     []string{},
   994  			expectedErr:         fmt.Errorf("golangci-lint found issues, see report above"),
   995  			failOnLintingError:  true,
   996  		},
   997  		{
   998  			name:                "success - ignore failed with ExitCode == 1",
   999  			shouldFailOnCommand: map[string]error{},
  1000  			exitCode:            1,
  1001  			expectedCommand:     []string{binaryPath, "run", "--out-format", lintSettings["reportStyle"]},
  1002  			expectedErr:         nil,
  1003  			failOnLintingError:  false,
  1004  		},
  1005  	}
  1006  
  1007  	for _, test := range tt {
  1008  		test := test
  1009  		t.Run(test.name, func(t *testing.T) {
  1010  			t.Parallel()
  1011  			utils := newGolangBuildTestsUtils()
  1012  			utils.ShouldFailOnCommand = test.shouldFailOnCommand
  1013  			utils.FileWriteError = test.fileWriteError
  1014  			utils.ExitCode = test.exitCode
  1015  			err := runGolangciLint(utils, golangciLintDir, test.failOnLintingError, lintSettings)
  1016  
  1017  			if test.expectedErr == nil {
  1018  				assert.Equal(t, test.expectedCommand[0], utils.Calls[0].Exec)
  1019  				assert.Equal(t, test.expectedCommand[1:], utils.Calls[0].Params)
  1020  			} else {
  1021  				assert.EqualError(t, err, test.expectedErr.Error())
  1022  			}
  1023  		})
  1024  	}
  1025  }
  1026  
  1027  func TestRetrieveGolangciLint(t *testing.T) {
  1028  	t.Parallel()
  1029  
  1030  	goPath := os.Getenv("GOPATH")
  1031  	golangciLintDir := filepath.Join(goPath, "bin")
  1032  
  1033  	tt := []struct {
  1034  		name        string
  1035  		downloadErr error
  1036  		untarErr    error
  1037  		expectedErr error
  1038  	}{
  1039  		{
  1040  			name: "success",
  1041  		},
  1042  		{
  1043  			name:        "failure - failed to download golangci-lint",
  1044  			downloadErr: fmt.Errorf("download err"),
  1045  			expectedErr: fmt.Errorf("failed to download golangci-lint: download err"),
  1046  		},
  1047  		{
  1048  			name:        "failure - failed to install golangci-lint",
  1049  			untarErr:    fmt.Errorf("retrieve archive err"),
  1050  			expectedErr: fmt.Errorf("failed to install golangci-lint: retrieve archive err"),
  1051  		},
  1052  	}
  1053  
  1054  	for _, test := range tt {
  1055  		test := test
  1056  		t.Run(test.name, func(t *testing.T) {
  1057  			t.Parallel()
  1058  			utils := newGolangBuildTestsUtils()
  1059  			utils.returnFileDownloadError = test.downloadErr
  1060  			utils.returnFileUntarError = test.untarErr
  1061  			utils.untarFileNames = []string{"golangci-lint"}
  1062  			config := golangBuildOptions{
  1063  				GolangciLintURL: "https://github.com/golangci/golangci-lint/releases/download/v1.50.1/golangci-lint-1.50.0-darwin-amd64.tar.gz",
  1064  			}
  1065  			err := retrieveGolangciLint(utils, golangciLintDir, config.GolangciLintURL)
  1066  
  1067  			if test.expectedErr != nil {
  1068  				assert.EqualError(t, err, test.expectedErr.Error())
  1069  			} else {
  1070  				b, err := utils.ReadFile("golangci-lint.tar.gz")
  1071  				assert.NoError(t, err)
  1072  				assert.Equal(t, []byte("content"), b)
  1073  				b, err = utils.ReadFile(filepath.Join(golangciLintDir, "golangci-lint"))
  1074  				assert.NoError(t, err)
  1075  				assert.Equal(t, []byte("test content"), b)
  1076  			}
  1077  		})
  1078  	}
  1079  }
  1080  
  1081  func Test_gitConfigurationForPrivateModules(t *testing.T) {
  1082  	type args struct {
  1083  		privateMod string
  1084  		token      string
  1085  	}
  1086  	type expectations struct {
  1087  		commandsExecuted [][]string
  1088  	}
  1089  	tests := []struct {
  1090  		name string
  1091  		args args
  1092  
  1093  		expected expectations
  1094  	}{
  1095  		{
  1096  			name: "with one private module",
  1097  			args: args{
  1098  				privateMod: "example.com/*",
  1099  				token:      "mytoken",
  1100  			},
  1101  			expected: expectations{
  1102  				commandsExecuted: [][]string{
  1103  					{"git", "config", "--global", "url.https://mytoken@example.com.insteadOf", "https://example.com"},
  1104  				},
  1105  			},
  1106  		},
  1107  		{
  1108  			name: "with multiple private modules",
  1109  			args: args{
  1110  				privateMod: "example.com/*,test.com/*",
  1111  				token:      "mytoken",
  1112  			},
  1113  			expected: expectations{
  1114  				commandsExecuted: [][]string{
  1115  					{"git", "config", "--global", "url.https://mytoken@example.com.insteadOf", "https://example.com"},
  1116  					{"git", "config", "--global", "url.https://mytoken@test.com.insteadOf", "https://test.com"},
  1117  				},
  1118  			},
  1119  		},
  1120  	}
  1121  	for _, tt := range tests {
  1122  		t.Run(tt.name, func(t *testing.T) {
  1123  			utils := newGolangBuildTestsUtils()
  1124  
  1125  			err := gitConfigurationForPrivateModules(tt.args.privateMod, tt.args.token, utils)
  1126  
  1127  			if assert.NoError(t, err) {
  1128  				for i, expectedCommand := range tt.expected.commandsExecuted {
  1129  					assert.Equal(t, expectedCommand[0], utils.Calls[i].Exec)
  1130  					assert.Equal(t, expectedCommand[1:], utils.Calls[i].Params)
  1131  				}
  1132  			}
  1133  		})
  1134  	}
  1135  }