| // Copyright 2015 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.google.devtools.build.lib.runtime; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.ImmutableSortedSet; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.cmdline.LabelSyntaxException; |
| import com.google.devtools.build.lib.cmdline.RepositoryMapping; |
| import com.google.devtools.build.lib.exec.ExecutionOptions; |
| import com.google.devtools.build.lib.exec.ExecutionOptions.TestSummaryFormat; |
| import com.google.devtools.build.lib.util.io.AnsiTerminalPrinter; |
| import com.google.devtools.build.lib.vfs.Path; |
| import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus; |
| import com.google.devtools.build.lib.view.test.TestStatus.TestCase; |
| import com.google.devtools.build.lib.view.test.TestStatus.TestCase.Status; |
| import com.google.devtools.common.options.OptionsParsingResult; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.List; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.mockito.ArgumentCaptor; |
| |
| /** Tests for {@link TerminalTestResultNotifier}. */ |
| @RunWith(JUnit4.class) |
| public final class TerminalTestResultNotifierTest { |
| |
| private static final String SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER = |
| "some targets did not have test case information"; |
| |
| private final OptionsParsingResult optionsParsingResult = mock(OptionsParsingResult.class); |
| private final AnsiTerminalPrinter ansiTerminalPrinter = mock(AnsiTerminalPrinter.class); |
| |
| private BlazeTestStatus targetStatus; |
| private int numFailedTestCases; |
| private int numUnknownTestCases; |
| private int numTotalTestCases; |
| private TestSummaryFormat testSummaryFormat; |
| |
| @Test |
| public void testCaseOption_allPass() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.TESTCASE; |
| numFailedTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.PASSED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains(info("10 passing")); |
| assertThat(printed).contains("0 failing"); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.ERROR.toString()); |
| } |
| |
| @Test |
| public void testCaseOption_allPassButTargetFails() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.TESTCASE; |
| numFailedTestCases = 0; |
| numUnknownTestCases = 10; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains("0 passing"); |
| assertThat(printed).contains("0 failing"); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).contains(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.ERROR.toString()); |
| } |
| |
| @Test |
| public void testCaseOption_someFail() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.TESTCASE; |
| numFailedTestCases = 2; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains(info("8 passing")); |
| assertThat(printed).contains(error("2 failing")); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| } |
| |
| @Test |
| public void shortOption_someFailToBuild() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.SHORT; |
| numFailedTestCases = 0; |
| int numFailedToBuildTestCases = TerminalTestResultNotifier.NUM_FAILED_TO_BUILD + 1; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED_TO_BUILD; |
| |
| printFailedToBuildSummaries(); |
| |
| String skippedMessage = getPrintedMessage(); |
| assertThat(skippedMessage).isEqualTo("(Skipping other failed to build tests)"); |
| |
| ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class); |
| verify(ansiTerminalPrinter, times(numFailedToBuildTestCases)).print(messageCaptor.capture()); |
| List<String> values = messageCaptor.getAllValues(); |
| |
| for (int i = 0; i < numFailedToBuildTestCases - 1; i++) { |
| String message = values.get(i); |
| assertThat(message).contains("//foo/bar:baz"); |
| assertThat(message).contains(BlazeTestStatus.FAILED_TO_BUILD.toString().replace('_', ' ')); |
| } |
| |
| String last = values.get(numFailedToBuildTestCases - 1); |
| assertThat(last).contains("Executed 0 out of 6 tests"); |
| assertThat(last).contains(numFailedToBuildTestCases + " fail to build"); |
| } |
| |
| @Test |
| public void testCaseOption_allFail() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.TESTCASE; |
| numFailedTestCases = 10; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains("0 passing"); |
| assertThat(printed).contains(error("10 failing")); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.INFO.toString()); |
| } |
| |
| @Test |
| public void detailedOption_allPass() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.DETAILED; |
| numFailedTestCases = 0; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.PASSED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains(info("10 passing")); |
| assertThat(printed).contains("0 failing"); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.ERROR.toString()); |
| } |
| |
| @Test |
| public void detailedOption_allPassButTargetFails() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.DETAILED; |
| numFailedTestCases = 0; |
| numUnknownTestCases = 10; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains("0 passing"); |
| assertThat(printed).contains("0 failing"); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).contains(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.ERROR.toString()); |
| } |
| |
| @Test |
| public void detailedOption_someFail() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.DETAILED; |
| numFailedTestCases = 2; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains(info("8 passing")); |
| assertThat(printed).contains(error("2 failing")); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| } |
| |
| @Test |
| public void detailedOption_allFail() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.DETAILED; |
| numFailedTestCases = 10; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| String printed = getPrintedMessage(); |
| assertThat(printed).contains("0 passing"); |
| assertThat(printed).contains(error("10 failing")); |
| assertThat(printed).contains("out of 10 test cases"); |
| assertThat(printed).doesNotContain(SOME_TARGETS_ARE_MISSING_TEST_CASES_DISCLAIMER); |
| assertThat(printed).doesNotContain(AnsiTerminalPrinter.Mode.INFO.toString()); |
| } |
| |
| @Test |
| public void shortOption_noSummaryPrinted() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.SHORT; |
| numFailedTestCases = 2; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| verifyNoSummaryPrinted(); |
| } |
| |
| @Test |
| public void terseOption_noSummaryPrinted() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.TERSE; |
| numFailedTestCases = 2; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| verifyNoSummaryPrinted(); |
| } |
| |
| @Test |
| public void noneOption_noSummaryPrinted() throws Exception { |
| testSummaryFormat = ExecutionOptions.TestSummaryFormat.NONE; |
| numFailedTestCases = 2; |
| numUnknownTestCases = 0; |
| numTotalTestCases = 10; |
| targetStatus = BlazeTestStatus.FAILED; |
| |
| printTestCaseSummary(); |
| |
| verifyNoSummaryPrinted(); |
| } |
| |
| private void printFailedToBuildSummaries() throws LabelSyntaxException { |
| ExecutionOptions executionOptions = ExecutionOptions.DEFAULTS; |
| executionOptions.testSummary = testSummaryFormat; |
| when(optionsParsingResult.getOptions(ExecutionOptions.class)).thenReturn(executionOptions); |
| TestSummaryOptions testSummaryOptions = new TestSummaryOptions(); |
| testSummaryOptions.verboseSummary = true; |
| when(optionsParsingResult.getOptions(TestSummaryOptions.class)).thenReturn(testSummaryOptions); |
| |
| ImmutableSortedSet.Builder<TestSummary> builder = |
| ImmutableSortedSet.orderedBy(Comparator.comparing(o -> o.getLabel().getName())); |
| for (int i = 0; i < TerminalTestResultNotifier.NUM_FAILED_TO_BUILD + 1; i++) { |
| TestSummary testSummary = mock(TestSummary.class); |
| when(testSummary.getTotalTestCases()).thenReturn(0); |
| |
| Label labelA = Label.parseCanonical("//foo/bar:baz" + i); |
| when(testSummary.getFailedTestCases()).thenReturn(ImmutableList.of()); |
| when(testSummary.getStatus()).thenReturn(BlazeTestStatus.FAILED_TO_BUILD); |
| when(testSummary.getLabel()).thenReturn(labelA); |
| |
| builder.add(testSummary); |
| } |
| |
| TerminalTestResultNotifier terminalTestResultNotifier = |
| new TerminalTestResultNotifier( |
| ansiTerminalPrinter, |
| Path::getPathString, |
| optionsParsingResult, |
| RepositoryMapping.ALWAYS_FALLBACK); |
| terminalTestResultNotifier.notify(builder.build(), 0); |
| } |
| |
| private void printTestCaseSummary() throws LabelSyntaxException { |
| ExecutionOptions executionOptions = ExecutionOptions.DEFAULTS; |
| executionOptions.testSummary = testSummaryFormat; |
| when(optionsParsingResult.getOptions(ExecutionOptions.class)).thenReturn(executionOptions); |
| TestSummaryOptions testSummaryOptions = new TestSummaryOptions(); |
| testSummaryOptions.verboseSummary = true; |
| when(optionsParsingResult.getOptions(TestSummaryOptions.class)).thenReturn(testSummaryOptions); |
| |
| TestSummary testSummary = mock(TestSummary.class); |
| when(testSummary.getTotalTestCases()).thenReturn(numTotalTestCases); |
| when(testSummary.getUnkownTestCases()).thenReturn(numUnknownTestCases); |
| TestCase failedTestCase = TestCase.newBuilder().setStatus(Status.FAILED).build(); |
| List<TestCase> failedTestCases = Collections.nCopies(numFailedTestCases, failedTestCase); |
| |
| Label labelA = Label.parseCanonical("//foo/bar:baz"); |
| when(testSummary.getFailedTestCases()).thenReturn(failedTestCases); |
| when(testSummary.getStatus()).thenReturn(targetStatus); |
| when(testSummary.getLabel()).thenReturn(labelA); |
| |
| TerminalTestResultNotifier terminalTestResultNotifier = |
| new TerminalTestResultNotifier( |
| ansiTerminalPrinter, |
| Path::getPathString, |
| optionsParsingResult, |
| RepositoryMapping.ALWAYS_FALLBACK); |
| terminalTestResultNotifier.notify(ImmutableSet.of(testSummary), 1); |
| } |
| |
| private String getPrintedMessage() { |
| ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class); |
| verify(ansiTerminalPrinter).printLn(messageCaptor.capture()); |
| return messageCaptor.getValue(); |
| } |
| |
| private void verifyNoSummaryPrinted() { |
| verify(ansiTerminalPrinter, never()).printLn(any()); |
| } |
| |
| private static String info(String message) { |
| return AnsiTerminalPrinter.Mode.INFO + message + AnsiTerminalPrinter.Mode.DEFAULT; |
| } |
| |
| private static String error(String message) { |
| return AnsiTerminalPrinter.Mode.ERROR + message + AnsiTerminalPrinter.Mode.DEFAULT; |
| } |
| } |