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/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
index 3085456..85dd518 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ExperimentalStateTracker.java
@@ -57,6 +57,7 @@
   private int actionsCompleted;
   private int totalTests;
   private int completedTests;
+  private TestSummary mostRecentTest;
   private int failedTests;
   private boolean ok;
 
@@ -169,6 +170,7 @@
 
   public synchronized void testSummary(TestSummary summary) {
     completedTests++;
+    mostRecentTest = summary;
     if (summary.getStatus() != BlazeTestStatus.PASSED) {
       failedTests++;
     }
@@ -196,6 +198,25 @@
     return false;
   }
 
+  /**
+   * Maybe add a note about the last test that passed. Return true, if the note was added (and
+   * hence a line break is appropriate if more data is to come. If a null value is provided for
+   * the terminal writer, only return wether a note would be added.
+   */
+  private boolean maybeShowRecentTest(AnsiTerminalWriter terminalWriter, boolean shortVersion)
+      throws IOException {
+    if (!shortVersion && mostRecentTest != null) {
+      if (terminalWriter != null) {
+        terminalWriter
+            .normal()
+            .append("; recent test: " + mostRecentTest.getTarget().getLabel().toString());
+      }
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   synchronized void writeProgressBar(AnsiTerminalWriter terminalWriter, boolean shortVersion)
       throws IOException {
     if (status != null) {
@@ -229,17 +250,28 @@
     }
     if (runningActions.size() == 0) {
       terminalWriter.normal().append(" no actions running");
+      maybeShowRecentTest(terminalWriter, shortVersion);
     } else if (runningActions.size() == 1) {
       String statusMessage = describeAction(runningActions.peekFirst(), clock.nanoTime());
-      terminalWriter.normal().append(" " + statusMessage);
+      if (maybeShowRecentTest(null, shortVersion)) {
+        // As we will break lines anyway, also show the number of running actions, to keep
+        // things stay roughly in the same place (also compensating for the missing plural-s
+        // in the word action).
+        terminalWriter.normal().append("  1 action running");
+        maybeShowRecentTest(terminalWriter, shortVersion);
+        terminalWriter.normal().newline().append("    " + statusMessage);
+      } else {
+        terminalWriter.normal().append(" " + statusMessage);
+      }
     } else {
       if (shortVersion) {
         String statusMessage = describeAction(runningActions.peekFirst(), clock.nanoTime());
         statusMessage += " ... (" + runningActions.size() + " actions)";
         terminalWriter.normal().append(" " + statusMessage);
       } else {
-        String statusMessage = " " + runningActions.size() + " actions running";
+        String statusMessage = "" + runningActions.size() + " actions running";
         terminalWriter.normal().append(" " + statusMessage);
+        maybeShowRecentTest(terminalWriter, shortVersion);
         sampleOldestActions(terminalWriter);
       }
     }