func/test/common/cmd.go

136 lines
2.8 KiB
Go

package common
import (
"bytes"
"os"
"os/exec"
"strings"
"testing"
)
type TestExecCmd struct {
// binary to invoke
// Example: "func", "kn", "kubectl", "/usr/bin/sh"
Binary string
// Binary args to append before actual args. Examples:
// when 'kn' binary binaryArgs should be ["func"]
BinaryArgs []string
// Run commands from Dir
SourceDir string
// Indicates shell should dump command line args during execution
ShouldDumpCmdLine bool
// Indicates shell should dump
ShouldDumpOnSuccess bool
// Fail Test on Error
ShouldFailOnError bool
// Environment variable to be used with the command
Env []string
// Optional function to be used to dump stdout command results
DumpLogger func(out string)
// Access to Running or Latest command
ExecCmd *exec.Cmd
// Function to be executed while the command is running. This function is executed only once
OnWaitCallback func(stdout *bytes.Buffer)
// Function to be executed after the command is completed (before error and cmd stdout logic is executed)
OnFinishCallback func(result *TestExecCmdResult)
T *testing.T
}
// TestExecCmdResult stored command result
type TestExecCmdResult struct {
Out string
Error error
}
func (f *TestExecCmd) WithEnv(envKey string, envValue string) *TestExecCmd {
env := envKey + "=" + envValue
f.Env = append(f.Env, env)
return f
}
func (f *TestExecCmd) FromDir(dir string) *TestExecCmd {
f.SourceDir = dir
return f
}
func (f *TestExecCmd) Run(oneArgs string) TestExecCmdResult {
args := strings.Split(oneArgs, " ")
return f.Exec(args...)
}
// Exec invokes go exec library and runs a shell command combining the binary args with args from method signature
func (f *TestExecCmd) Exec(args ...string) TestExecCmdResult {
finalArgs := f.BinaryArgs
if finalArgs == nil {
finalArgs = args
} else if args != nil {
finalArgs = append(finalArgs, args...)
}
if f.ShouldDumpCmdLine {
f.T.Log(f.Binary, strings.Join(finalArgs, " "))
}
var out bytes.Buffer
cmd := exec.Command(f.Binary, finalArgs...)
cmd.Stderr = &out
cmd.Stdout = &out
f.ExecCmd = cmd
if f.SourceDir != "" {
cmd.Dir = f.SourceDir
}
cmd.Env = append(os.Environ(), f.Env...)
// Start command execution
err := cmd.Start()
if err == nil {
if f.OnWaitCallback != nil {
fn := f.OnWaitCallback
f.OnWaitCallback = nil
go fn(&out)
}
// Wait for command to complete
err = cmd.Wait()
}
result := TestExecCmdResult{
Out: out.String(),
Error: err,
}
if f.OnFinishCallback != nil {
f.OnFinishCallback(&result)
}
if err == nil && f.ShouldDumpOnSuccess {
if result.Out != "" {
if f.DumpLogger != nil {
f.DumpLogger(result.Out)
} else {
f.T.Logf("%v", result.Out)
}
}
}
if err != nil {
f.T.Log(result.Out)
f.T.Log(err.Error())
if f.ShouldFailOnError {
f.T.Fail()
}
}
return result
}