platformtest: harness: refactor + support SkipNow

This commit is contained in:
Christian Schwarz 2019-12-21 19:01:47 +01:00
parent e7aa08564b
commit ddd7acec49
2 changed files with 97 additions and 42 deletions

View File

@ -4,6 +4,7 @@ import (
"context"
"flag"
"fmt"
"os"
"path/filepath"
"time"
@ -17,12 +18,25 @@ import (
"github.com/zrepl/zrepl/platformtest/tests"
)
func main() {
var bold = color.New(color.Bold)
var boldRed = color.New(color.Bold, color.FgHiRed)
var boldGreen = color.New(color.Bold, color.FgHiGreen)
var args struct {
createArgs platformtest.ZpoolCreateArgs
stopAndKeepPoolOnFail bool
var args struct {
createArgs platformtest.ZpoolCreateArgs
stopAndKeepPoolOnFail bool
}
func main() {
if err := doMain(); err != nil {
os.Exit(1)
}
}
var exitWithErr = fmt.Errorf("exit with error")
func doMain() error {
flag.StringVar(&args.createArgs.PoolName, "poolname", "", "")
flag.StringVar(&args.createArgs.ImagePath, "imagepath", "", "")
flag.Int64Var(&args.createArgs.ImageSize, "imagesize", 100*(1<<20), "")
@ -50,48 +64,83 @@ func main() {
ctx := platformtest.WithLogger(context.Background(), logger)
ex := platformtest.NewEx(logger)
bold := color.New(color.Bold)
boldRed := color.New(color.Bold, color.FgHiRed)
boldGreen := color.New(color.Bold, color.FgHiGreen)
for _, c := range tests.Cases {
// ATTENTION future parallelism must pass c by value into closure!
err := func() (err error) {
var oErr = &err
bold.Printf("BEGIN TEST CASE %s\n", c)
pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.createArgs)
if err != nil {
return errors.Wrap(err, "create test pool")
}
defer func() {
if err := recover(); err != nil {
*oErr = errors.Errorf("panic while running test: %v", err) // shadow
if args.stopAndKeepPoolOnFail {
return
}
// fallthrough
}
if err := pool.Destroy(ctx, ex); err != nil {
fmt.Printf("error destroying test pool: %s", err)
}
}()
ctx := &platformtest.Context{
Context: ctx,
RootDataset: filepath.Join(pool.Name(), "rootds"),
}
c(ctx)
return nil
}()
bold.Printf("BEGIN TEST CASE %s\n", c)
pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.createArgs)
if err != nil {
boldRed.Printf("TEST CASE FAILED WITH ERROR:\n")
fmt.Printf("%+v\n", err) // print with stack trace
if args.stopAndKeepPoolOnFail {
bold.Printf("STOPPING TEST RUN AT FAILING TEST PER USER REQUEST\n")
return
}
} else {
boldGreen.Printf("DONE TEST CASE %s\n", c)
panic(errors.Wrap(err, "create test pool"))
}
ctx := &platformtest.Context{
Context: ctx,
RootDataset: filepath.Join(pool.Name(), "rootds"),
}
res := runTestCase(ctx, ex, c)
if res.failed {
fmt.Printf("%+v\n", res.failedStack) // print with stack trace
}
if res.failed && args.stopAndKeepPoolOnFail {
boldRed.Printf("STOPPING TEST RUN AT FAILING TEST PER USER REQUEST\n")
return exitWithErr
}
if err := pool.Destroy(ctx, ex); err != nil {
panic(fmt.Sprintf("error destroying test pool: %s", err))
}
if res.failed {
boldRed.Printf("TEST FAILED\n")
} else if res.skipped {
bold.Printf("TEST SKIPPED\n")
} else if res.succeeded {
boldGreen.Printf("TEST PASSED\n")
}
fmt.Println()
}
return nil
}
type testCaseResult struct {
// oneof
failed, skipped, succeeded bool
failedStack error // has stack inside, valid if failed=true
}
func runTestCase(ctx *platformtest.Context, ex platformtest.Execer, c tests.Case) testCaseResult {
// run case
var paniced = false
var panicValue interface{} = nil
var panicStack error
func() {
defer func() {
if item := recover(); item != nil {
panicValue = item
paniced = true
panicStack = errors.Errorf("panic while running test: %v", panicValue)
}
}()
c(ctx)
}()
if paniced {
switch panicValue {
case platformtest.SkipNowSentinel:
return testCaseResult{skipped: true}
case platformtest.FailNowSentinel:
return testCaseResult{failed: true, failedStack: panicStack}
default:
return testCaseResult{failed: true, failedStack: panicStack}
}
} else {
return testCaseResult{succeeded: true}
}
}

View File

@ -15,6 +15,8 @@ type Context struct {
var FailNowSentinel = fmt.Errorf("platformtest: FailNow called on context")
var SkipNowSentinel = fmt.Errorf("platformtest: SkipNow called on context")
var _ assert.TestingT = (*Context)(nil)
var _ require.TestingT = (*Context)(nil)
@ -25,3 +27,7 @@ func (c *Context) Errorf(format string, args ...interface{}) {
func (c *Context) FailNow() {
panic(FailNowSentinel)
}
func (c *Context) SkipNow() {
panic(SkipNowSentinel)
}