Skip to content

Commit

Permalink
Recover panic in the RunWith wrapper and log it to stderr and refactor (
Browse files Browse the repository at this point in the history
elastic#6011)

the cli_test tests.
  • Loading branch information
ph authored and Steffen Siering committed Feb 8, 2018
1 parent f8f6f3b commit 73d96ef
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 28 deletions.
10 changes: 10 additions & 0 deletions libbeat/common/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@ package cli
import (
"fmt"
"os"
"runtime/debug"

"github.com/spf13/cobra"
)

func exitOnPanic() {
if r := recover(); r != nil {
fmt.Fprintf(os.Stderr, "panic: %s\n", r)
debug.PrintStack()
os.Exit(1)
}
}

// RunWith wrap cli function with an error handler instead of having the code exit early.
func RunWith(
fn func(cmd *cobra.Command, args []string) error,
) func(cmd *cobra.Command, args []string) {
return func(cmd *cobra.Command, args []string) {
defer exitOnPanic()
if err := fn(cmd, args); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
Expand Down
74 changes: 46 additions & 28 deletions libbeat/common/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,51 +11,69 @@ import (
"github.com/stretchr/testify/assert"
)

func funcWithError() {
var cmd *cobra.Command
var args []string
RunWith(func(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Something bad")
})(cmd, args)
}
func runCli(testName string) (*bytes.Buffer, error) {
cmd := exec.Command(os.Args[0], "-test.run="+testName)
cmd.Env = append(os.Environ(), "TEST_RUNWITH=1")
stderr := new(bytes.Buffer)
cmd.Stderr = stderr

func funcWithoutError() {
var cmd *cobra.Command
var args []string
RunWith(func(cmd *cobra.Command, args []string) error {
return nil
})(cmd, args)
err := cmd.Run()
return stderr, err
}

// Example taken from slides from Andrew Gerrand
// https://talks.golang.org/2014/testing.slide#23
func TestExitWithError(t *testing.T) {
if os.Getenv("TEST_RUNWITH") == "1" {
funcWithError()
return
func() {
var cmd *cobra.Command
var args []string
RunWith(func(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Something bad")
})(cmd, args)
return
}()
}
cmd := exec.Command(os.Args[0], "-test.run=TestExitWithError")
cmd.Env = append(os.Environ(), "TEST_RUNWITH=1")
bufError := new(bytes.Buffer)
cmd.Stderr = bufError
err := cmd.Run()

stderr, err := runCli("TestExitWithError")
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "exit status 1")
}
assert.Equal(t, "Something bad\n", bufError.String())
assert.Equal(t, "Something bad\n", stderr.String())
}

func TestExitWithoutError(t *testing.T) {
if os.Getenv("TEST_RUNWITH") == "1" {
funcWithoutError()
func() {
var cmd *cobra.Command
var args []string
RunWith(func(cmd *cobra.Command, args []string) error {
return nil
})(cmd, args)
}()
return
}

cmd := exec.Command(os.Args[0], "-test.run=TestExitWithoutError")
cmd.Env = append(os.Environ(), "TEST_RUNWITH=1")
bufError := new(bytes.Buffer)
cmd.Stderr = bufError
err := cmd.Run()
stderr, err := runCli("TestExitWithoutError")
assert.NoError(t, err)
assert.Equal(t, "", bufError.String())
assert.Equal(t, "", stderr.String())
}

func TestExitWithPanic(t *testing.T) {
if os.Getenv("TEST_RUNWITH") == "1" {
func() {
var cmd *cobra.Command
var args []string
RunWith(func(cmd *cobra.Command, args []string) error {
panic("something really bad happened")
})(cmd, args)
}()
return
}

stderr, err := runCli("TestExitWithPanic")
if assert.Error(t, err) {
assert.Equal(t, err.Error(), "exit status 1")
}
assert.Contains(t, stderr.String(), "something really bad happened")
}

0 comments on commit 73d96ef

Please sign in to comment.