1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-07-03 00:57:26 +02:00

Rewrite mta IT using docker cli (#1819)

This change addresses some issues of the testcontainer based testing approach (much repeated code, API not on the right abstraction level). It introduces new methods that make use of the docker cli, and rewrites the mta tests using this method.


Co-authored-by: Stephan Aßmus <stephan.assmus@sap.com>
This commit is contained in:
Florian Wilhelm
2020-07-20 18:07:08 +02:00
committed by GitHub
parent 94dba13fef
commit 219327a427
3 changed files with 179 additions and 175 deletions

View File

@ -0,0 +1,129 @@
// +build integration
package main
import (
"bytes"
"github.com/SAP/jenkins-library/pkg/command"
"github.com/SAP/jenkins-library/pkg/log"
"io/ioutil"
"math/rand"
"os"
"path"
"strconv"
"strings"
"testing"
"time"
)
// IntegrationTestDockerExecRunner keeps the state of an instance of a docker runner
type IntegrationTestDockerExecRunner struct {
// Runner is the ExecRunner to which all executions are forwarded in the end.
Runner command.Command
Image string
User string
TestDir []string
Mounts map[string]string
Environment map[string]string
Setup []string
ContainerName string
}
// IntegrationTestDockerExecRunnerBundle is used to construct an instance of IntegrationTestDockerExecRunner
type IntegrationTestDockerExecRunnerBundle struct {
Image string
User string
TestDir []string
Mounts map[string]string
Environment map[string]string
Setup []string
}
func givenThisContainer(t *testing.T, bundle IntegrationTestDockerExecRunnerBundle) IntegrationTestDockerExecRunner {
runner := command.Command{}
// Generate a random container name so we can start a new one for each test method
// We don't rely on docker's random name generator for two reasons
// First, it is easier to save the name here compared to getting it from stdout
// Second, the common prefix allows batch stopping/deleting of containers if so desired
// The test code will not automatically delete containers as they might be useful for debugging
var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
containerName := "piper-integration-test-" + strconv.Itoa(seededRand.Int())
testRunner := IntegrationTestDockerExecRunner{
Runner: runner,
Image: bundle.Image,
User: bundle.User,
Mounts: bundle.Mounts,
Setup: bundle.Setup,
ContainerName: containerName,
}
//todo ensure it is a linux binary
wd, _ := os.Getwd()
localPiper := path.Join(wd, "..", "piper")
if localPiper == "" {
t.Fatal("Could not locate piper binary to test")
}
projectDir := path.Join(wd, path.Join(bundle.TestDir...))
// 1. Copy test files to a temp dir in order to avoid non-repeatable test executions because of changed state
// 2. Don't remove the temp dir to allow investigation of failed tests. Maybe add an option for cleaning it later?
tempDir, err := ioutil.TempDir("", "piper-integration-test")
if err != nil {
t.Fatal(err)
}
err = copyDir(projectDir, tempDir)
if err != nil {
t.Fatalf("")
}
//todo mounts
//todo env (secrets)
err = testRunner.Runner.RunExecutable("docker", "run", "-d", "-u="+testRunner.User,
"-v", localPiper+":/piper", "-v", tempDir+":/project",
"--name="+testRunner.ContainerName,
testRunner.Image,
"sleep", "2000")
if err != nil {
t.Fatalf("Starting test container has failed %s", err)
}
for _, scriptLine := range testRunner.Setup {
err := testRunner.Runner.RunExecutable("docker", "exec", testRunner.ContainerName, "/bin/bash", "-c", scriptLine)
if err != nil {
t.Fatalf("Running setup script in test container has failed %s", err)
}
}
err = testRunner.Runner.RunExecutable("docker", "cp", "piper-command-wrapper.sh", testRunner.ContainerName+":/piper-wrapper")
if err != nil {
t.Fatalf("Copying command wrapper to container has failed %s", err)
}
err = testRunner.Runner.RunExecutable("docker", "exec", testRunner.ContainerName, "chmod", "+x", "/piper-wrapper")
if err != nil {
t.Fatalf("Making command wrapper in container executable has failed %s", err)
}
return testRunner
}
func (d *IntegrationTestDockerExecRunner) whenRunningPiperCommand(command string, parameters ...string) error {
args := []string{"exec", "--workdir", "/project", d.ContainerName, "/bin/bash", "/piper-wrapper", "/piper", command}
args = append(args, parameters...)
return d.Runner.RunExecutable("docker", args...)
}
func (d *IntegrationTestDockerExecRunner) assertHasOutput(t *testing.T, want string) {
buffer := new(bytes.Buffer)
d.Runner.Stdout(buffer)
err := d.Runner.RunExecutable("docker", "exec", d.ContainerName, "cat", "/tmp/test-log.txt")
d.Runner.Stdout(log.Writer())
if err != nil {
t.Fatalf("Failed to get log output of container %s", d.ContainerName)
}
if !strings.Contains(buffer.String(), want) {
t.Fatalf("Assertion has failed. Expected output %s in command output.\n%s", want, buffer.String())
}
}