You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/e2e/testcli/testcli.go

198 lines
4.4 KiB

// inspired by github.com/rendon/testcli
package testcli
import (
"bytes"
"errors"
"io"
"log"
"os"
"os/exec"
"regexp"
"strings"
)
// Cmd is typically constructed through the Command() call and provides state
// to the execution engine.
type Cmd struct {
cmd *exec.Cmd
env []string
exitError error
executed bool
stdout string
stderr string
stdin io.Reader
}
// ErrUninitializedCmd is returned when members are accessed before a run, that
// can only be used after a command has been run.
var ErrUninitializedCmd = errors.New("You need to run this command first")
var pkgCmd = &Cmd{}
// Command constructs a *Cmd. It is passed the command name and arguments.
func Command(name string, arg ...string) *Cmd {
return &Cmd{
cmd: exec.Command(name, arg...),
}
}
func (c *Cmd) validate() {
if !c.executed {
log.Fatal(ErrUninitializedCmd)
}
}
// SetEnv overwrites the environment with the provided one. Otherwise, the
// parent environment will be supplied.
func (c *Cmd) SetEnv(env []string) {
c.env = env
}
// SetStdin sets the stdin stream. It makes no attempt to determine if the
// command accepts anything over stdin.
func (c *Cmd) SetStdin(stdin io.Reader) {
c.stdin = stdin
}
// Run runs the command.
func (c *Cmd) Run() {
if c.stdin != nil {
c.cmd.Stdin = c.stdin
}
if c.env != nil {
c.cmd.Env = c.env
} else {
c.cmd.Env = os.Environ()
}
var outBuf bytes.Buffer
c.cmd.Stdout = &outBuf
var errBuf bytes.Buffer
c.cmd.Stderr = &errBuf
if err := c.cmd.Run(); err != nil {
c.exitError = err
}
c.stdout = string(outBuf.Bytes())
c.stderr = string(errBuf.Bytes())
c.executed = true
}
// Run runs a command with name and arguments. After this, package-level
// functions will return the data about the last command run.
func Run(name string, arg ...string) {
pkgCmd = Command(name, arg...)
pkgCmd.Run()
}
// Error is the command's error, if any.
func (c *Cmd) Error() error {
c.validate()
return c.exitError
}
// Error is the command's error, if any.
func Error() error {
return pkgCmd.Error()
}
// Stdout stream for the command
func (c *Cmd) Stdout() string {
c.validate()
return c.stdout
}
// Stdout stream for the command
func Stdout() string {
return pkgCmd.Stdout()
}
// Stderr stream for the command
func (c *Cmd) Stderr() string {
c.validate()
return c.stderr
}
// Stderr stream for the command
func Stderr() string {
return pkgCmd.Stderr()
}
// StdoutContains determines if command's STDOUT contains `str`, this operation
// is case insensitive.
func (c *Cmd) StdoutContains(str string) bool {
c.validate()
str = strings.ToLower(str)
return strings.Contains(strings.ToLower(c.stdout), str)
}
// StdoutContains determines if command's STDOUT contains `str`, this operation
// is case insensitive.
func StdoutContains(str string) bool {
return pkgCmd.StdoutContains(str)
}
// StderrContains determines if command's STDERR contains `str`, this operation
// is case insensitive.
func (c *Cmd) StderrContains(str string) bool {
c.validate()
str = strings.ToLower(str)
return strings.Contains(strings.ToLower(c.stderr), str)
}
// StderrContains determines if command's STDERR contains `str`, this operation
// is case insensitive.
func StderrContains(str string) bool {
return pkgCmd.StderrContains(str)
}
// Success is a boolean status which indicates if the program exited non-zero
// or not.
func (c *Cmd) Success() bool {
c.validate()
return c.exitError == nil
}
// Success is a boolean status which indicates if the program exited non-zero
// or not.
func Success() bool {
return pkgCmd.Success()
}
// Failure is the inverse of Success().
func (c *Cmd) Failure() bool {
c.validate()
return c.exitError != nil
}
// Failure is the inverse of Success().
func Failure() bool {
return pkgCmd.Failure()
}
// StdoutMatches compares a regex to the stdout produced by the command.
func (c *Cmd) StdoutMatches(regex string) bool {
c.validate()
re := regexp.MustCompile(regex)
return re.MatchString(c.Stdout())
}
// StdoutMatches compares a regex to the stdout produced by the command.
func StdoutMatches(regex string) bool {
return pkgCmd.StdoutMatches(regex)
}
// StderrMatches compares a regex to the stderr produced by the command.
func (c *Cmd) StderrMatches(regex string) bool {
c.validate()
re := regexp.MustCompile(regex)
return re.MatchString(c.Stderr())
}
// StderrMatches compares a regex to the stderr produced by the command.
func StderrMatches(regex string) bool {
return pkgCmd.StderrMatches(regex)
}