You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-09-16 09:26:22 +02:00
@@ -7,8 +7,6 @@ import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/pkg/errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
@@ -19,6 +17,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/magiconair/properties/assert"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
)
|
||||
@@ -42,6 +43,7 @@ type IntegrationTestDockerExecRunnerBundle struct {
|
||||
Environment map[string]string
|
||||
Setup []string
|
||||
Network string
|
||||
ExecNoLogin bool
|
||||
}
|
||||
|
||||
// IntegrationTestDockerExecRunner keeps the state of an instance of a docker runner
|
||||
@@ -56,6 +58,7 @@ type IntegrationTestDockerExecRunner struct {
|
||||
Setup []string
|
||||
Network string
|
||||
ContainerName string
|
||||
ExecNoLogin bool
|
||||
}
|
||||
|
||||
func givenThisContainer(t *testing.T, bundle IntegrationTestDockerExecRunnerBundle) IntegrationTestDockerExecRunner {
|
||||
@@ -70,6 +73,7 @@ func givenThisContainer(t *testing.T, bundle IntegrationTestDockerExecRunnerBund
|
||||
Environment: bundle.Environment,
|
||||
Setup: bundle.Setup,
|
||||
Network: bundle.Network,
|
||||
ExecNoLogin: bundle.ExecNoLogin,
|
||||
ContainerName: containerName,
|
||||
}
|
||||
|
||||
@@ -173,7 +177,13 @@ func setupPiperBinary(t *testing.T, testRunner IntegrationTestDockerExecRunner,
|
||||
}
|
||||
|
||||
func (d *IntegrationTestDockerExecRunner) whenRunningPiperCommand(command string, parameters ...string) error {
|
||||
args := []string{"exec", "--workdir", "/project", d.ContainerName, "/bin/sh", "-l", "/piper-wrapper", "/piper", command}
|
||||
args := []string{"exec", "--workdir", "/project", d.ContainerName, "/bin/sh"}
|
||||
|
||||
if !d.ExecNoLogin {
|
||||
args = append(args, "-l")
|
||||
}
|
||||
|
||||
args = append(args, "/piper-wrapper", "/piper", command)
|
||||
args = append(args, parameters...)
|
||||
err := d.Runner.RunExecutable("docker", args...)
|
||||
if err != nil {
|
||||
@@ -184,10 +194,27 @@ func (d *IntegrationTestDockerExecRunner) whenRunningPiperCommand(command string
|
||||
}
|
||||
|
||||
func (d *IntegrationTestDockerExecRunner) runScriptInsideContainer(script string) error {
|
||||
args := []string{"exec", "--workdir", "/project", d.ContainerName, "/bin/sh", "-l", "-c", script}
|
||||
args := []string{"exec", "--workdir", "/project", d.ContainerName, "/bin/sh"}
|
||||
|
||||
if !d.ExecNoLogin {
|
||||
args = append(args, "-l")
|
||||
}
|
||||
|
||||
args = append(args, "-c", script)
|
||||
return d.Runner.RunExecutable("docker", args...)
|
||||
}
|
||||
|
||||
func (d *IntegrationTestDockerExecRunner) assertHasNoOutput(t *testing.T, want string) {
|
||||
buffer, err := d.getPiperOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get log output of container %s", d.ContainerName)
|
||||
}
|
||||
|
||||
if strings.Contains(buffer.String(), want) {
|
||||
assert.Equal(t, buffer.String(), want, "Unexpected command output")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *IntegrationTestDockerExecRunner) assertHasOutput(t *testing.T, want string) {
|
||||
buffer, err := d.getPiperOutput()
|
||||
if err != nil {
|
||||
|
@@ -6,157 +6,92 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/testcontainers/testcontainers-go"
|
||||
)
|
||||
|
||||
// In this test the piper command golangBuild performs testing, BOM file creation and building a project with entry point in the cmd/server/server.go
|
||||
// The configuration for golangBuild can be found in testdata/TestGolangIntegration/golang-project1/.pipeline/config.yml
|
||||
func TestGolangBuild_Project1(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
assert.NoError(t, err, "Getting current working directory failed.")
|
||||
pwd = filepath.Dir(pwd)
|
||||
|
||||
// using custom createTmpDir function to avoid issues with symlinks on Docker for Mac
|
||||
tempDir, err := createTmpDir("")
|
||||
defer os.RemoveAll(tempDir) // clean up
|
||||
assert.NoError(t, err, "Error when creating temp dir")
|
||||
|
||||
err = copyDir(filepath.Join(pwd, "integration", "testdata", "TestGolangIntegration", "golang-project1"), tempDir)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to copy test project.")
|
||||
}
|
||||
|
||||
//workaround to use test script util it is possible to set workdir for Exec call
|
||||
testScript := fmt.Sprintf(`#!/bin/sh
|
||||
cd /test
|
||||
/piperbin/piper golangBuild >test-log.txt 2>&1
|
||||
`)
|
||||
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
|
||||
|
||||
reqNode := testcontainers.ContainerRequest{
|
||||
Image: "golang:1",
|
||||
Cmd: []string{"tail", "-f"},
|
||||
BindMounts: map[string]string{
|
||||
pwd: "/piperbin",
|
||||
tempDir: "/test",
|
||||
},
|
||||
}
|
||||
|
||||
nodeContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: reqNode,
|
||||
Started: true,
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "golang:1",
|
||||
TestDir: []string{"testdata", "TestGolangIntegration", "golang-project1"},
|
||||
ExecNoLogin: true,
|
||||
})
|
||||
|
||||
code, err := nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
|
||||
err := container.whenRunningPiperCommand("golangBuild")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, code)
|
||||
|
||||
content, err := ioutil.ReadFile(filepath.Join(tempDir, "/test-log.txt"))
|
||||
if err != nil {
|
||||
t.Fatal("Could not read test-log.txt.", err)
|
||||
}
|
||||
output := string(content)
|
||||
assert.Contains(t, output, "info golangBuild - running command: go install gotest.tools/gotestsum@latest")
|
||||
assert.Contains(t, output, "info golangBuild - running command: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest")
|
||||
assert.Contains(t, output, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
assert.Contains(t, output, "info golangBuild - DONE 8 tests")
|
||||
assert.Contains(t, output, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
assert.Contains(t, output, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
assert.Contains(t, output, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
assert.Contains(t, output, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64 cmd/server/server.go")
|
||||
assert.Contains(t, output, "info golangBuild - SUCCESS")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go install gotest.tools/gotestsum@latest")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - DONE 8 tests")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64 cmd/server/server.go")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
|
||||
//workaround to use test script util it is possible to set workdir for Exec call
|
||||
testScript = fmt.Sprintf(`#!/bin/sh
|
||||
cd /test
|
||||
ls -l >files-list.txt 2>&1
|
||||
`)
|
||||
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
|
||||
container.assertHasFile(t, "/project/TEST-go.xml")
|
||||
container.assertHasFile(t, "/project/TEST-integration.xml")
|
||||
container.assertHasFile(t, "/project/bom.xml")
|
||||
container.assertHasFile(t, "/project/cover.out")
|
||||
container.assertHasFile(t, "/project/coverage.html")
|
||||
container.assertHasFile(t, "/project/golang-app-linux.amd64")
|
||||
}
|
||||
|
||||
code, err = nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
|
||||
// This test extends TestGolangBuild_Project1 with multi-package build
|
||||
func TestGolangBuild_Project1_Multipackage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "golang:1",
|
||||
TestDir: []string{"testdata", "TestGolangIntegration", "golang-project1"},
|
||||
ExecNoLogin: true,
|
||||
})
|
||||
err := container.whenRunningPiperCommand("golangBuild", "--packages", "github.com/example/golang-app/cmd/server,github.com/example/golang-app/cmd/helper")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, code)
|
||||
|
||||
content, err = ioutil.ReadFile(filepath.Join(tempDir, "/files-list.txt"))
|
||||
if err != nil {
|
||||
t.Fatal("Could not read files-list.txt.", err)
|
||||
}
|
||||
output = string(content)
|
||||
assert.Contains(t, output, "TEST-go.xml")
|
||||
assert.Contains(t, output, "TEST-integration.xml")
|
||||
assert.Contains(t, output, "bom.xml")
|
||||
assert.Contains(t, output, "cover.out")
|
||||
assert.Contains(t, output, "coverage.html")
|
||||
assert.Contains(t, output, "golang-app-linux.amd64")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go install gotest.tools/gotestsum@latest")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - DONE 8 tests")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go build -trimpath -o golang-app-linux-amd64/ github.com/example/golang-app/cmd/server github.com/example/golang-app/cmd/helper")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
|
||||
container.assertHasFile(t, "/project/TEST-go.xml")
|
||||
container.assertHasFile(t, "/project/TEST-integration.xml")
|
||||
container.assertHasFile(t, "/project/bom.xml")
|
||||
container.assertHasFile(t, "/project/cover.out")
|
||||
container.assertHasFile(t, "/project/coverage.html")
|
||||
container.assertHasFile(t, "/project/golang-app-linux-amd64/server")
|
||||
container.assertHasFile(t, "/project/golang-app-linux-amd64/helper")
|
||||
}
|
||||
|
||||
// In this test, the piper golangBuild command only builds the project with the entry point at the project root.
|
||||
// The configuration for golangBuild can be found in testdata/TestGolangIntegration/golang-project2/.pipeline/config.yml
|
||||
func TestGolangBuild_Project2(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
assert.NoError(t, err, "Getting current working directory failed.")
|
||||
pwd = filepath.Dir(pwd)
|
||||
|
||||
// using custom createTmpDir function to avoid issues with symlinks on Docker for Mac
|
||||
tempDir, err := createTmpDir("")
|
||||
defer os.RemoveAll(tempDir) // clean up
|
||||
assert.NoError(t, err, "Error when creating temp dir")
|
||||
|
||||
err = copyDir(filepath.Join(pwd, "integration", "testdata", "TestGolangIntegration", "golang-project2"), tempDir)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to copy test project.")
|
||||
}
|
||||
|
||||
//workaround to use test script util it is possible to set workdir for Exec call
|
||||
testScript := fmt.Sprintf(`#!/bin/sh
|
||||
cd /test
|
||||
/piperbin/piper golangBuild >test-log.txt 2>&1
|
||||
`)
|
||||
ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700)
|
||||
|
||||
reqNode := testcontainers.ContainerRequest{
|
||||
Image: "golang:1",
|
||||
Cmd: []string{"tail", "-f"},
|
||||
BindMounts: map[string]string{
|
||||
pwd: "/piperbin",
|
||||
tempDir: "/test",
|
||||
},
|
||||
}
|
||||
|
||||
nodeContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
|
||||
ContainerRequest: reqNode,
|
||||
Started: true,
|
||||
container := givenThisContainer(t, IntegrationTestDockerExecRunnerBundle{
|
||||
Image: "golang:1",
|
||||
TestDir: []string{"testdata", "TestGolangIntegration", "golang-project2"},
|
||||
ExecNoLogin: true,
|
||||
})
|
||||
|
||||
code, err := nodeContainer.Exec(ctx, []string{"sh", "/test/runPiper.sh"})
|
||||
err := container.whenRunningPiperCommand("golangBuild")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0, code)
|
||||
|
||||
content, err := ioutil.ReadFile(filepath.Join(tempDir, "/test-log.txt"))
|
||||
if err != nil {
|
||||
t.Fatal("Could not read test-log.txt.", err)
|
||||
}
|
||||
output := string(content)
|
||||
assert.NotContains(t, output, "info golangBuild - running command: go install gotest.tools/gotestsum@latest")
|
||||
assert.NotContains(t, output, "info golangBuild - running command: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest")
|
||||
assert.NotContains(t, output, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
assert.NotContains(t, output, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
assert.NotContains(t, output, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
assert.NotContains(t, output, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
assert.Contains(t, output, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64")
|
||||
assert.Contains(t, output, "info golangBuild - SUCCESS")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: go install gotest.tools/gotestsum@latest")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@latest")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-go.xml -- -coverprofile=cover.out ./...")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: go tool cover -html cover.out -o coverage.html")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: gotestsum --junitfile TEST-integration.xml -- -tags=integration ./...")
|
||||
container.assertHasNoOutput(t, "info golangBuild - running command: cyclonedx-gomod mod -licenses -test -output bom.xml")
|
||||
container.assertHasOutput(t, "info golangBuild - running command: go build -trimpath -o golang-app-linux.amd64")
|
||||
container.assertHasOutput(t, "info golangBuild - SUCCESS")
|
||||
}
|
||||
|
34
integration/testdata/TestGolangIntegration/golang-project1/cmd/helper/helper.go
vendored
Normal file
34
integration/testdata/TestGolangIntegration/golang-project1/cmd/helper/helper.go
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/example/golang-app/pkg/http/handlers"
|
||||
"github.com/example/golang-app/pkg/http/middlewares"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultServerAddress = "0.0.0.0"
|
||||
defaultServerPort = "8080"
|
||||
)
|
||||
|
||||
func main() {
|
||||
serverAddress := flag.String("server.address", defaultServerAddress, "IP address of the HTTP server")
|
||||
serverPort := flag.String("server.port", defaultServerPort, "Port of the HTTP server")
|
||||
flag.Parse()
|
||||
|
||||
router := mux.NewRouter()
|
||||
|
||||
router.HandleFunc("/hello/{who}", middlewares.MultipleMiddleware(handlers.HelloHandler,
|
||||
middlewares.LoggerMiddleware, middlewares.RecoverMiddleware)).Methods("GET", "POST")
|
||||
router.HandleFunc("/panic", middlewares.MultipleMiddleware(handlers.ThrowPanicHandler,
|
||||
middlewares.LoggerMiddleware, middlewares.RecoverMiddleware)).Methods("GET", "POST")
|
||||
http.Handle("/", router)
|
||||
|
||||
fmt.Printf("Server address: %s:%s\n", *serverAddress, *serverPort)
|
||||
fmt.Println("Server is listening...")
|
||||
http.ListenAndServe(fmt.Sprintf("%s:%s", *serverAddress, *serverPort), nil)
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
module github.com/example/golang-app
|
||||
|
||||
go 1.15
|
||||
go 1.18
|
||||
|
||||
require github.com/gorilla/mux v1.8.0
|
||||
|
@@ -1,3 +1,3 @@
|
||||
module github.com/example/golang-app
|
||||
|
||||
go 1.15
|
||||
go 1.18
|
||||
|
Reference in New Issue
Block a user