Apply TopLevelStatusEvents to non-Skymeld code path.

So far we've only applied (TopLevelTarget|Aspect)BuiltEvent to the non-Skymeld
code path. This CL applies the rest of the events. Note that we post the events regardless of the value of --experimental_use_event_based_build_completion_status: it should only affect whether we use the result of BuildResultListener in the final result summary.

Also added integration tests for these.

PiperOrigin-RevId: 449685522
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
index 2a461f4..d4d35bf 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.analysis.AnalysisPhaseCompleteEvent;
 import com.google.devtools.build.lib.analysis.AnalysisResult;
 import com.google.devtools.build.lib.analysis.BuildView;
+import com.google.devtools.build.lib.analysis.ConfiguredAspect;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
@@ -46,10 +47,15 @@
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
 import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
 import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
 import com.google.devtools.build.lib.skyframe.BuildInfoCollectionFunction;
 import com.google.devtools.build.lib.skyframe.PrecomputedValue;
 import com.google.devtools.build.lib.skyframe.TargetPatternPhaseValue;
+import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.AspectAnalyzedEvent;
+import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TestAnalyzedEvent;
+import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TopLevelTargetAnalyzedEvent;
+import com.google.devtools.build.lib.skyframe.TopLevelStatusEvents.TopLevelTargetSkippedEvent;
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.RegexFilter;
@@ -57,6 +63,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
@@ -271,9 +278,38 @@
                 analysisResult.getTargetsToTest(),
                 analysisResult.getTargetsToSkip(),
                 configurationMap));
+    postTopLevelStatusEvents(env, analysisResult, configurationMap);
+
     return analysisResult;
   }
 
+  /** Post the appropriate {@link com.google.devtools.build.lib.skyframe.TopLevelStatusEvents}. */
+  private static void postTopLevelStatusEvents(
+      CommandEnvironment env,
+      AnalysisResult analysisResult,
+      Map<BuildConfigurationKey, BuildConfigurationValue> configurationMap) {
+    for (ConfiguredTarget configuredTarget : analysisResult.getTargetsToBuild()) {
+      env.getEventBus().post(TopLevelTargetAnalyzedEvent.create(configuredTarget));
+      if (analysisResult.getTargetsToSkip().contains(configuredTarget)) {
+        env.getEventBus().post(TopLevelTargetSkippedEvent.create(configuredTarget));
+      }
+
+      if (analysisResult.getTargetsToTest() != null
+          && analysisResult.getTargetsToTest().contains(configuredTarget)) {
+        env.getEventBus()
+            .post(
+                TestAnalyzedEvent.create(
+                    configuredTarget,
+                    configurationMap.get(configuredTarget.getConfigurationKey()),
+                    /*isSkipped=*/ analysisResult.getTargetsToSkip().contains(configuredTarget)));
+      }
+    }
+
+    for (Entry<AspectKey, ConfiguredAspect> entry : analysisResult.getAspectsMap().entrySet()) {
+      env.getEventBus().post(AspectAnalyzedEvent.create(entry.getKey(), entry.getValue()));
+    }
+  }
+
   static void reportTargets(
       CommandEnvironment env,
       Collection<ConfiguredTarget> targetsToBuild,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildDriverFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildDriverFunction.java
index b7c0e8b..7f14152 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildDriverFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildDriverFunction.java
@@ -61,6 +61,7 @@
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunction.Environment.SkyKeyComputeState;
 import com.google.devtools.build.skyframe.SkyFunctionException;
+import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.SkyValue;
 import com.google.devtools.build.skyframe.SkyframeIterableResult;
@@ -172,7 +173,9 @@
             // result summary.
             if (!NOT_TEST.equals(buildDriverKey.getTestType())) {
               env.getListener()
-                  .post(TestAnalyzedEvent.createSkipped(configuredTarget, buildConfigurationValue));
+                  .post(
+                      TestAnalyzedEvent.create(
+                          configuredTarget, buildConfigurationValue, /*isSkipped=*/ true));
             }
             // We consider the evaluation of this BuildDriverKey successful at this point, even when
             // the target is skipped.
@@ -301,7 +304,10 @@
       return;
     }
 
-    env.getListener().post(TestAnalyzedEvent.create(configuredTarget, buildConfigurationValue));
+    env.getListener()
+        .post(
+            TestAnalyzedEvent.create(
+                configuredTarget, buildConfigurationValue, /*isSkipped=*/ false));
 
     if (PARALLEL.equals(buildDriverKey.getTestType())) {
       // Only run non-exclusive tests here. Exclusive tests need to be run sequentially later.
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TopLevelStatusEvents.java b/src/main/java/com/google/devtools/build/lib/skyframe/TopLevelStatusEvents.java
index ea5c277..1d40ae4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TopLevelStatusEvents.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TopLevelStatusEvents.java
@@ -33,26 +33,29 @@
 public final class TopLevelStatusEvents {
   private TopLevelStatusEvents() {}
 
+  /** An event that marks the successful analysis of a top-level target, including tests. */
   @AutoValue
-  abstract static class TopLevelTargetAnalyzedEvent implements ProgressLike {
+  public abstract static class TopLevelTargetAnalyzedEvent implements ProgressLike {
     abstract ConfiguredTarget configuredTarget();
 
-    static TopLevelTargetAnalyzedEvent create(ConfiguredTarget configuredTarget) {
+    public static TopLevelTargetAnalyzedEvent create(ConfiguredTarget configuredTarget) {
       return new AutoValue_TopLevelStatusEvents_TopLevelTargetAnalyzedEvent(configuredTarget);
     }
   }
 
+  /** An event that marks the skipping of a top-level target, including skipped tests. */
   @AutoValue
-  abstract static class TopLevelTargetSkippedEvent implements ProgressLike {
+  public abstract static class TopLevelTargetSkippedEvent implements ProgressLike {
     abstract ConfiguredTarget configuredTarget();
 
-    static TopLevelTargetSkippedEvent create(ConfiguredTarget configuredTarget) {
+    public static TopLevelTargetSkippedEvent create(ConfiguredTarget configuredTarget) {
       return new AutoValue_TopLevelStatusEvents_TopLevelTargetSkippedEvent(configuredTarget);
     }
   }
 
+  /** An event that marks the successful build of a top-level target, including tests. */
   @AutoValue
-  abstract static class TopLevelTargetBuiltEvent implements ProgressLike {
+  public abstract static class TopLevelTargetBuiltEvent implements ProgressLike {
     abstract ConfiguredTargetKey configuredTargetKey();
 
     static TopLevelTargetBuiltEvent create(ConfiguredTargetKey configuredTargetKey) {
@@ -69,26 +72,24 @@
 
     public abstract boolean isSkipped();
 
-    static TestAnalyzedEvent create(
-        ConfiguredTarget configuredTarget, BuildConfigurationValue buildConfigurationValue) {
+    public static TestAnalyzedEvent create(
+        ConfiguredTarget configuredTarget,
+        BuildConfigurationValue buildConfigurationValue,
+        boolean isSkipped) {
       return new AutoValue_TopLevelStatusEvents_TestAnalyzedEvent(
-          configuredTarget, buildConfigurationValue, /*isSkipped=*/ false);
-    }
-
-    static TestAnalyzedEvent createSkipped(
-        ConfiguredTarget configuredTarget, BuildConfigurationValue buildConfigurationValue) {
-      return new AutoValue_TopLevelStatusEvents_TestAnalyzedEvent(
-          configuredTarget, buildConfigurationValue, /*isSkipped=*/ true);
+          configuredTarget, buildConfigurationValue, isSkipped);
     }
   }
 
+  /** An event that marks the successful analysis of an aspect. */
   @AutoValue
-  abstract static class AspectAnalyzedEvent implements ProgressLike {
+  public abstract static class AspectAnalyzedEvent implements ProgressLike {
     abstract AspectKey aspectKey();
 
     abstract ConfiguredAspect configuredAspect();
 
-    static AspectAnalyzedEvent create(AspectKey aspectKey, ConfiguredAspect configuredAspect) {
+    public static AspectAnalyzedEvent create(
+        AspectKey aspectKey, ConfiguredAspect configuredAspect) {
       return new AutoValue_TopLevelStatusEvents_AspectAnalyzedEvent(aspectKey, configuredAspect);
     }
   }
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
index 856fef3..27cb567 100644
--- a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
@@ -649,3 +649,20 @@
         "@com_google_testparameterinjector//:testparameterinjector",
     ],
 )
+
+java_test(
+    name = "BuildResultListenerIntegrationTest",
+    srcs = ["BuildResultListenerIntegrationTest.java"],
+    tags = [
+        "no_windows",
+    ],
+    deps = [
+        "//src/main/java/com/google/devtools/build/lib:runtime",
+        "//src/main/java/com/google/devtools/build/lib/actions",
+        "//src/main/java/com/google/devtools/build/lib/analysis:view_creation_failed_exception",
+        "//src/test/java/com/google/devtools/build/lib/buildtool/util",
+        "//third_party:junit4",
+        "//third_party:truth",
+        "@com_google_testparameterinjector//:testparameterinjector",
+    ],
+)
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultListenerIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultListenerIntegrationTest.java
new file mode 100644
index 0000000..85e797d
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/BuildResultListenerIntegrationTest.java
@@ -0,0 +1,242 @@
+// Copyright 2022 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.buildtool;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import com.google.devtools.build.lib.actions.BuildFailedException;
+import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
+import com.google.devtools.build.lib.buildtool.util.BuildIntegrationTestCase;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+import java.io.IOException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Integration test for {@link com.google.devtools.build.lib.skyframe.BuildResultListener}. */
+@RunWith(TestParameterInjector.class)
+public class BuildResultListenerIntegrationTest extends BuildIntegrationTestCase {
+  @TestParameter boolean mergedAnalysisExecution;
+
+  @Before
+  public final void setUp() {
+    addOptions("--experimental_merged_skyframe_analysis_execution=" + mergedAnalysisExecution);
+  }
+
+  /** A simple rule that has srcs, deps and writes these attributes to its output. */
+  private void writeMyRuleBzl() throws IOException {
+    write(
+        "foo/my_rule.bzl",
+        "def _path(file):",
+        "  return file.path",
+        "def _impl(ctx):",
+        "  inputs = depset(",
+        "    ctx.files.srcs, transitive = [dep[DefaultInfo].files for dep in ctx.attr.deps])",
+        "  output = ctx.actions.declare_file(ctx.attr.name + '.out')",
+        "  command = 'echo $@ > %s' % (output.path)",
+        "  args = ctx.actions.args()",
+        "  args.add_all(inputs, map_each=_path)",
+        "  ctx.actions.run_shell(",
+        "    inputs = inputs,",
+        "    outputs = [output],",
+        "    command = command,",
+        "    arguments = [args]",
+        "  )",
+        "  return DefaultInfo(files = depset([output]))",
+        "",
+        "my_rule = rule(",
+        "  implementation = _impl,",
+        "  attrs = {",
+        "    'srcs': attr.label_list(allow_files = True),",
+        "    'deps': attr.label_list(providers = ['DefaultInfo']),",
+        "  }",
+        ")");
+  }
+
+  private void writeAnalysisFailureAspectBzl() throws IOException {
+    write(
+        "foo/aspect.bzl",
+        "def _aspect_impl(target, ctx):",
+        "  malformed",
+        "",
+        "analysis_err_aspect = aspect(implementation = _aspect_impl)");
+  }
+
+  private void writeExecutionFailureAspectBzl() throws IOException {
+    write(
+        "foo/aspect.bzl",
+        "def _aspect_impl(target, ctx):",
+        "  output = ctx.actions.declare_file('aspect_output')",
+        "  ctx.actions.run_shell(",
+        "    outputs = [output],",
+        "    command = 'false',",
+        "  )",
+        "  return [OutputGroupInfo(",
+        "    files = depset([output])",
+        "  )]",
+        "",
+        "execution_err_aspect = aspect(implementation = _aspect_impl)");
+  }
+
+  private void writeSuccessfulAspectBzl() throws IOException {
+    write(
+        "foo/aspect.bzl",
+        "def _aspect_impl(target, ctx):",
+        "  print('hello')",
+        "  return []",
+        "",
+        "successful_aspect = aspect(implementation = _aspect_impl)");
+  }
+
+  private void writeEnvironmentRules(String... defaults) throws Exception {
+    StringBuilder defaultsBuilder = new StringBuilder();
+    for (String defaultEnv : defaults) {
+      defaultsBuilder.append("'").append(defaultEnv).append("', ");
+    }
+
+    write(
+        "buildenv/BUILD",
+        "environment_group(",
+        "    name = 'group',",
+        "    environments = [':one', ':two'],",
+        "    defaults = [" + defaultsBuilder + "])",
+        "environment(name = 'one')",
+        "environment(name = 'two')");
+  }
+
+  @Test
+  public void multiTargetBuild_success() throws Exception {
+    writeMyRuleBzl();
+    writeSuccessfulAspectBzl();
+    write(
+        "foo/BUILD",
+        "load('//foo:my_rule.bzl', 'my_rule')",
+        "my_rule(name = 'bar', srcs = ['bar.in'])",
+        "my_rule(name = 'foo', srcs = ['foo.in'])");
+    write("foo/foo.in");
+    write("foo/bar.in");
+    addOptions("--aspects=//foo:aspect.bzl%successful_aspect");
+
+    BuildResult result = buildTarget("//foo:foo", "//foo:bar");
+
+    assertThat(result.getSuccess()).isTrue();
+    assertThat(getLabelsOfAnalyzedTargets()).containsExactly("//foo:foo", "//foo:bar");
+    assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo", "//foo:bar");
+    assertThat(getLabelsOfAnalyzedAspects()).containsExactly("//foo:foo", "//foo:bar");
+    assertThat(getLabelsOfBuiltAspects()).containsExactly("//foo:foo", "//foo:bar");
+  }
+
+  @Test
+  public void aspectAnalysisFailure_consistentWithNonSkymeld() throws Exception {
+    writeMyRuleBzl();
+    writeAnalysisFailureAspectBzl();
+    write(
+        "foo/BUILD",
+        "load('//foo:my_rule.bzl', 'my_rule')",
+        "my_rule(name = 'foo', srcs = ['foo.in'])");
+    write("foo/foo.in");
+
+    addOptions("--aspects=//foo:aspect.bzl%analysis_err_aspect", "--output_groups=files");
+
+    assertThrows(ViewCreationFailedException.class, () -> buildTarget("//foo:foo"));
+
+    assertThat(getLabelsOfAnalyzedAspects()).isEmpty();
+  }
+
+  @Test
+  public void aspectExecutionFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing)
+      throws Exception {
+    addOptions("--keep_going=" + keepGoing);
+    writeMyRuleBzl();
+    writeExecutionFailureAspectBzl();
+    write(
+        "foo/BUILD",
+        "load('//foo:my_rule.bzl', 'my_rule')",
+        "my_rule(name = 'foo', srcs = ['foo.in'])");
+    write("foo/foo.in");
+
+    addOptions("--aspects=//foo:aspect.bzl%execution_err_aspect", "--output_groups=files");
+
+    assertThrows(BuildFailedException.class, () -> buildTarget("//foo:foo"));
+
+    assertThat(getLabelsOfAnalyzedAspects()).contains("//foo:foo");
+    assertThat(getLabelsOfBuiltAspects()).isEmpty();
+  }
+
+  @Test
+  public void targetExecutionFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing)
+      throws Exception {
+    addOptions("--keep_going=" + keepGoing);
+    writeMyRuleBzl();
+    write(
+        "foo/BUILD",
+        "load('//foo:my_rule.bzl', 'my_rule')",
+        "my_rule(name = 'execution_failure', srcs = ['missing'])",
+        "my_rule(name = 'foo', srcs = ['foo.in'])");
+    write("foo/foo.in");
+
+    assertThrows(
+        BuildFailedException.class, () -> buildTarget("//foo:foo", "//foo:execution_failure"));
+
+    assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:execution_failure");
+    if (keepGoing) {
+      assertThat(getLabelsOfAnalyzedTargets())
+          .containsExactly("//foo:foo", "//foo:execution_failure");
+      assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo");
+    }
+  }
+
+  @Test
+  public void targetAnalysisFailure_consistentWithNonSkymeld(@TestParameter boolean keepGoing)
+      throws Exception {
+    addOptions("--keep_going=" + keepGoing);
+    writeMyRuleBzl();
+    write(
+        "foo/BUILD",
+        "load('//foo:my_rule.bzl', 'my_rule')",
+        "my_rule(name = 'analysis_failure', srcs = ['foo.in'], deps = [':missing'])",
+        "my_rule(name = 'foo', srcs = ['foo.in'])");
+    write("foo/foo.in");
+
+    if (keepGoing) {
+      assertThrows(
+          BuildFailedException.class, () -> buildTarget("//foo:foo", "//foo:analysis_failure"));
+      assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:foo");
+      assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo");
+    } else {
+      assertThrows(
+          ViewCreationFailedException.class,
+          () -> buildTarget("//foo:foo", "//foo:analysis_failure"));
+      assertThat(getBuildResultListener().getBuiltTargets()).isEmpty();
+    }
+  }
+
+  @Test
+  public void targetSkipped_consistentWithNonSkymeld() throws Exception {
+    writeEnvironmentRules();
+    write(
+        "foo/BUILD",
+        "sh_library(name = 'good', srcs = ['bar.sh'], restricted_to = ['//buildenv:one'])",
+        "sh_library(name = 'bad', srcs = ['bar.sh'], compatible_with = ['//buildenv:two'])");
+    write("foo/bar.sh");
+    addOptions("--auto_cpu_environment_group=//buildenv:group", "--cpu=one");
+
+    buildTarget("//foo:all");
+    assertThat(getLabelsOfAnalyzedTargets()).containsExactly("//foo:good", "//foo:bad");
+    assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:good");
+    assertThat(getLabelsOfSkippedTargets()).containsExactly("//foo:bad");
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java
index f2c5daa..268a732 100644
--- a/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/SkymeldBuildIntegrationTest.java
@@ -158,11 +158,6 @@
     assertThrows(BuildFailedException.class, () -> buildTarget("//foo:foo"));
     events.assertContainsError(
         "Action foo/aspect_output failed: (Exit 1): bash failed: error executing command");
-
-    // TODO(b/227138583) Update this.
-    if (mergedAnalysisExecution) {
-      assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:foo");
-    }
   }
 
   @Test
@@ -186,16 +181,6 @@
     }
     events.assertContainsError(
         "Action foo/execution_failure.out failed: missing input file '//foo:missing'");
-
-    // TODO(b/227138583) Update this.
-    if (mergedAnalysisExecution) {
-      assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:execution_failure");
-      if (keepGoing) {
-        assertThat(getLabelsOfAnalyzedTargets())
-            .containsExactly("//foo:foo", "//foo:execution_failure");
-        assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo");
-      }
-    }
   }
 
   @Test
@@ -222,16 +207,6 @@
           () -> buildTarget("//foo:foo", "//foo:analysis_failure"));
     }
     events.assertContainsError("rule '//foo:missing' does not exist");
-
-    // TODO(b/227138583) Update this.
-    if (mergedAnalysisExecution) {
-      if (keepGoing) {
-        assertThat(getLabelsOfAnalyzedTargets()).contains("//foo:foo");
-        assertThat(getLabelsOfBuiltTargets()).containsExactly("//foo:foo");
-      } else {
-        assertThat(getBuildResultListener().getBuiltTargets()).isEmpty();
-      }
-    }
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java
index dea8a7b..6eac64a 100644
--- a/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/util/BuildIntegrationTestCase.java
@@ -196,7 +196,7 @@
   }
 
   @Before
-  public final void createFilesAndMocks() throws Exception  {
+  public final void createFilesAndMocks() throws Exception {
     runPriorToBeforeMethods();
     events.setFailFast(false);
     // TODO(mschaller): This will ignore any attempt by Blaze modules to provide a filesystem;
@@ -218,8 +218,7 @@
             workspace,
             /* defaultSystemJavabase= */ null,
             TestConstants.PRODUCT_NAME);
-    binTools =
-        IntegrationMock.get().getIntegrationBinTools(fileSystem, directories);
+    binTools = IntegrationMock.get().getIntegrationBinTools(fileSystem, directories);
     mockToolsConfig = new MockToolsConfig(workspace, realFileSystem());
     setupMockTools();
     createRuntimeWrapper();
@@ -311,7 +310,7 @@
   }
 
   @After
-  public final void cleanUp() throws Exception  {
+  public final void cleanUp() throws Exception {
     if (subscriberException.getException() != null) {
       throwIfUnchecked(subscriberException.getException());
       throw new RuntimeException(subscriberException.getException());
@@ -398,8 +397,8 @@
   }
 
   /**
-   * Called in #setUp before creating the workspace directory. Subclasses should override this
-   * if they want to a non-standard filesystem setup, e.g. introduce symlinked directories.
+   * Called in #setUp before creating the workspace directory. Subclasses should override this if
+   * they want to a non-standard filesystem setup, e.g. introduce symlinked directories.
    */
   protected void beforeCreatingWorkspace(@SuppressWarnings("unused") Path workspace)
       throws Exception {}
@@ -640,9 +639,7 @@
     return getSkyframeExecutor().getConfiguredTargetForTesting(eventHandler, label, config);
   }
 
-  /**
-   * Gets all the already computed configured targets.
-   */
+  /** Gets all the already computed configured targets. */
   protected Iterable<ConfiguredTarget> getAllConfiguredTargets() {
     return SkyframeExecutorTestUtils.getAllExistingConfiguredTargets(getSkyframeExecutor());
   }
@@ -709,8 +706,9 @@
   }
 
   /**
-   * Creates a BuildRequest for either blaze build or blaze analyze, using the
-   * currently-installed request options.
+   * Creates a BuildRequest for either blaze build or blaze analyze, using the currently-installed
+   * request options.
+   *
    * @param commandName blaze build or analyze command
    * @param targets the targets to be built
    */
@@ -719,9 +717,7 @@
     return runtimeWrapper.createRequest(commandName, Arrays.asList(targets));
   }
 
-  /**
-   * Utility function: parse a string as a label.
-   */
+  /** Utility function: parse a string as a label. */
   protected static Label label(String labelString) throws LabelSyntaxException {
     return Label.parseAbsolute(labelString, ImmutableMap.of());
   }
@@ -731,10 +727,7 @@
     return run(executable.getPath(), null, environment, arguments);
   }
 
-  /**
-   * This runs an executable using the executor instance configured for
-   * this test.
-   */
+  /** This runs an executable using the executor instance configured for this test. */
   protected String run(Path executable, String... arguments) throws Exception {
     Map<String, String> environment = null;
     return run(executable, null, environment, arguments);
@@ -807,9 +800,7 @@
     return writeAbsolute(path, lines);
   }
 
-  /**
-   * Same as {@link #write}, but with an absolute path.
-   */
+  /** Same as {@link #write}, but with an absolute path. */
   protected Path writeAbsolute(Path path, String... lines) throws IOException {
     // Check that the path string encoding matches what is returned by NativePosixFiles. Otherwise,
     // tests may lose fidelity.
@@ -834,9 +825,9 @@
   }
 
   /**
-   * The TimestampGranularityMonitor operates on the files created by the
-   * request and thus does not help here. Calling this method ensures that files
-   * we modify as part of the test environment are considered as changed.
+   * The TimestampGranularityMonitor operates on the files created by the request and thus does not
+   * help here. Calling this method ensures that files we modify as part of the test environment are
+   * considered as changed.
    */
   protected static void waitForTimestampGranularity() throws Exception {
     // Ext4 has a nanosecond granularity. Empirically, tmpfs supports ~5ms increments on
@@ -918,23 +909,17 @@
         .getConfiguration(NullEventHandler.INSTANCE, ct.getConfigurationKey());
   }
 
-  /**
-   * Returns the BuildRequest of the last call to buildTarget().
-   */
+  /** Returns the BuildRequest of the last call to buildTarget(). */
   protected BuildRequest getRequest() {
     return runtimeWrapper.getLastRequest();
   }
 
-  /**
-   * Returns the BuildResultof the last call to buildTarget().
-   */
+  /** Returns the BuildResultof the last call to buildTarget(). */
   protected BuildResult getResult() {
     return runtimeWrapper.getLastResult();
   }
 
-  /**
-   * Returns the {@link BlazeRuntime} in use.
-   */
+  /** Returns the {@link BlazeRuntime} in use. */
   protected BlazeRuntime getRuntime() {
     return runtimeWrapper.getRuntime();
   }
@@ -983,12 +968,36 @@
         .collect(toImmutableList());
   }
 
+  protected ImmutableList<String> getLabelsOfAnalyzedAspects() {
+    return getBuildResultListener().getAnalyzedAspects().keySet().stream()
+        .map(x -> x.getLabel().toString())
+        .collect(toImmutableList());
+  }
+
   protected ImmutableList<String> getLabelsOfBuiltTargets() {
     return getBuildResultListener().getBuiltTargets().stream()
         .map(x -> x.getLabel().toString())
         .collect(toImmutableList());
   }
 
+  protected ImmutableList<String> getLabelsOfBuiltAspects() {
+    return getBuildResultListener().getBuiltAspects().stream()
+        .map(x -> x.getLabel().toString())
+        .collect(toImmutableList());
+  }
+
+  protected ImmutableList<String> getLabelsOfSkippedTargets() {
+    return getBuildResultListener().getSkippedTargets().stream()
+        .map(x -> x.getLabel().toString())
+        .collect(toImmutableList());
+  }
+
+  protected ImmutableList<String> getLabelsOfAnalyzedTests() {
+    return getBuildResultListener().getAnalyzedTests().stream()
+        .map(x -> x.getLabel().toString())
+        .collect(toImmutableList());
+  }
+
   /**
    * Assertion-checks that the expected error was reported,
    */