run-cts: add "log" arg to log test results to file

Bug: dawn:1123
Change-Id: Id9ad62dde8f7988cb66e39ca0d543c23d0fad341
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/65781
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
Antonio Maiorano 2021-10-05 21:18:10 +00:00 committed by Dawn LUCI CQ
parent 78632a644f
commit 22da31cf43
1 changed files with 50 additions and 7 deletions

View File

@ -67,7 +67,7 @@ func run() error {
} }
} }
var dawnNode, cts, node, npx string var dawnNode, cts, node, npx, logFilename string
var verbose, build bool var verbose, build bool
var numRunners int var numRunners int
flag.StringVar(&dawnNode, "dawn-node", "", "path to dawn.node module") flag.StringVar(&dawnNode, "dawn-node", "", "path to dawn.node module")
@ -78,6 +78,7 @@ func run() error {
flag.BoolVar(&build, "build", true, "attempt to build the CTS before running") flag.BoolVar(&build, "build", true, "attempt to build the CTS before running")
flag.BoolVar(&colors, "colors", colors, "enable / disable colors") flag.BoolVar(&colors, "colors", colors, "enable / disable colors")
flag.IntVar(&numRunners, "j", runtime.NumCPU(), "number of concurrent runners") flag.IntVar(&numRunners, "j", runtime.NumCPU(), "number of concurrent runners")
flag.StringVar(&logFilename, "log", "", "path to log file of tests run and result")
flag.Parse() flag.Parse()
if colors { if colors {
@ -140,6 +141,15 @@ func run() error {
require('./src/common/runtime/cmdline.ts');`, require('./src/common/runtime/cmdline.ts');`,
} }
if logFilename != "" {
writer, err := os.Create(logFilename)
if err != nil {
return fmt.Errorf("failed to open log '%v': %w", logFilename, err)
}
defer writer.Close()
r.log = newLogger(writer)
}
if build { if build {
// Attempt to build the CTS (instead of using the `setup-ts-in-node` transpiler) // Attempt to build the CTS (instead of using the `setup-ts-in-node` transpiler)
if npx != "" { if npx != "" {
@ -163,12 +173,41 @@ func run() error {
return r.run() return r.run()
} }
type logger struct {
writer io.Writer
idx int
resultByIndex map[int]result
}
// newLogger creates a new logger instance.
func newLogger(writer io.Writer) logger {
return logger{writer, 0, map[int]result{}}
}
// logResult writes the test results to the log file in sequential order.
// logResult should be called whenever a new test result becomes available.
func (l *logger) logResults(res result) {
if l.writer == nil {
return
}
l.resultByIndex[res.index] = res
for {
logRes, ok := l.resultByIndex[l.idx]
if !ok {
break
}
fmt.Fprintf(l.writer, "%v [%v]\n", logRes.testcase, logRes.status)
l.idx++
}
}
type runner struct { type runner struct {
numRunners int numRunners int
verbose bool verbose bool
node, npx, dawnNode, cts string node, npx, dawnNode, cts string
evalScript string evalScript string
testcases []string testcases []string
log logger
} }
// buildCTS calls `npx grunt run:build-out-node` in the CTS directory to compile // buildCTS calls `npx grunt run:build-out-node` in the CTS directory to compile
@ -265,9 +304,12 @@ func (r *runner) run() error {
// we're not printing endless progress bars. // we're not printing endless progress bars.
progressUpdateRate = time.Second progressUpdateRate = time.Second
} }
for res := range results { for res := range results {
name := res.testcase r.log.logResults(res)
numByStatus[res.status] = numByStatus[res.status] + 1 numByStatus[res.status] = numByStatus[res.status] + 1
name := res.testcase
if r.verbose || (res.status != pass && res.status != skip) { if r.verbose || (res.status != pass && res.status != skip) {
fmt.Printf("%v - %v: %v\n", name, res.status, res.message) fmt.Printf("%v - %v: %v\n", name, res.status, res.message)
updateProgress() updateProgress()
@ -308,6 +350,7 @@ const (
// result holds the information about a completed test // result holds the information about a completed test
type result struct { type result struct {
index int
testcase string testcase string
status status status status
message string message string
@ -341,15 +384,15 @@ func (r *runner) runTestcase(idx int) result {
msg := string(out) msg := string(out)
switch { switch {
case errors.Is(err, context.DeadlineExceeded): case errors.Is(err, context.DeadlineExceeded):
return result{testcase: testcase, status: timeout, message: msg} return result{index: idx, testcase: testcase, status: timeout, message: msg}
case strings.Contains(msg, "[fail]"): case strings.Contains(msg, "[fail]"):
return result{testcase: testcase, status: fail, message: msg} return result{index: idx, testcase: testcase, status: fail, message: msg}
case strings.Contains(msg, "[skip]"): case strings.Contains(msg, "[skip]"):
return result{testcase: testcase, status: skip, message: msg} return result{index: idx, testcase: testcase, status: skip, message: msg}
case strings.Contains(msg, "[pass]"), err == nil: case strings.Contains(msg, "[pass]"), err == nil:
return result{testcase: testcase, status: pass, message: msg} return result{index: idx, testcase: testcase, status: pass, message: msg}
} }
return result{testcase: testcase, status: fail, message: fmt.Sprint(msg, err), error: err} return result{index: idx, testcase: testcase, status: fail, message: fmt.Sprint(msg, err), error: err}
} }
// filterTestcases returns in with empty strings removed // filterTestcases returns in with empty strings removed