1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-09-16 09:26:22 +02:00

added integration tests

Co-authored-by: Gareth Evans <g.evans@sap.com>
This commit is contained in:
Pavel Busko
2022-04-14 14:10:32 +02:00
committed by Pavel Busko
parent 74b6b09609
commit 4b6c6e423c
5 changed files with 128 additions and 132 deletions

View File

@@ -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 {

View File

@@ -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")
}

View 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)
}

View File

@@ -1,5 +1,5 @@
module github.com/example/golang-app
go 1.15
go 1.18
require github.com/gorilla/mux v1.8.0

View File

@@ -1,3 +1,3 @@
module github.com/example/golang-app
go 1.15
go 1.18