Skip to content

Commit

Permalink
[6.4.0] Print Passed and Failed methods in detailed test summary (#19505
Browse files Browse the repository at this point in the history
)

Cherry-pick of c75fda9

Previously, Bazel only printed Failed methods in the detailed test
summary when using the `--test_summary=detailed` option. With this
change, both Passed and Failed methods are now printed, providing a more
comprehensive view of the test results.

Fix #18685

Closes #19099.

RELNOTES: The `--test_summary=detailed` option now also prints passed
test cases.
PiperOrigin-RevId: 553737487
Change-Id: I332b70d916394de7caed7a07667b46087724a6c1

Co-authored-by: NelsonLi0701 <meteorli@gmail.com>
  • Loading branch information
thirtyseven and NelsonLi0701 authored Sep 13, 2023
1 parent 970b9dd commit 2ebbfeb
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ private boolean duplicateLabels(Set<TestSummary> summaries) {
* @param summaries summaries of tests {@link TestSummary}
* @param showAllTests if true, print information about each test regardless of its status
* @param showNoStatusTests if true, print information about not executed tests (no status tests)
* @param printFailedTestCases if true, print details about which test cases in a test failed
* @param showAllTestCases if true, print all test cases status and detailed information
*/
private void printSummary(
Set<TestSummary> summaries,
boolean showAllTests,
boolean showNoStatusTests,
boolean printFailedTestCases) {
boolean showAllTestCases) {
boolean withConfig = duplicateLabels(summaries);
int numFailedToBuildReported = 0;
for (TestSummary summary : summaries) {
Expand All @@ -171,7 +171,7 @@ private void printSummary(
printer,
testLogPathFormatter,
summaryOptions.verboseSummary,
printFailedTestCases,
showAllTestCases,
withConfig);
}
}
Expand Down Expand Up @@ -243,25 +243,25 @@ public void notify(Set<TestSummary> summaries, int numberOfExecutedTargets) {
case DETAILED:
printSummary(
summaries,
/* showAllTests= */ false,
/* showAllTests= */ true,
/* showNoStatusTests= */ true,
/* printFailedTestCases= */ true);
/* showAllTestCases= */ true);
break;

case SHORT:
printSummary(
summaries,
/* showAllTests= */ true,
/* showNoStatusTests= */ false,
/* printFailedTestCases= */ false);
/* showAllTestCases= */ false);
break;

case TERSE:
printSummary(
summaries,
/* showAllTests= */ false,
/* showNoStatusTests= */ false,
/* printFailedTestCases= */ false);
/* showAllTestCases= */ false);
break;

case TESTCASE:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
import com.google.devtools.build.lib.view.test.TestStatus.FailedTestCasesStatus;
import com.google.devtools.build.lib.view.test.TestStatus.TestCase;
import com.google.devtools.build.lib.view.test.TestStatus.TestCase.Status;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.protobuf.util.Durations;
import com.google.protobuf.util.Timestamps;
Expand Down Expand Up @@ -218,9 +219,20 @@ private int traverseTestCases(TestCase testCase) {
if (testCase.getStatus() != TestCase.Status.PASSED) {
this.summary.failedTestCases.add(testCase);
}

if (testCase.getStatus() == Status.PASSED) {
this.summary.passedTestCases.add(testCase);
}

return 1;
}

public Builder addPassedTestCases(List<TestCase> testCases) {
checkMutation(testCases);
summary.passedTestCases.addAll(testCases);
return this;
}

@CanIgnoreReturnValue
public Builder addFailedTestCases(List<TestCase> testCases, FailedTestCasesStatus status) {
checkMutation(status);
Expand Down Expand Up @@ -396,6 +408,7 @@ private void makeSummaryImmutable() {
private boolean ranRemotely;
private boolean wasUnreportedWrongSize;
private List<TestCase> failedTestCases = new ArrayList<>();
private final List<TestCase> passedTestCases = new ArrayList<>();
private List<Path> passedLogs = new ArrayList<>();
private List<Path> failedLogs = new ArrayList<>();
private List<String> warnings = new ArrayList<>();
Expand Down Expand Up @@ -507,6 +520,10 @@ public List<TestCase> getFailedTestCases() {
return failedTestCases;
}

public List<TestCase> getPassedTestCases() {
return passedTestCases;
}

public List<Path> getCoverageFiles() {
return coverageFiles;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
import com.google.devtools.build.lib.view.test.TestStatus.FailedTestCasesStatus;
import com.google.devtools.build.lib.view.test.TestStatus.TestCase;
import com.google.devtools.build.lib.view.test.TestStatus.TestCase.Status;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -117,26 +118,21 @@ public static void print(
AnsiTerminalPrinter terminalPrinter,
TestLogPathFormatter testLogPathFormatter,
boolean verboseSummary,
boolean printFailedTestCases) {
print(
summary,
terminalPrinter,
testLogPathFormatter,
verboseSummary,
printFailedTestCases,
false);
boolean showAllTestCases) {
print(summary, terminalPrinter, testLogPathFormatter, verboseSummary, showAllTestCases, false);
}

/**
* Prints summary status for a single test.
*
* @param terminalPrinter The printer to print to
*/
public static void print(
TestSummary summary,
AnsiTerminalPrinter terminalPrinter,
TestLogPathFormatter testLogPathFormatter,
boolean verboseSummary,
boolean printFailedTestCases,
boolean showAllTestCases,
boolean withConfigurationName) {
BlazeTestStatus status = summary.getStatus();
// Skip output for tests that failed to build.
Expand All @@ -158,29 +154,35 @@ public static void print(
+ (verboseSummary ? getAttemptSummary(summary) + getTimeSummary(summary) : "")
+ "\n");

if (printFailedTestCases && summary.getStatus() == BlazeTestStatus.FAILED) {
if (summary.getFailedTestCasesStatus() == FailedTestCasesStatus.NOT_AVAILABLE) {
terminalPrinter.print(
Mode.WARNING + " (individual test case information not available) "
+ Mode.DEFAULT + "\n");
} else {
for (TestCase testCase : summary.getFailedTestCases()) {
if (testCase.getStatus() != TestCase.Status.PASSED) {
TestSummaryPrinter.printTestCase(terminalPrinter, testCase);
}
}
if (showAllTestCases) {
for (TestCase testCase : summary.getPassedTestCases()) {
TestSummaryPrinter.printTestCase(terminalPrinter, testCase);
}

if (summary.getFailedTestCasesStatus() != FailedTestCasesStatus.FULL) {
if (summary.getStatus() == BlazeTestStatus.FAILED) {
if (summary.getFailedTestCasesStatus() == FailedTestCasesStatus.NOT_AVAILABLE) {
terminalPrinter.print(
Mode.WARNING
+ " (some shards did not report details, list of failed test"
+ " cases incomplete)\n"
+ Mode.DEFAULT);
+ " (individual test case information not available) "
+ Mode.DEFAULT
+ "\n");
} else {
for (TestCase testCase : summary.getFailedTestCases()) {
if (testCase.getStatus() != TestCase.Status.PASSED) {
TestSummaryPrinter.printTestCase(terminalPrinter, testCase);
}
}

if (summary.getFailedTestCasesStatus() != FailedTestCasesStatus.FULL) {
terminalPrinter.print(
Mode.WARNING
+ " (some shards did not report details, list of failed test"
+ " cases incomplete)\n"
+ Mode.DEFAULT);
}
}
}
}

if (!printFailedTestCases) {
} else {
for (String warning : summary.getWarnings()) {
terminalPrinter.print(" " + AnsiTerminalPrinter.Mode.WARNING + "WARNING: "
+ AnsiTerminalPrinter.Mode.DEFAULT + warning + "\n");
Expand All @@ -205,12 +207,8 @@ public static void print(
}
}

/**
* Prints the result of an individual test case. It is assumed not to have
* passed, since passed test cases are not reported.
*/
static void printTestCase(
AnsiTerminalPrinter terminalPrinter, TestCase testCase) {
/** Prints the result of an individual test case. */
static void printTestCase(AnsiTerminalPrinter terminalPrinter, TestCase testCase) {
String timeSummary;
if (testCase.hasRunDurationMillis()) {
timeSummary = " ("
Expand All @@ -220,16 +218,17 @@ static void printTestCase(
timeSummary = "";
}

Mode mode = (testCase.getStatus() == Status.PASSED) ? Mode.INFO : Mode.ERROR;
terminalPrinter.print(
" "
+ Mode.ERROR
+ Strings.padEnd(testCase.getStatus().toString(), 8, ' ')
+ Mode.DEFAULT
+ testCase.getClassName()
+ "."
+ testCase.getName()
+ timeSummary
+ "\n");
+ mode
+ Strings.padEnd(testCase.getStatus().toString(), 8, ' ')
+ Mode.DEFAULT
+ testCase.getClassName()
+ "."
+ testCase.getName()
+ timeSummary
+ "\n");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,30 @@ public void testTestCaseNamesShownWhenNeeded() throws Exception {
verify(printerFailed).print(find("FAILED.*orange *\\(1\\.5"));
}

@Test
public void testShowTestCaseNames() throws Exception {
TestCase detailPassed = newDetail("strawberry", TestCase.Status.PASSED, 1000L);
TestCase detailFailed = newDetail("orange", TestCase.Status.FAILED, 1500L);

TestSummary summaryPassed =
createPassedTestSummary(BlazeTestStatus.PASSED, Arrays.asList(detailPassed));

TestSummary summaryFailed =
createTestSummaryWithDetails(
BlazeTestStatus.FAILED, Arrays.asList(detailPassed, detailFailed));
assertThat(summaryFailed.getStatus()).isEqualTo(BlazeTestStatus.FAILED);

AnsiTerminalPrinter printerPassed = Mockito.mock(AnsiTerminalPrinter.class);
TestSummaryPrinter.print(summaryPassed, printerPassed, Path::getPathString, true, true);
verify(printerPassed).print(contains("//package:name"));
verify(printerPassed).print(find("PASSED.*strawberry *\\(1\\.0"));

AnsiTerminalPrinter printerFailed = Mockito.mock(AnsiTerminalPrinter.class);
TestSummaryPrinter.print(summaryFailed, printerFailed, Path::getPathString, true, true);
verify(printerFailed).print(contains("//package:name"));
verify(printerFailed).print(find("FAILED.*orange *\\(1\\.5"));
}

@Test
public void testTestCaseNamesOrdered() throws Exception {
TestCase[] details = {
Expand Down Expand Up @@ -500,13 +524,13 @@ public void testCachedResultsFirstInSort() throws Exception {

@Test
public void testCollectingFailedDetails() throws Exception {
TestCase rootCase = TestCase.newBuilder()
.setName("tests")
.setRunDurationMillis(5000L)
.addChild(newDetail("apple", TestCase.Status.FAILED, 1000L))
.addChild(newDetail("banana", TestCase.Status.PASSED, 1000L))
.addChild(newDetail("cherry", TestCase.Status.ERROR, 1000L))
.build();
TestCase rootCase =
TestCase.newBuilder()
.setName("tests")
.setRunDurationMillis(5000L)
.addChild(newDetail("apple", TestCase.Status.FAILED, 1000L))
.addChild(newDetail("cherry", TestCase.Status.ERROR, 1000L))
.build();

TestSummary summary =
getTemplateBuilder().collectTestCases(rootCase).setStatus(BlazeTestStatus.FAILED).build();
Expand All @@ -518,6 +542,46 @@ public void testCollectingFailedDetails() throws Exception {
verify(printer).print(find("ERROR.*cherry"));
}

@Test
public void testCollectingAllDetails() throws Exception {
TestCase rootCase =
TestCase.newBuilder()
.setName("tests")
.setRunDurationMillis(5000L)
.addChild(newDetail("apple", TestCase.Status.FAILED, 1000L))
.addChild(newDetail("banana", TestCase.Status.PASSED, 1000L))
.addChild(newDetail("cherry", TestCase.Status.ERROR, 1000L))
.build();

TestSummary summary =
getTemplateBuilder().collectTestCases(rootCase).setStatus(BlazeTestStatus.FAILED).build();

AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
TestSummaryPrinter.print(summary, printer, Path::getPathString, true, true);
verify(printer).print(contains("//package:name"));
verify(printer).print(find("FAILED.*apple"));
verify(printer).print(find("PASSED.*banana"));
verify(printer).print(find("ERROR.*cherry"));
}

@Test
public void testCollectingPassedDetails() throws Exception {
TestCase rootCase =
TestCase.newBuilder()
.setName("tests")
.setRunDurationMillis(5000L)
.addChild(newDetail("apple", TestCase.Status.PASSED, 1000L))
.build();

TestSummary summary =
getTemplateBuilder().collectTestCases(rootCase).setStatus(BlazeTestStatus.PASSED).build();

AnsiTerminalPrinter printer = Mockito.mock(AnsiTerminalPrinter.class);
TestSummaryPrinter.print(summary, printer, Path::getPathString, true, true);
verify(printer).print(contains("//package:name"));
verify(printer).print(find("PASSED.*apple"));
}

@Test
public void countTotalTestCases() throws Exception {
TestCase rootCase =
Expand Down Expand Up @@ -605,6 +669,10 @@ private ConfiguredTarget stubTarget() throws Exception {
return target(PATH, TARGET_NAME);
}

private TestSummary createPassedTestSummary(BlazeTestStatus status, List<TestCase> details) {
return getTemplateBuilder().setStatus(status).addPassedTestCases(details).build();
}

private TestSummary createTestSummaryWithDetails(BlazeTestStatus status,
List<TestCase> details) {
TestSummary summary = getTemplateBuilder()
Expand Down
15 changes: 14 additions & 1 deletion src/test/shell/bazel/bazel_test_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ EOF
expect_log "name=\"dir/fail\""
}

function test_detailed_test_summary() {
function test_detailed_test_summary_for_failed_test() {
copy_examples
create_workspace_with_default_repos WORKSPACE
setup_javatest_support
Expand All @@ -658,6 +658,19 @@ function test_detailed_test_summary() {
expect_log 'FAILED.*com\.example\.myproject\.Fail\.testFail'
}

function test_detailed_test_summary_for_passed_test() {
copy_examples
create_workspace_with_default_repos WORKSPACE
setup_javatest_support

local java_native_tests=//examples/java-native/src/test/java/com/example/myproject

bazel test --test_summary=detailed "${java_native_tests}:hello" >& $TEST_log \
|| fail "expected success"
expect_log 'PASSED.*com\.example\.myproject\.TestHello\.testNoArgument'
expect_log 'PASSED.*com\.example\.myproject\.TestHello\.testWithArgument'
}

# This test uses "--ignore_all_rc_files" since outside .bazelrc files can pollute
# this environment. Just "--bazelrc=/dev/null" is not sufficient to fix.
function test_flaky_test() {
Expand Down

0 comments on commit 2ebbfeb

Please sign in to comment.