func parseTestResultsDir(target *core.BuildTarget, outputDir string) (core.TestResults, error) { results := core.TestResults{} if !core.PathExists(outputDir) { return results, fmt.Errorf("Didn't find any test results in %s", outputDir) } err := filepath.Walk(outputDir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } else if !info.IsDir() { fileResults, err := parseTestResultsImpl(target, path) if err != nil { return fmt.Errorf("Error parsing %s: %s", path, err) } results.Aggregate(fileResults) } return nil }) return results, err }
func appendResult2(test JUnitXMLTest, results *core.TestResults, failure JUnitXMLFailure) { results.Failed++ results.Failures = append(results.Failures, core.TestFailure{ Name: combineNames(test.ClassName, test.Name), Type: failure.Type, Traceback: messageOrTraceback(failure), // TODO(pebers): store both of these, not just one. Stdout: test.Stdout, Stderr: test.Stderr, }) }
func parseGoTestResults(data []byte) (core.TestResults, error) { results := core.TestResults{} lines := bytes.Split(data, []byte{'\n'}) testsStarted := map[string]bool{} for i, line := range lines { testStartMatches := testStart.FindSubmatch(line) testResultMatches := testResult.FindSubmatch(line) if testStartMatches != nil { testsStarted[strings.TrimSpace(string(testStartMatches[1]))] = true } else if testResultMatches != nil { testName := strings.TrimSpace(string(testResultMatches[2])) if !testsStarted[testName] { continue } results.NumTests++ if bytes.Equal(testResultMatches[1], []byte("PASS")) { results.Passed++ results.Passes = append(results.Passes, testName) } else if bytes.Equal(testResultMatches[1], []byte("SKIP")) { results.Skipped++ i++ // Skip following line too that has the reason for being skipped } else { output := "" for j := i + 1; j < len(lines) && !bytes.HasPrefix(lines[j], []byte("===")); j++ { output += string(lines[j]) + "\n" i = j } results.Failed++ results.Failures = append(results.Failures, core.TestFailure{ Name: testName, Type: "FAILURE", Traceback: output, Stdout: "", Stderr: "", }) } } else if bytes.Equal(line, []byte("PASS")) { // Do nothing, all's well. } else if bytes.Equal(line, []byte("FAIL")) { if results.Failed == 0 { return results, fmt.Errorf("Test indicated final failure but no failures found yet") } } } return results, nil }
func processResult(state *core.BuildState, result *core.BuildResult, buildingTargets []buildingTarget, aggregatedResults *core.TestResults, plainOutput bool, keepGoing bool, failedTargets, failedNonTests *[]core.BuildLabel, failedTargetMap map[core.BuildLabel]error, shouldTrace bool) { label := result.Label active := result.Status == core.PackageParsing || result.Status == core.TargetBuilding || result.Status == core.TargetTesting failed := result.Status == core.ParseFailed || result.Status == core.TargetBuildFailed || result.Status == core.TargetTestFailed cached := result.Status == core.TargetCached || result.Tests.Cached stopped := result.Status == core.TargetBuildStopped if shouldTrace { addTrace(result, buildingTargets[result.ThreadId].Label, active) } if failed && result.Tests.NumTests == 0 && result.Tests.Failed == 0 { result.Tests.NumTests = 1 result.Tests.Failed = 1 // Ensure there's one test failure when there're no results to parse. } // Only aggregate test results the first time it finishes. if buildingTargets[result.ThreadId].Active && !active { aggregatedResults.Aggregate(result.Tests) } target := state.Graph.Target(label) updateTarget(state, plainOutput, &buildingTargets[result.ThreadId], label, active, failed, cached, result.Description, result.Err, targetColour(target)) if failed { failedTargetMap[label] = result.Err // Don't stop here after test failure, aggregate them for later. if !keepGoing && result.Status != core.TargetTestFailed { // Reset colour so the entire compiler error output doesn't appear red. log.Errorf("%s failed:${RESET}\n%s", result.Label, result.Err) state.KillAll() } else if !plainOutput { // plain output will have already logged this log.Errorf("%s failed: %s", result.Label, result.Err) } *failedTargets = append(*failedTargets, label) if result.Status != core.TargetTestFailed { *failedNonTests = append(*failedNonTests, label) } } else if stopped { failedTargetMap[result.Label] = nil } else if plainOutput && state.ShowTestOutput && result.Status == core.TargetTested { // If using interactive output we'll print it afterwards. printf("Finished test %s:\n%s\n", label, target.Results.Output) } }
func appendResult(test JUnitXMLTest, results *core.TestResults) { results.NumTests++ if test.Failure != nil { appendResult2(test, results, *test.Failure) } else if test.Error != nil { appendResult2(test, results, *test.Error) } else if test.Type == "FAILURE" || test.Success == "false" || test.Stacktrace != "" { appendResult2(test, results, JUnitXMLFailure{"", "FAILURE", test.Stacktrace}) } else { results.Passed++ results.Passes = append(results.Passes, test.Name) } }
func printTestResults(state *core.BuildState, aggregatedResults core.TestResults, failedTargets []core.BuildLabel, duration float64) { if len(failedTargets) > 0 { for _, failed := range failedTargets { target := state.Graph.TargetOrDie(failed) if len(target.Results.Failures) == 0 { if target.Results.TimedOut { printf("${WHITE_ON_RED}Fail:${RED_NO_BG} %s ${WHITE_ON_RED}Timed out${RESET}\n", target.Label) } else { printf("${WHITE_ON_RED}Fail:${RED_NO_BG} %s ${WHITE_ON_RED}Failed to run test${RESET}\n", target.Label) } } else { printf("${WHITE_ON_RED}Fail:${RED_NO_BG} %s ${BOLD_GREEN}%3d passed ${BOLD_YELLOW}%3d skipped ${BOLD_RED}%3d failed ${BOLD_WHITE}Took %3.1fs${RESET}\n", target.Label, target.Results.Passed, target.Results.Skipped, target.Results.Failed, target.Results.Duration) for _, failure := range target.Results.Failures { printf("${BOLD_RED}Failure: %s in %s${RESET}\n", failure.Type, failure.Name) printf("%s\n", failure.Traceback) if len(failure.Stdout) > 0 { printf("${BOLD_RED}Standard output:${RESET}\n%s\n", failure.Stdout) } if len(failure.Stderr) > 0 { printf("${BOLD_RED}Standard error:${RESET}\n%s\n", failure.Stderr) } } } if len(target.Results.Output) > 0 { printf("${BOLD_RED}Full output:${RESET}\n%s\n", target.Results.Output) } if target.Results.Flakes > 0 { printf("${BOLD_MAGENTA}Flaky target; made %s before giving up${RESET}\n", pluralise(target.Results.Flakes, "attempt", "attempts")) } } } // Print individual test results i := 0 for _, target := range state.Graph.AllTargets() { if target.IsTest && target.Results.NumTests > 0 { if target.Results.Failed > 0 { printf("${RED}%s${RESET} %s\n", target.Label, testResultMessage(target.Results, failedTargets)) } else { printf("${GREEN}%s${RESET} %s\n", target.Label, testResultMessage(target.Results, failedTargets)) } if state.ShowTestOutput && target.Results.Output != "" { printf("Test output:\n%s\n", target.Results.Output) } i++ } } aggregatedResults.Duration = -0.1 // Exclude this from being displayed later. printf(fmt.Sprintf("${BOLD_WHITE}%s and %s${BOLD_WHITE}. Total time %0.2fs.${RESET}\n", pluralise(i, "test target", "test targets"), testResultMessage(aggregatedResults, failedTargets), duration)) }