2019-10-25 14:58:59 +02:00
|
|
|
package command
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2020-03-03 12:15:24 +02:00
|
|
|
"strings"
|
2019-10-25 14:58:59 +02:00
|
|
|
"testing"
|
2020-06-24 10:04:05 +02:00
|
|
|
|
|
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
|
|
"github.com/stretchr/testify/assert"
|
2019-10-25 14:58:59 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
//based on https://golang.org/src/os/exec/exec_test.go
|
|
|
|
func helperCommand(command string, s ...string) (cmd *exec.Cmd) {
|
|
|
|
cs := []string{"-test.run=TestHelperProcess", "--", command}
|
|
|
|
cs = append(cs, s...)
|
|
|
|
cmd = exec.Command(os.Args[0], cs...)
|
|
|
|
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestShellRun(t *testing.T) {
|
|
|
|
|
|
|
|
t.Run("test shell", func(t *testing.T) {
|
|
|
|
ExecCommand = helperCommand
|
|
|
|
defer func() { ExecCommand = exec.Command }()
|
|
|
|
o := new(bytes.Buffer)
|
|
|
|
e := new(bytes.Buffer)
|
|
|
|
|
2019-11-19 15:29:53 +02:00
|
|
|
s := Command{stdout: o, stderr: e}
|
2019-10-25 14:58:59 +02:00
|
|
|
s.RunShell("/bin/bash", "myScript")
|
|
|
|
|
|
|
|
t.Run("success case", func(t *testing.T) {
|
|
|
|
t.Run("stdin-stdout", func(t *testing.T) {
|
|
|
|
expectedOut := "Stdout: command /bin/bash - Stdin: myScript\n"
|
|
|
|
if oStr := o.String(); oStr != expectedOut {
|
|
|
|
t.Errorf("expected: %v got: %v", expectedOut, oStr)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("stderr", func(t *testing.T) {
|
|
|
|
expectedErr := "Stderr: command /bin/bash\n"
|
|
|
|
if eStr := e.String(); eStr != expectedErr {
|
|
|
|
t.Errorf("expected: %v got: %v", expectedErr, eStr)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestExecutableRun(t *testing.T) {
|
|
|
|
|
2020-06-30 12:57:27 +02:00
|
|
|
t.Run("test executable", func(t *testing.T) {
|
2019-10-25 14:58:59 +02:00
|
|
|
ExecCommand = helperCommand
|
|
|
|
defer func() { ExecCommand = exec.Command }()
|
2020-03-03 12:15:24 +02:00
|
|
|
stdout := new(bytes.Buffer)
|
|
|
|
stderr := new(bytes.Buffer)
|
2019-10-25 14:58:59 +02:00
|
|
|
|
|
|
|
t.Run("success case", func(t *testing.T) {
|
2020-06-24 10:04:05 +02:00
|
|
|
ex := Command{stdout: stdout, stderr: stderr}
|
|
|
|
ex.RunExecutable("echo", []string{"foo bar", "baz"}...)
|
|
|
|
|
2020-06-30 12:57:27 +02:00
|
|
|
assert.Equal(t, 0, ex.GetExitCode())
|
|
|
|
|
2019-10-25 14:58:59 +02:00
|
|
|
t.Run("stdin", func(t *testing.T) {
|
|
|
|
expectedOut := "foo bar baz\n"
|
2020-03-03 12:15:24 +02:00
|
|
|
if oStr := stdout.String(); oStr != expectedOut {
|
2019-10-25 14:58:59 +02:00
|
|
|
t.Errorf("expected: %v got: %v", expectedOut, oStr)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("stderr", func(t *testing.T) {
|
|
|
|
expectedErr := "Stderr: command echo\n"
|
2020-03-03 12:15:24 +02:00
|
|
|
if eStr := stderr.String(); eStr != expectedErr {
|
2019-10-25 14:58:59 +02:00
|
|
|
t.Errorf("expected: %v got: %v", expectedErr, eStr)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
2020-06-24 10:04:05 +02:00
|
|
|
|
|
|
|
t.Run("success case - log parsing", func(t *testing.T) {
|
|
|
|
log.SetErrorCategory(log.ErrorUndefined)
|
|
|
|
ex := Command{stdout: stdout, stderr: stderr, ErrorCategoryMapping: map[string][]string{"config": {"command echo"}}}
|
|
|
|
ex.RunExecutable("echo", []string{"foo bar", "baz"}...)
|
|
|
|
assert.Equal(t, log.ErrorConfiguration, log.GetErrorCategory())
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("success case - log parsing long line", func(t *testing.T) {
|
|
|
|
log.SetErrorCategory(log.ErrorUndefined)
|
|
|
|
ex := Command{stdout: stdout, stderr: stderr, ErrorCategoryMapping: map[string][]string{"config": {"aaaa"}}}
|
|
|
|
ex.RunExecutable("long", []string{"foo bar", "baz"}...)
|
|
|
|
assert.Equal(t, log.ErrorUndefined, log.GetErrorCategory())
|
|
|
|
})
|
|
|
|
|
|
|
|
log.SetErrorCategory(log.ErrorUndefined)
|
2019-10-25 14:58:59 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-03-03 12:15:24 +02:00
|
|
|
func TestEnvironmentVariables(t *testing.T) {
|
|
|
|
|
|
|
|
ExecCommand = helperCommand
|
|
|
|
defer func() { ExecCommand = exec.Command }()
|
|
|
|
|
|
|
|
stdout := new(bytes.Buffer)
|
|
|
|
stderr := new(bytes.Buffer)
|
|
|
|
|
|
|
|
ex := Command{stdout: stdout, stderr: stderr}
|
|
|
|
|
|
|
|
// helperCommand function replaces the full environment with one single entry
|
|
|
|
// (GO_WANT_HELPER_PROCESS), hence there is no need for checking if the DEBUG
|
|
|
|
// environment variable already exists in the set of environment variables for the
|
|
|
|
// current process.
|
|
|
|
ex.SetEnv([]string{"DEBUG=true"})
|
|
|
|
ex.RunExecutable("env")
|
|
|
|
|
|
|
|
oStr := stdout.String()
|
|
|
|
|
|
|
|
if !strings.Contains(oStr, "DEBUG=true") {
|
|
|
|
t.Errorf("expected Environment variable not found")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 14:58:59 +02:00
|
|
|
func TestPrepareOut(t *testing.T) {
|
|
|
|
|
|
|
|
t.Run("os", func(t *testing.T) {
|
|
|
|
s := Command{}
|
2020-06-24 10:04:05 +02:00
|
|
|
s.prepareOut()
|
2019-10-25 14:58:59 +02:00
|
|
|
|
2020-06-24 10:04:05 +02:00
|
|
|
if s.stdout != os.Stdout {
|
2019-10-25 14:58:59 +02:00
|
|
|
t.Errorf("expected out to be os.Stdout")
|
|
|
|
}
|
|
|
|
|
2020-06-24 10:04:05 +02:00
|
|
|
if s.stderr != os.Stderr {
|
2019-10-25 14:58:59 +02:00
|
|
|
t.Errorf("expected err to be os.Stderr")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("custom", func(t *testing.T) {
|
|
|
|
o := bytes.NewBufferString("")
|
|
|
|
e := bytes.NewBufferString("")
|
2019-11-19 15:29:53 +02:00
|
|
|
s := Command{stdout: o, stderr: e}
|
2020-06-24 10:04:05 +02:00
|
|
|
s.prepareOut()
|
2019-10-25 14:58:59 +02:00
|
|
|
|
|
|
|
expectOut := "Test out"
|
|
|
|
expectErr := "Test err"
|
2020-06-24 10:04:05 +02:00
|
|
|
s.stdout.Write([]byte(expectOut))
|
|
|
|
s.stderr.Write([]byte(expectErr))
|
2019-10-25 14:58:59 +02:00
|
|
|
|
|
|
|
t.Run("out", func(t *testing.T) {
|
|
|
|
if o.String() != expectOut {
|
|
|
|
t.Errorf("expected: %v got: %v", expectOut, o.String())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("err", func(t *testing.T) {
|
|
|
|
if e.String() != expectErr {
|
|
|
|
t.Errorf("expected: %v got: %v", expectErr, e.String())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-06-24 10:04:05 +02:00
|
|
|
func TestParseConsoleErrors(t *testing.T) {
|
|
|
|
cmd := Command{
|
|
|
|
ErrorCategoryMapping: map[string][]string{
|
|
|
|
"config": {"configuration error 1", "configuration error 2"},
|
|
|
|
"build": {"build failed"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
tt := []struct {
|
|
|
|
consoleLine string
|
|
|
|
expectedCategory log.ErrorCategory
|
|
|
|
}{
|
|
|
|
{consoleLine: "this is an error", expectedCategory: log.ErrorUndefined},
|
|
|
|
{consoleLine: "this is configuration error 2", expectedCategory: log.ErrorConfiguration},
|
|
|
|
{consoleLine: "the build failed", expectedCategory: log.ErrorBuild},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tt {
|
|
|
|
log.SetErrorCategory(log.ErrorUndefined)
|
|
|
|
cmd.parseConsoleErrors(test.consoleLine)
|
|
|
|
assert.Equal(t, test.expectedCategory, log.GetErrorCategory(), test.consoleLine)
|
|
|
|
}
|
|
|
|
log.SetErrorCategory(log.ErrorUndefined)
|
|
|
|
}
|
|
|
|
|
2020-06-30 10:48:30 +02:00
|
|
|
func TestMatchPattern(t *testing.T) {
|
|
|
|
tt := []struct {
|
|
|
|
text string
|
|
|
|
pattern string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{text: "", pattern: "", expected: true},
|
|
|
|
{text: "simple test", pattern: "", expected: false},
|
|
|
|
{text: "simple test", pattern: "no", expected: false},
|
|
|
|
{text: "simple test", pattern: "simple", expected: true},
|
|
|
|
{text: "simple test", pattern: "test", expected: true},
|
|
|
|
{text: "advanced pattern test", pattern: "advanced * test", expected: true},
|
|
|
|
{text: "advanced pattern failed", pattern: "advanced * test", expected: false},
|
|
|
|
{text: "advanced pattern with multiple placeholders", pattern: "advanced * with * placeholders", expected: true},
|
|
|
|
{text: "advanced pattern lacking multiple placeholders", pattern: "advanced * with * placeholders", expected: false},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tt {
|
|
|
|
assert.Equalf(t, test.expected, matchPattern(test.text, test.pattern), test.text)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-25 14:58:59 +02:00
|
|
|
func TestCmdPipes(t *testing.T) {
|
|
|
|
cmd := helperCommand("echo", "foo bar", "baz")
|
|
|
|
defer func() { ExecCommand = exec.Command }()
|
|
|
|
|
|
|
|
t.Run("success case", func(t *testing.T) {
|
|
|
|
o, e, err := cmdPipes(cmd)
|
|
|
|
t.Run("no error", func(t *testing.T) {
|
|
|
|
if err != nil {
|
2020-09-24 07:41:06 +02:00
|
|
|
t.Errorf("error occurred but no error expected")
|
2019-10-25 14:58:59 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("out pipe", func(t *testing.T) {
|
|
|
|
if o == nil {
|
|
|
|
t.Errorf("no pipe received")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("err pipe", func(t *testing.T) {
|
|
|
|
if e == nil {
|
|
|
|
t.Errorf("no pipe received")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
//based on https://golang.org/src/os/exec/exec_test.go
|
|
|
|
//this is not directly executed
|
|
|
|
func TestHelperProcess(*testing.T) {
|
2020-03-03 12:15:24 +02:00
|
|
|
|
2019-10-25 14:58:59 +02:00
|
|
|
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer os.Exit(0)
|
|
|
|
|
|
|
|
args := os.Args
|
|
|
|
for len(args) > 0 {
|
|
|
|
if args[0] == "--" {
|
|
|
|
args = args[1:]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
args = args[1:]
|
|
|
|
}
|
|
|
|
if len(args) == 0 {
|
|
|
|
fmt.Fprintf(os.Stderr, "No command\n")
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd, args := args[0], args[1:]
|
|
|
|
switch cmd {
|
|
|
|
case "/bin/bash":
|
|
|
|
o, _ := ioutil.ReadAll(os.Stdin)
|
|
|
|
fmt.Fprintf(os.Stdout, "Stdout: command %v - Stdin: %v\n", cmd, string(o))
|
|
|
|
fmt.Fprintf(os.Stderr, "Stderr: command %v\n", cmd)
|
|
|
|
case "echo":
|
|
|
|
iargs := []interface{}{}
|
|
|
|
for _, s := range args {
|
|
|
|
iargs = append(iargs, s)
|
|
|
|
}
|
|
|
|
fmt.Println(iargs...)
|
|
|
|
fmt.Fprintf(os.Stderr, "Stderr: command %v\n", cmd)
|
2020-03-03 12:15:24 +02:00
|
|
|
case "env":
|
|
|
|
for _, e := range os.Environ() {
|
|
|
|
fmt.Println(e)
|
|
|
|
}
|
2020-06-24 10:04:05 +02:00
|
|
|
case "long":
|
|
|
|
b := []byte("a")
|
|
|
|
size := 64000
|
|
|
|
b = bytes.Repeat(b, size)
|
|
|
|
|
|
|
|
fmt.Fprint(os.Stderr, b)
|
2019-10-25 14:58:59 +02:00
|
|
|
default:
|
|
|
|
fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
|
|
|
|
os.Exit(2)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|