blob: 17679f75e788678c6571ce45b4c56af9b66da608 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runutil
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
const timedCommandTimeout = 3 * time.Second
var forever time.Duration
func removeTimestamps(t *testing.T, buffer *bytes.Buffer) string {
result := ""
scanner := bufio.NewScanner(buffer)
for scanner.Scan() {
line := scanner.Text()
if index := strings.Index(line, prefix); index != -1 {
result += line[index:] + "\n"
} else {
result += line + "\n"
}
}
if err := scanner.Err(); err != nil {
t.Fatalf("Scan() failed: %v", err)
}
return result
}
func TestCommandOK(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
if err := e.run(forever, e.opts, "go", "run", "./testdata/ok_hello.go"); err != nil {
t.Fatalf(`Command("go run ./testdata/ok_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/ok_hello.go\nhello\n>> OK\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestCommandFail(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
if err := e.run(forever, e.opts, "go", "run", "./testdata/fail_hello.go"); err == nil {
t.Fatalf(`Command("go run ./testdata/fail_hello.go") did not fail when it should`)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/fail_hello.go\nhello\n>> FAILED: exit status 1\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestCommandWithOptsOK(t *testing.T) {
var cmdOut, runOut bytes.Buffer
e := newExecutor(nil, os.Stdin, &runOut, ioutil.Discard, false, true)
opts := e.opts
opts.stdout = &cmdOut
if err := e.run(forever, opts, "go", "run", "./testdata/ok_hello.go"); err != nil {
t.Fatalf(`CommandWithOpts("go run ./testdata/ok_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &runOut), ">> go run ./testdata/ok_hello.go\n>> OK\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
if got, want := strings.TrimSpace(cmdOut.String()), "hello"; got != want {
t.Fatalf("unexpected output: got %v, want %v", got, want)
}
}
func TestCommandWithOptsFail(t *testing.T) {
var cmdOut, runOut bytes.Buffer
e := newExecutor(nil, os.Stdin, &runOut, ioutil.Discard, false, true)
opts := e.opts
opts.stdout = &cmdOut
if err := e.run(forever, opts, "go", "run", "./testdata/fail_hello.go"); err == nil {
t.Fatalf(`CommandWithOpts("go run ./testdata/fail_hello.go") did not fail when it should`)
}
if got, want := removeTimestamps(t, &runOut), ">> go run ./testdata/fail_hello.go\n>> FAILED: exit status 1\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
if got, want := strings.TrimSpace(cmdOut.String()), "hello"; got != want {
t.Fatalf("unexpected output: got %v, want %v", got, want)
}
}
func TestTimedCommandOK(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
bin, err := buildTestProgram(e, "fast_hello")
if bin != "" {
defer os.RemoveAll(filepath.Dir(bin))
}
if err != nil {
t.Fatalf("%v", err)
}
if err := e.run(2*time.Minute, e.opts, bin); err != nil {
t.Fatalf(`TimedCommand("go run ./testdata/fast_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &out), fmt.Sprintf(">> %s\nhello\n>> OK\n", bin); got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestTimedCommandFail(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
bin, err := buildTestProgram(e, "slow_hello")
if bin != "" {
defer os.RemoveAll(filepath.Dir(bin))
}
if err != nil {
t.Fatalf("%v", err)
}
if err := e.run(timedCommandTimeout, e.opts, bin); err == nil {
t.Fatalf(`TimedCommand("go run ./testdata/slow_hello.go") did not fail when it should`)
} else if got, want := IsTimeout(err), true; got != want {
t.Fatalf("unexpected error: got %v, want %v", got, want)
}
if got, want := removeTimestamps(t, &out), fmt.Sprintf(">> %s\nhello\n>> TIMED OUT\n", bin); got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestTimedCommandWithOptsOK(t *testing.T) {
var cmdOut, runOut bytes.Buffer
e := newExecutor(nil, os.Stdin, &runOut, ioutil.Discard, false, true)
bin, err := buildTestProgram(e, "fast_hello")
if bin != "" {
defer os.RemoveAll(filepath.Dir(bin))
}
if err != nil {
t.Fatalf("%v", err)
}
opts := e.opts
opts.stdout = &cmdOut
if err := e.run(2*time.Minute, opts, bin); err != nil {
t.Fatalf(`TimedCommandWithOpts("go run ./testdata/fast_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &runOut), fmt.Sprintf(">> %s\n>> OK\n", bin); got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
if got, want := strings.TrimSpace(cmdOut.String()), "hello"; got != want {
t.Fatalf("unexpected output: got %v, want %v", got, want)
}
}
func TestTimedCommandWithOptsFail(t *testing.T) {
var cmdOut, runOut bytes.Buffer
e := newExecutor(nil, os.Stdin, &runOut, ioutil.Discard, false, true)
bin, err := buildTestProgram(e, "slow_hello")
if bin != "" {
defer os.RemoveAll(filepath.Dir(bin))
}
if err != nil {
t.Fatalf("%v", err)
}
opts := e.opts
opts.stdout = &cmdOut
if err := e.run(timedCommandTimeout, opts, bin); err == nil {
t.Fatalf(`TimedCommandWithOpts("go run ./testdata/slow_hello.go") did not fail when it should`)
} else if got, want := IsTimeout(err), true; got != want {
t.Fatalf("unexpected error: got %v, want %v", got, want)
}
if got, want := removeTimestamps(t, &runOut), fmt.Sprintf(">> %s\n>> TIMED OUT\n", bin); got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
if got, want := strings.TrimSpace(cmdOut.String()), "hello"; got != want {
t.Fatalf("unexpected output: got %v, want %v", got, want)
}
}
func TestFunctionOK(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
fn := func() error {
cmd := exec.Command("go", "run", "./testdata/ok_hello.go")
cmd.Stdout = &out
return cmd.Run()
}
if err := e.function(e.opts, fn, "%v %v %v", "go", "run", "./testdata/ok_hello.go"); err != nil {
t.Fatalf(`Function("go run ./testdata/ok_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/ok_hello.go\nhello\n>> OK\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestFunctionFail(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
fn := func() error {
cmd := exec.Command("go", "run", "./testdata/fail_hello.go")
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return fmt.Errorf("the function failed")
}
return nil
}
if err := e.function(e.opts, fn, "%v %v %v", "go", "run", "./testdata/fail_hello.go"); err == nil {
t.Fatalf(`Function("go run ./testdata/fail_hello.go") did not fail when it should`)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/fail_hello.go\nhello\n>> FAILED: the function failed\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestFunctionWithOptsOK(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, false)
opts := e.opts
opts.verbose = true
fn := func() error {
cmd := exec.Command("go", "run", "./testdata/ok_hello.go")
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return fmt.Errorf("the function failed")
}
return nil
}
if err := e.function(opts, fn, "%v %v %v", "go", "run", "./testdata/ok_hello.go"); err != nil {
t.Fatalf(`FunctionWithOpts("go run ./testdata/ok_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/ok_hello.go\nhello\n>> OK\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestFunctionWithOptsFail(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, false)
opts := e.opts
opts.verbose = true
fn := func() error {
cmd := exec.Command("go", "run", "./testdata/fail_hello.go")
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return fmt.Errorf("the function failed")
}
return nil
}
if err := e.function(opts, fn, "%v %v %v", "go", "run", "./testdata/fail_hello.go"); err == nil {
t.Fatalf(`FunctionWithOpts("go run ./testdata/fail_hello.go") did not fail when it should`)
}
if got, want := removeTimestamps(t, &out), ">> go run ./testdata/fail_hello.go\nhello\n>> FAILED: the function failed\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestOutput(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
e.output(e.opts, []string{"hello", "world"})
if got, want := removeTimestamps(t, &out), ">> hello\n>> world\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestOutputWithOpts(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, false)
opts := e.opts
opts.verbose = true
e.output(opts, []string{"hello", "world"})
if got, want := removeTimestamps(t, &out), ">> hello\n>> world\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
func TestNested(t *testing.T) {
var out bytes.Buffer
e := newExecutor(nil, os.Stdin, &out, ioutil.Discard, false, true)
fn := func() error {
e.output(e.opts, []string{"hello", "world"})
return nil
}
e.function(e.opts, fn, "%v", "greetings")
if got, want := removeTimestamps(t, &out), ">> greetings\n>>>> hello\n>>>> world\n>> OK\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
/*
func TestStartCommandWithOptsOK(t *testing.T) {
var cmdOut, runOut bytes.Buffer
start := NewStart(nil, os.Stdin, &runOut, ioutil.Discard, false, false, true)
opts := start.Opts()
opts.Stdout = &cmdOut
cmd, err := start.CommandWithOpts(opts, "go", "run", "./testdata/ok_hello.go")
if err != nil {
t.Fatalf(`Command("go run ./testdata/ok_hello.go") failed to start: %v`, err)
}
if err := cmd.Wait(); err != nil {
t.Fatalf(`Command("go run ./testdata/ok_hello.go") failed: %v`, err)
}
if got, want := removeTimestamps(t, &cmdOut), "hello\n"; got != want {
t.Fatalf("unexpected output:\ngot\n%v\nwant\n%v", got, want)
}
}
*/
func buildTestProgram(e *executor, fileName string) (string, error) {
tmpDir, err := ioutil.TempDir("", "runtest")
if err != nil {
return "", fmt.Errorf("TempDir() failed: %v", err)
}
bin := filepath.Join(tmpDir, fileName)
buildArgs := []string{"build", "-o", bin, fmt.Sprintf("./testdata/%s.go", fileName)}
opts := e.opts
opts.verbose = false
if err := e.run(forever, opts, "go", buildArgs...); err != nil {
return "", err
}
return bin, nil
}