experimental UI: show passed and failed tests

In the experimental UI, show the most recent finished test in the (long) progress bar.
For failed test, immediately write an entry to the scroll-back buffer. In this
way, the user can get an already investigate test failures while other tests are
still running.

--
Change-Id: I5df29dc55b979c8547e99e9ac3f60563736b48e8
Reviewed-on: https://bazel-review.googlesource.com/#/c/3351
MOS_MIGRATED_REVID=119732631
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java b/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
index bf53b69..236f469 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/ExperimentalStateTrackerTest.java
@@ -25,11 +25,13 @@
 import com.google.devtools.build.lib.actions.Root;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
 import com.google.devtools.build.lib.testutil.ManualClock;
 import com.google.devtools.build.lib.util.io.AnsiTerminalWriter;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.view.test.TestStatus.BlazeTestStatus;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -251,15 +253,19 @@
   }
 
   @Test
-  public void testCountVisible() throws IOException {
+  public void testCountVisible() throws Exception {
     // The test count should be visible in the status bar, as well as the short status bar
     ManualClock clock = new ManualClock();
     ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
     TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
+    Label labelA = Label.parseAbsolute("//foo/bar:baz");
     ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
+    when(targetA.getLabel()).thenReturn(labelA);
     ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
     when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
     TestSummary testSummary = Mockito.mock(TestSummary.class);
+    when(testSummary.getTarget()).thenReturn(targetA);
+
     stateTracker.testFilteringComplete(filteringComplete);
     stateTracker.testSummary(testSummary);
 
@@ -275,4 +281,31 @@
     assertTrue(
         "Test count should be visible in short output: " + output, output.contains(" 1 / 2 tests"));
   }
+
+  @Test
+  public void testPassedVisible() throws Exception {
+    // The last test that passed should still be visible in the long status bar.
+    ManualClock clock = new ManualClock();
+    ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
+    TestFilteringCompleteEvent filteringComplete = Mockito.mock(TestFilteringCompleteEvent.class);
+    Label labelA = Label.parseAbsolute("//foo/bar:baz");
+    ConfiguredTarget targetA = Mockito.mock(ConfiguredTarget.class);
+    when(targetA.getLabel()).thenReturn(labelA);
+    ConfiguredTarget targetB = Mockito.mock(ConfiguredTarget.class);
+    when(filteringComplete.getTestTargets()).thenReturn(ImmutableSet.of(targetA, targetB));
+    TestSummary testSummary = Mockito.mock(TestSummary.class);
+    when(testSummary.getStatus()).thenReturn(BlazeTestStatus.PASSED);
+    when(testSummary.getTarget()).thenReturn(targetA);
+
+    stateTracker.testFilteringComplete(filteringComplete);
+    stateTracker.testSummary(testSummary);
+
+    LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter();
+    stateTracker.writeProgressBar(terminalWriter);
+    String output = terminalWriter.getWritten();
+
+    assertTrue(
+        "Label " + labelA.toString() + " should be present in progress bar: " + output,
+        output.contains(labelA.toString()));
+  }
 }