Beispiel #1
0
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
}
Beispiel #2
0
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,
	})
}
Beispiel #3
0
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
}
Beispiel #4
0
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)
	}
}
Beispiel #5
0
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)
	}
}
Beispiel #6
0
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))
}