experimental UI: track touched packages during loading/analysis

To give a better understanding of which packages are on the critical
path during loading and analysis, provide information in the same way
as during execution: show the earliest started, but not yet completed
package. As not all packages looked at during the analysis phase are
reported to the progress receiver, use a custom class to aggregate those
data.

--
Change-Id: I03c25efdecb4124e1bc06fce8be9175dc56b5500
Reviewed-on: https://bazel-review.googlesource.com/#/c/3700
MOS_MIGRATED_REVID=123408689
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 a276bc5..ae6ec13 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
@@ -27,9 +27,12 @@
 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.skyframe.LoadingPhaseStartedEvent;
+import com.google.devtools.build.lib.skyframe.PackageProgressReceiver;
 import com.google.devtools.build.lib.testutil.FoundationTestCase;
 import com.google.devtools.build.lib.testutil.LoggingTerminalWriter;
 import com.google.devtools.build.lib.testutil.ManualClock;
+import com.google.devtools.build.lib.util.Pair;
 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;
@@ -67,6 +70,35 @@
   }
 
   @Test
+  public void testLoadingActivity() throws IOException {
+    // During loading phase, state and activity, as reported by the PackageProgressReceiver,
+    // should be visible in the progress bar.
+    String state = "42 packages loaded";
+    String activity = "currently loading //src/foo/bar and 17 more";
+    PackageProgressReceiver progress = Mockito.mock(PackageProgressReceiver.class);
+    when(progress.progressState()).thenReturn(new Pair<String, String>(state, activity));
+
+    ManualClock clock = new ManualClock();
+    ExperimentalStateTracker stateTracker = new ExperimentalStateTracker(clock);
+
+    stateTracker.loadingStarted(new LoadingPhaseStartedEvent(progress));
+
+    LoggingTerminalWriter terminalWriter = new LoggingTerminalWriter(/*discardHighlight=*/ true);
+    stateTracker.writeProgressBar(terminalWriter);
+    String output = terminalWriter.getTranscript();
+
+    assertTrue(
+        "Output should indicate that we are in the loading phase, but was:\n" + output,
+        output.contains("Loading"));
+    assertTrue(
+        "Output should contain loading state '" + state + "', but was:\n" + output,
+        output.contains(state));
+    assertTrue(
+        "Output should contain loading state '" + activity + "', but was:\n" + output,
+        output.contains(activity));
+  }
+
+  @Test
   public void testActionVisible() throws IOException {
     // If there is only one action running, it should be visible
     // somewhere in the progress bar, and also the short version thereof.