1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00
sap-jenkins-library/cmd/golangBuild_test.go
Oliver Nocon 9a78fabc89
feat(golangBuild): add new step for building go (#3178)
* feat(golangBuild): add new step for building go

* chore(golangBuild): increase test coverage

* remove indirect dependencies

* cleanup go.sum

* chore: remove trailing spaces

* chore(golangBuild): cleanup params, add groovy wrapper

* fix: update docker options

* update docs

* update installation according to https://golang.org/doc/go-get-install-deprecation

* fix: update installation

* update groovy test exclusion

* Update vars/golangBuild.groovy

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* update branch

* address PR feedback

* fix compilation error

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
2021-12-06 16:17:59 +01:00

435 lines
16 KiB
Go

package cmd
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/SAP/jenkins-library/pkg/mock"
"github.com/SAP/jenkins-library/pkg/telemetry"
"github.com/stretchr/testify/assert"
)
type golangBuildMockUtils struct {
*mock.ExecMockRunner
*mock.FilesMock
}
func newGolangBuildTestsUtils() golangBuildMockUtils {
utils := golangBuildMockUtils{
ExecMockRunner: &mock.ExecMockRunner{},
FilesMock: &mock.FilesMock{},
}
return utils
}
func TestRunGolangBuild(t *testing.T) {
t.Run("success - no tests", func(t *testing.T) {
config := golangBuildOptions{
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"build"}, utils.ExecMockRunner.Calls[0].Params)
})
t.Run("success - tests & ldflags", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
LdflagsTemplate: "test",
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"install", "gotest.tools/gotestsum@latest"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"--junitfile", "TEST-go.xml", "--", fmt.Sprintf("-coverprofile=%v", coverageFile), "./..."}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"build", "-ldflags", "test"}, utils.ExecMockRunner.Calls[2].Params)
})
t.Run("success - tests with coverage", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
ReportCoverage: true,
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"tool", "cover", "-html", coverageFile, "-o", "coverage.html"}, utils.ExecMockRunner.Calls[2].Params)
})
t.Run("success - integration tests", func(t *testing.T) {
config := golangBuildOptions{
RunIntegrationTests: true,
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"install", "gotest.tools/gotestsum@latest"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"--junitfile", "TEST-integration.xml", "--", "-tags=integration", "./..."}, utils.ExecMockRunner.Calls[1].Params)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[2].Exec)
assert.Equal(t, []string{"build"}, utils.ExecMockRunner.Calls[2].Params)
})
t.Run("failure - install pre-requisites", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
}
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"go install gotest.tools/gotestsum": fmt.Errorf("install failure")}
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "failed to install pre-requisite: install failure")
})
t.Run("failure - test run failure", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
}
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"gotestsum --junitfile": fmt.Errorf("test failure")}
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "running tests failed - junit result missing: test failure")
})
t.Run("failure - test failure", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
}
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"gotestsum --junitfile": fmt.Errorf("test failure")}
utils.AddFile("TEST-go.xml", []byte("some content"))
utils.AddFile(coverageFile, []byte("some content"))
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "some tests failed")
})
t.Run("failure - prepareLdflags", func(t *testing.T) {
config := golangBuildOptions{
RunTests: true,
LdflagsTemplate: "{{.CPE.test",
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.Contains(t, fmt.Sprint(err), "failed to parse ldflagsTemplate")
})
t.Run("failure - build failure", func(t *testing.T) {
config := golangBuildOptions{
RunIntegrationTests: true,
TargetArchitectures: []string{"linux,amd64"},
}
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"go build": fmt.Errorf("build failure")}
telemetryData := telemetry.CustomData{}
err := runGolangBuild(&config, &telemetryData, utils)
assert.EqualError(t, err, "failed to run build for linux.amd64: build failure")
})
}
func TestRunGolangTests(t *testing.T) {
t.Parallel()
t.Run("success", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.AddFile("TEST-go.xml", []byte("some content"))
utils.AddFile(coverageFile, []byte("some content"))
success, err := runGolangTests(&config, utils)
assert.NoError(t, err)
assert.True(t, success)
assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"--junitfile", "TEST-go.xml", "--", fmt.Sprintf("-coverprofile=%v", coverageFile), "./..."}, utils.ExecMockRunner.Calls[0].Params)
})
t.Run("success - failed tests", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.AddFile("TEST-go.xml", []byte("some content"))
utils.AddFile(coverageFile, []byte("some content"))
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
success, err := runGolangTests(&config, utils)
assert.NoError(t, err)
assert.False(t, success)
})
t.Run("error - run failed, no junit", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
_, err := runGolangTests(&config, utils)
assert.EqualError(t, err, "running tests failed - junit result missing: execution error")
})
t.Run("error - run failed, no coverage", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
utils.AddFile("TEST-go.xml", []byte("some content"))
_, err := runGolangTests(&config, utils)
assert.EqualError(t, err, "running tests failed - coverage output missing: execution error")
})
}
func TestRunGolangIntegrationTests(t *testing.T) {
t.Parallel()
t.Run("success", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.AddFile("TEST-integration.xml", []byte("some content"))
success, err := runGolangIntegrationTests(&config, utils)
assert.NoError(t, err)
assert.True(t, success)
assert.Equal(t, "gotestsum", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"--junitfile", "TEST-integration.xml", "--", "-tags=integration", "./..."}, utils.ExecMockRunner.Calls[0].Params)
})
t.Run("success - failed tests", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.AddFile("TEST-integration.xml", []byte("some content"))
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
success, err := runGolangIntegrationTests(&config, utils)
assert.NoError(t, err)
assert.False(t, success)
})
t.Run("error - run failed", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gotestsum": fmt.Errorf("execution error")}
_, err := runGolangIntegrationTests(&config, utils)
assert.EqualError(t, err, "running tests failed: execution error")
})
}
func TestReportGolangTestCoverage(t *testing.T) {
t.Parallel()
t.Run("success - cobertura", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura"}
utils := newGolangBuildTestsUtils()
utils.AddFile(coverageFile, []byte("some content"))
err := reportGolangTestCoverage(&config, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"install", "github.com/boumenot/gocover-cobertura@latest"}, utils.ExecMockRunner.Calls[0].Params)
assert.Equal(t, "gocover-cobertura", utils.ExecMockRunner.Calls[1].Exec)
exists, err := utils.FileExists("cobertura-coverage.xml")
assert.NoError(t, err)
assert.True(t, exists)
})
t.Run("success - cobertura exclude generated", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
utils := newGolangBuildTestsUtils()
utils.AddFile(coverageFile, []byte("some content"))
err := reportGolangTestCoverage(&config, utils)
assert.NoError(t, err)
assert.Equal(t, "gocover-cobertura", utils.ExecMockRunner.Calls[1].Exec)
assert.Equal(t, []string{"-ignore-gen-files"}, utils.ExecMockRunner.Calls[1].Params)
})
t.Run("error - cobertura installation", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
utils := newGolangBuildTestsUtils()
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"go install github.com/boumenot/gocover-cobertura": fmt.Errorf("install error")}
err := reportGolangTestCoverage(&config, utils)
assert.EqualError(t, err, "failed to install pre-requisite: install error")
})
t.Run("error - cobertura missing coverage file", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
utils := newGolangBuildTestsUtils()
err := reportGolangTestCoverage(&config, utils)
assert.Contains(t, fmt.Sprint(err), "failed to read coverage file")
})
t.Run("error - cobertura coversion", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
utils := newGolangBuildTestsUtils()
utils.AddFile(coverageFile, []byte("some content"))
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"gocover-cobertura -ignore-gen-files": fmt.Errorf("execution error")}
err := reportGolangTestCoverage(&config, utils)
assert.EqualError(t, err, "failed to convert coverage data to cobertura format: execution error")
})
t.Run("error - writing cobertura file", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{CoverageFormat: "cobertura", ExcludeGeneratedFromCoverage: true}
utils := newGolangBuildTestsUtils()
utils.AddFile(coverageFile, []byte("some content"))
utils.FileWriteError = fmt.Errorf("write failure")
err := reportGolangTestCoverage(&config, utils)
assert.EqualError(t, err, "failed to create cobertura coverage file: write failure")
})
t.Run("success - html", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
err := reportGolangTestCoverage(&config, utils)
assert.NoError(t, err)
assert.Equal(t, "go", utils.ExecMockRunner.Calls[0].Exec)
assert.Equal(t, []string{"tool", "cover", "-html", coverageFile, "-o", "coverage.html"}, utils.ExecMockRunner.Calls[0].Params)
})
t.Run("error - html", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.ExecMockRunner.ShouldFailOnCommand = map[string]error{"go tool cover -html cover.out -o coverage.html": fmt.Errorf("execution error")}
utils.AddFile(coverageFile, []byte("some content"))
err := reportGolangTestCoverage(&config, utils)
assert.EqualError(t, err, "failed to create html coverage file: execution error")
})
}
func TestPrepareLdflags(t *testing.T) {
t.Parallel()
dir, err := ioutil.TempDir("", "")
defer os.RemoveAll(dir) // clean up
assert.NoError(t, err, "Error when creating temp dir")
err = os.Mkdir(filepath.Join(dir, "commonPipelineEnvironment"), 0777)
assert.NoError(t, err, "Error when creating folder structure")
err = ioutil.WriteFile(filepath.Join(dir, "commonPipelineEnvironment", "artifactVersion"), []byte("1.2.3"), 0666)
assert.NoError(t, err, "Error when creating cpe file")
t.Run("success - default", func(t *testing.T) {
config := golangBuildOptions{LdflagsTemplate: "-X version={{ .CPE.artifactVersion }}"}
utils := newGolangBuildTestsUtils()
result, err := prepareLdflags(&config, utils, dir)
assert.NoError(t, err)
assert.Equal(t, "-X version=1.2.3", result)
})
t.Run("error - template parsing", func(t *testing.T) {
config := golangBuildOptions{LdflagsTemplate: "-X version={{ .CPE.artifactVersion "}
utils := newGolangBuildTestsUtils()
_, err := prepareLdflags(&config, utils, dir)
assert.Contains(t, fmt.Sprint(err), "failed to parse ldflagsTemplate")
})
}
func TestRunGolangBuildPerArchitecture(t *testing.T) {
t.Parallel()
t.Run("success - default", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
ldflags := ""
architecture := "linux,amd64"
err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
assert.NoError(t, err)
assert.Greater(t, len(utils.Env), 3)
assert.Contains(t, utils.Env, "CGO_ENABLED=0")
assert.Contains(t, utils.Env, "GOOS=linux")
assert.Contains(t, utils.Env, "GOARCH=amd64")
assert.Equal(t, utils.Calls[0].Exec, "go")
assert.Equal(t, utils.Calls[0].Params[0], "build")
})
t.Run("success - custom params", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{BuildFlags: []string{"--flag1", "val1", "--flag2", "val2"}, Output: "testBin", Packages: []string{"./test/.."}}
utils := newGolangBuildTestsUtils()
ldflags := "-X test=test"
architecture := "linux,amd64"
err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
assert.NoError(t, err)
assert.Contains(t, utils.Calls[0].Params, "-o")
assert.Contains(t, utils.Calls[0].Params, "testBin-linux.amd64")
assert.Contains(t, utils.Calls[0].Params, "./test/..")
assert.Contains(t, utils.Calls[0].Params, "-ldflags")
assert.Contains(t, utils.Calls[0].Params, "-X test=test")
})
t.Run("success - windows", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{Output: "testBin"}
utils := newGolangBuildTestsUtils()
ldflags := ""
architecture := "windows,amd64"
err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
assert.NoError(t, err)
assert.Contains(t, utils.Calls[0].Params, "-o")
assert.Contains(t, utils.Calls[0].Params, "testBin-windows.amd64.exe")
})
t.Run("execution error", func(t *testing.T) {
t.Parallel()
config := golangBuildOptions{}
utils := newGolangBuildTestsUtils()
utils.ShouldFailOnCommand = map[string]error{"go build": fmt.Errorf("execution error")}
ldflags := ""
architecture := "linux,amd64"
err := runGolangBuildPerArchitecture(&config, utils, ldflags, architecture)
assert.EqualError(t, err, "failed to run build for linux.amd64: execution error")
})
}