platformtest: harness: run filter + summary

This commit is contained in:
Christian Schwarz 2019-12-23 11:48:48 +01:00
parent ddd7acec49
commit e675b35cda
2 changed files with 66 additions and 9 deletions

View File

@ -144,8 +144,9 @@ format:
ZREPL_PLATFORMTEST_POOLNAME := zreplplatformtest ZREPL_PLATFORMTEST_POOLNAME := zreplplatformtest
ZREPL_PLATFORMTEST_IMAGEPATH := /tmp/zreplplatformtest.pool.img ZREPL_PLATFORMTEST_IMAGEPATH := /tmp/zreplplatformtest.pool.img
ZREPL_PLATFORMTEST_ARGS :=
platformtest: # do not track dependency on platformtest-bin to allow build of platformtest outside of test VM platformtest: # do not track dependency on platformtest-bin to allow build of platformtest outside of test VM
"$(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)" -poolname "$(ZREPL_PLATFORMTEST_POOLNAME)" -imagepath "$(ZREPL_PLATFORMTEST_IMAGEPATH)" "$(ARTIFACTDIR)/platformtest-$(ZREPL_TARGET_TUPLE)" -poolname "$(ZREPL_PLATFORMTEST_POOLNAME)" -imagepath "$(ZREPL_PLATFORMTEST_IMAGEPATH)" $(ZREPL_PLATFORMTEST_ARGS)
##################### NOARCH ##################### ##################### NOARCH #####################
.PHONY: noarch $(ARTIFACTDIR)/bash_completion $(ARTIFACTDIR)/go_env.txt docs docs-clean .PHONY: noarch $(ARTIFACTDIR)/bash_completion $(ARTIFACTDIR)/go_env.txt docs docs-clean

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"time" "time"
"github.com/fatih/color" "github.com/fatih/color"
@ -25,6 +26,9 @@ var boldGreen = color.New(color.Bold, color.FgHiGreen)
var args struct { var args struct {
createArgs platformtest.ZpoolCreateArgs createArgs platformtest.ZpoolCreateArgs
stopAndKeepPoolOnFail bool stopAndKeepPoolOnFail bool
run string
runRE *regexp.Regexp
} }
func main() { func main() {
@ -42,8 +46,11 @@ func doMain() error {
flag.Int64Var(&args.createArgs.ImageSize, "imagesize", 100*(1<<20), "") flag.Int64Var(&args.createArgs.ImageSize, "imagesize", 100*(1<<20), "")
flag.StringVar(&args.createArgs.Mountpoint, "mountpoint", "none", "") flag.StringVar(&args.createArgs.Mountpoint, "mountpoint", "none", "")
flag.BoolVar(&args.stopAndKeepPoolOnFail, "failure.stop-and-keep-pool", false, "if a test case fails, stop test execution and keep pool as it was when the test failed") flag.BoolVar(&args.stopAndKeepPoolOnFail, "failure.stop-and-keep-pool", false, "if a test case fails, stop test execution and keep pool as it was when the test failed")
flag.StringVar(&args.run, "run", "", "")
flag.Parse() flag.Parse()
args.runRE = regexp.MustCompile(args.run)
outlets := logger.NewOutlets() outlets := logger.NewOutlets()
outlet, level, err := logging.ParseOutlet(config.LoggingOutletEnum{Ret: &config.StdoutLoggingOutlet{ outlet, level, err := logging.ParseOutlet(config.LoggingOutletEnum{Ret: &config.StdoutLoggingOutlet{
LoggingOutletCommon: config.LoggingOutletCommon{ LoggingOutletCommon: config.LoggingOutletCommon{
@ -64,9 +71,21 @@ func doMain() error {
ctx := platformtest.WithLogger(context.Background(), logger) ctx := platformtest.WithLogger(context.Background(), logger)
ex := platformtest.NewEx(logger) ex := platformtest.NewEx(logger)
for _, c := range tests.Cases { type invocation struct {
runFunc tests.Case
result *testCaseResult
}
bold.Printf("BEGIN TEST CASE %s\n", c) invocations := make([]*invocation, 0, len(tests.Cases))
for _, c := range tests.Cases {
if args.runRE.MatchString(c.String()) {
invocations = append(invocations, &invocation{runFunc: c})
}
}
for _, inv := range invocations {
bold.Printf("BEGIN TEST CASE %s\n", inv.runFunc.String())
pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.createArgs) pool, err := platformtest.CreateOrReplaceZpool(ctx, ex, args.createArgs)
if err != nil { if err != nil {
@ -78,7 +97,8 @@ func doMain() error {
RootDataset: filepath.Join(pool.Name(), "rootds"), RootDataset: filepath.Join(pool.Name(), "rootds"),
} }
res := runTestCase(ctx, ex, c) res := runTestCase(ctx, ex, inv.runFunc)
inv.result = res
if res.failed { if res.failed {
fmt.Printf("%+v\n", res.failedStack) // print with stack trace fmt.Printf("%+v\n", res.failedStack) // print with stack trace
} }
@ -98,11 +118,47 @@ func doMain() error {
bold.Printf("TEST SKIPPED\n") bold.Printf("TEST SKIPPED\n")
} else if res.succeeded { } else if res.succeeded {
boldGreen.Printf("TEST PASSED\n") boldGreen.Printf("TEST PASSED\n")
} else {
panic("unreachable")
} }
fmt.Println() fmt.Println()
} }
var summary struct {
succ, fail, skip []*invocation
}
for _, inv := range invocations {
var bucket *[]*invocation
if inv.result.failed {
bucket = &summary.fail
} else if inv.result.skipped {
bucket = &summary.skip
} else if inv.result.succeeded {
bucket = &summary.succ
} else {
panic("unreachable")
}
*bucket = append(*bucket, inv)
}
printBucket := func(bucketName string, c *color.Color, bucket []*invocation) {
c.Printf("%s:", bucketName)
if len(bucket) == 0 {
fmt.Printf(" []\n")
return
}
fmt.Printf("\n")
for _, inv := range bucket {
fmt.Printf(" %s\n", inv.runFunc.String())
}
}
printBucket("PASSING TESTS", boldGreen, summary.succ)
printBucket("SKIPPED TESTS", bold, summary.skip)
printBucket("FAILED TESTS", boldRed, summary.fail)
if len(summary.fail) > 0 {
return errors.New("at least one test failed")
}
return nil return nil
} }
@ -113,7 +169,7 @@ type testCaseResult struct {
failedStack error // has stack inside, valid if failed=true failedStack error // has stack inside, valid if failed=true
} }
func runTestCase(ctx *platformtest.Context, ex platformtest.Execer, c tests.Case) testCaseResult { func runTestCase(ctx *platformtest.Context, ex platformtest.Execer, c tests.Case) *testCaseResult {
// run case // run case
var paniced = false var paniced = false
@ -133,14 +189,14 @@ func runTestCase(ctx *platformtest.Context, ex platformtest.Execer, c tests.Case
if paniced { if paniced {
switch panicValue { switch panicValue {
case platformtest.SkipNowSentinel: case platformtest.SkipNowSentinel:
return testCaseResult{skipped: true} return &testCaseResult{skipped: true}
case platformtest.FailNowSentinel: case platformtest.FailNowSentinel:
return testCaseResult{failed: true, failedStack: panicStack} return &testCaseResult{failed: true, failedStack: panicStack}
default: default:
return testCaseResult{failed: true, failedStack: panicStack} return &testCaseResult{failed: true, failedStack: panicStack}
} }
} else { } else {
return testCaseResult{succeeded: true} return &testCaseResult{succeeded: true}
} }
} }