Fix test rules failing under allow_analysis_failures

Prior to this change, such targets would cause a runtime exception to be thrown due to inconsistent state -- a failing test rule target would lack providers Bazel expected for all test rules.
After this change, Bazel is lenient in such cases, provided allow_analysis_failures is true.

Fixes https://github.com/bazelbuild/bazel-skylib/issues/144 when released into Bazel.

RELNOTES: None.
PiperOrigin-RevId: 250295243
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 7c2c089..15f7937 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -93,6 +93,10 @@
    */
   @Nullable
   public ConfiguredTarget build() throws ActionConflictException {
+    // If allowing analysis failures, the current target may not propagate all of the
+    // expected providers; be lenient on such cases (for example, avoid precondition checks).
+    boolean allowAnalysisFailures = ruleContext.getConfiguration().allowAnalysisFailures();
+
     if (ruleContext.getConfiguration().enforceConstraints()) {
       checkConstraints();
     }
@@ -134,8 +138,13 @@
     // Create test action and artifacts if target was successfully initialized
     // and is a test.
     if (TargetUtils.isTestRule(ruleContext.getTarget())) {
-      Preconditions.checkState(runfilesSupport != null);
-      add(TestProvider.class, initializeTestProvider(filesToRunProvider));
+      if (runfilesSupport != null) {
+        add(TestProvider.class, initializeTestProvider(filesToRunProvider));
+      } else {
+        if (!allowAnalysisFailures) {
+          throw new IllegalStateException("Test rules must have runfiles");
+        }
+      }
     }
 
     ExtraActionArtifactsProvider extraActionsProvider =
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
index 8111e15..d3a853f 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
@@ -2084,6 +2084,29 @@
   }
 
   @Test
+  public void testAnalysisFailureInfo_forTest() throws Exception {
+    scratch.file(
+        "test/extension.bzl",
+        "def custom_rule_impl(ctx):",
+        "   fail('This Is My Failure Message')",
+        "",
+        "custom_test = rule(implementation = custom_rule_impl,",
+        "    test = True)");
+
+    scratch.file(
+        "test/BUILD", "load('//test:extension.bzl', 'custom_test')", "", "custom_test(name = 'r')");
+
+    useConfiguration("--allow_analysis_failures=true");
+
+    ConfiguredTarget target = getConfiguredTarget("//test:r");
+    AnalysisFailureInfo info =
+        (AnalysisFailureInfo) target.get(AnalysisFailureInfo.SKYLARK_CONSTRUCTOR.getKey());
+    AnalysisFailure failure = info.getCauses().toList().get(0);
+    assertThat(failure.getMessage()).contains("This Is My Failure Message");
+    assertThat(failure.getLabel()).isEqualTo(Label.parseAbsoluteUnchecked("//test:r"));
+  }
+
+  @Test
   public void testAnalysisFailureInfoWithOutput() throws Exception {
     scratch.file(
         "test/extension.bzl",