1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
package integration
import (
"bytes"
"fmt"
"io"
"os/exec"
"regexp"
"strings"
"testing"
"github.com/ThomasRooney/gexpect"
"github.com/smallstep/assert"
)
// CleanOutput returns the output from the cursor character.
func CleanOutput(str string) string {
if i := strings.Index(str, "?25h"); i > 0 {
return str[i+4:]
}
return str
}
// Command executes a shell command.
func Command(command string) *exec.Cmd {
return exec.Command("sh", "-c", command)
}
// ExitError converts an error to an exec.ExitError.
func ExitError(err error) (*exec.ExitError, bool) {
v, ok := err.(*exec.ExitError)
return v, ok
}
// Output executes a shell command and returns output from stdout.
func Output(command string) ([]byte, error) {
return Command(command).Output()
}
// CombinedOutput executes a shell command and returns combined output from
// stdout and stderr.
func CombinedOutput(command string) ([]byte, error) {
return Command(command).CombinedOutput()
}
// WithStdin executes a shell command with a provided reader used for stdin.
func WithStdin(command string, r io.Reader) ([]byte, error) {
cmd := Command(command)
cmd.Stdin = r
return cmd.Output()
}
// CLICommand repreents a command-line command to execute.
type CLICommand struct {
command string
arguments string
flags map[string]string
stdin io.Reader
}
// CLIOutput represents the output from executing a CLICommand.
// nolint:unused
type CLIOutput struct {
stdout string
stderr string
combined string
}
// NewCLICommand generates a new CLICommand.
func NewCLICommand() CLICommand {
return CLICommand{"", "", make(map[string]string), nil}
}
func (c CLICommand) setFlag(flag, value string) CLICommand {
flags := make(map[string]string)
for k, v := range c.flags {
flags[k] = v
}
flags[flag] = value
return CLICommand{c.command, c.arguments, flags, c.stdin}
}
func (c CLICommand) setCommand(command string) CLICommand {
return CLICommand{command, c.arguments, c.flags, c.stdin}
}
func (c CLICommand) setArguments(arguments string) CLICommand {
return CLICommand{c.command, arguments, c.flags, c.stdin}
}
func (c CLICommand) setStdin(stdin string) CLICommand {
return CLICommand{c.command, c.arguments, c.flags, strings.NewReader(stdin)}
}
func (c CLICommand) cmd() string {
flags := ""
for key, value := range c.flags {
if strings.Contains(value, " ") {
value = "\"" + value + "\""
}
flags += fmt.Sprintf("--%s %s ", key, value)
}
return fmt.Sprintf("%s %s %s", c.command, c.arguments, flags)
}
func (c CLICommand) run() (CLIOutput, error) {
var stdout, stderr, combined bytes.Buffer
cmd := Command(c.cmd())
cmd.Stdout = io.MultiWriter(&stdout, &combined)
cmd.Stderr = io.MultiWriter(&stderr, &combined)
cmd.Stdin = c.stdin
err := cmd.Run()
return CLIOutput{stdout.String(), stderr.String(), combined.String()}, err
}
func (c CLICommand) spawn() (*gexpect.ExpectSubprocess, error) {
return gexpect.Spawn(c.cmd())
}
func (c CLICommand) test(t *testing.T, name string, expected string, msg ...interface{}) {
t.Run(name, func(t *testing.T) {
out, err := c.run()
assert.FatalError(t, err, fmt.Sprintf("`%s`: returned error '%s'\n\nOutput:\n%s", c.cmd(), err, out.combined))
assert.Equals(t, out.combined, expected, msg...)
})
}
func (c CLICommand) fail(t *testing.T, name string, expected interface{}, msg ...interface{}) {
t.Run(name, func(t *testing.T) {
out, err := c.run()
if assert.NotNil(t, err) {
assert.Equals(t, err.Error(), "exit status 1")
}
switch v := expected.(type) {
case string:
assert.Equals(t, expected, out.stderr)
case *regexp.Regexp:
re := expected.(*regexp.Regexp)
if !re.MatchString(out.stderr) {
t.Errorf("Error message did not match regex:\n Regex: %s\n\n Output:\n%s", re.String(), out.stderr)
}
default:
t.Errorf("unexpected type %T", v)
}
assert.Equals(t, "", out.stdout)
})
}
|