Add a testing Skylark module that exposes an ExecutionInfoProvider constructor.

--
PiperOrigin-RevId: 141594768
MOS_MIGRATED_REVID=141594768
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java
index 495d5eb..1abc893 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisUtils.java
@@ -25,6 +25,8 @@
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
 import com.google.devtools.build.lib.packages.TriState;
 import com.google.devtools.build.lib.vfs.PathFragment;
 
@@ -77,6 +79,23 @@
   }
 
   /**
+   * Returns the list of declared providers (native and Skylark) of the specified Skylark key from a
+   * set of transitive info collections.
+   */
+  public static Iterable<SkylarkClassObject> getProviders(
+      Iterable<? extends TransitiveInfoCollection> prerequisites,
+      final SkylarkClassObjectConstructor.Key skylarkKey) {
+    ImmutableList.Builder<SkylarkClassObject> result = ImmutableList.builder();
+    for (TransitiveInfoCollection prerequisite : prerequisites) {
+      SkylarkClassObject prerequisiteProvider = prerequisite.get(skylarkKey);
+      if (prerequisiteProvider != null) {
+        result.add(prerequisiteProvider);
+      }
+    }
+    return result.build();
+  }
+
+  /**
    * Returns the iterable of collections that have the specified provider.
    */
   public static <S extends TransitiveInfoCollection, C extends TransitiveInfoProvider> Iterable<S>
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 0047976..78877d3 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
@@ -224,7 +224,11 @@
     TestParams testParams =
         testActionBuilder
             .setFilesToRunProvider(filesToRunProvider)
-            .setExecutionRequirements(providersBuilder.getProvider(ExecutionInfoProvider.class))
+            .setExecutionRequirements(
+                (ExecutionInfoProvider)
+                    skylarkDeclaredProviders
+                        .build()
+                        .get(ExecutionInfoProvider.SKYLARK_CONSTRUCTOR.getKey()))
             .setShardCount(explicitShardCount)
             .build();
     ImmutableList<String> testTags = ImmutableList.copyOf(ruleContext.getRule().getRuleTags());
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index fad548a..879a1bb 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -71,6 +71,8 @@
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
 import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TargetUtils;
@@ -838,6 +840,15 @@
   }
 
   /**
+   * Returns all the declared providers (native and Skylark) for the specified constructor under the
+   * specified attribute of this target in the BUILD file.
+   */
+  public Iterable<SkylarkClassObject> getPrerequisites(
+      String attributeName, Mode mode, final SkylarkClassObjectConstructor.Key skylarkKey) {
+    return AnalysisUtils.getProviders(getPrerequisites(attributeName, mode), skylarkKey);
+  }
+
+  /**
    * Returns all the providers of the specified type that are listed under the specified attribute
    * of this target in the BUILD file, and that contain the specified provider.
    */
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index ef82170..5497fc8 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -162,6 +162,7 @@
 import com.google.devtools.build.lib.rules.repository.LocalRepositoryRule;
 import com.google.devtools.build.lib.rules.repository.NewLocalRepositoryRule;
 import com.google.devtools.build.lib.rules.repository.WorkspaceBaseRule;
+import com.google.devtools.build.lib.rules.test.SkylarkTestingModule;
 import com.google.devtools.build.lib.rules.test.TestSuiteRule;
 import com.google.devtools.build.lib.syntax.Type;
 import com.google.devtools.build.lib.util.ResourceFileLoader;
@@ -277,6 +278,7 @@
     OBJC_RULES.init(builder);
     J2OBJC_RULES.init(builder);
     ANDROID_STUDIO_ASPECT.init(builder);
+    TESTING_SUPPORT.init(builder);
     VARIOUS_WORKSPACE_RULES.init(builder);
 
     // This rule is a little special: it needs to depend on every configuration fragment that has
@@ -383,6 +385,19 @@
         }
       };
 
+  public static final RuleSet TESTING_SUPPORT =
+      new RuleSet() {
+        @Override
+        public void init(Builder builder) {
+          builder.addSkylarkAccessibleTopLevels("testing", new SkylarkTestingModule());
+        }
+
+        @Override
+        public ImmutableList<RuleSet> requires() {
+          return ImmutableList.of(CORE_RULES);
+        }
+      };
+
   public static final RuleSet SH_RULES =
       new RuleSet() {
         @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index a1fa0a8..1cb110a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -362,8 +362,7 @@
     // Support test execution on darwin.
     if (Platform.isApplePlatform(cppConfiguration.getTargetCpu())
         && TargetUtils.isTestRule(ruleContext.getRule())) {
-      ruleBuilder.add(
-          ExecutionInfoProvider.class,
+      ruleBuilder.addNativeDeclaredProvider(
           new ExecutionInfoProvider(ImmutableMap.of("requires-darwin", "")));
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
index 46ddaf4..d75b0b4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosTest.java
@@ -226,7 +226,7 @@
         .setFilesToBuild(filesToBuildBuilder.build())
         .addProvider(xcodeProvider)
         .addProvider(RunfilesProvider.simple(runfiles))
-        .addProvider(new ExecutionInfoProvider(execInfoMapBuilder.build()))
+        .addNativeDeclaredProvider(new ExecutionInfoProvider(execInfoMapBuilder.build()))
         .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider)
         .addProviders(testSupport.getExtraProviders())
         .setRunfilesSupport(runfilesSupport, executable)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/ExecutionInfoProvider.java b/src/main/java/com/google/devtools/build/lib/rules/test/ExecutionInfoProvider.java
index 5eb084e..37639c6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/ExecutionInfoProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/ExecutionInfoProvider.java
@@ -16,7 +16,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
+import com.google.devtools.build.lib.packages.SkylarkClassObjectConstructor;
 import java.util.Map;
 
 /**
@@ -24,11 +25,17 @@
  * tests).
  */
 @Immutable
-public final class ExecutionInfoProvider implements TransitiveInfoProvider {
+public final class ExecutionInfoProvider extends SkylarkClassObject
+    implements TransitiveInfoProvider {
+
+  /** Skylark constructor and identifier for ExecutionInfoProvider. */
+  public static final SkylarkClassObjectConstructor SKYLARK_CONSTRUCTOR =
+      SkylarkClassObjectConstructor.createNative("ExecutionInfo");
 
   private final ImmutableMap<String, String> executionInfo;
 
   public ExecutionInfoProvider(Map<String, String> requirements) {
+    super(SKYLARK_CONSTRUCTOR, ImmutableMap.<String, Object>of("requirements", requirements));
     this.executionInfo = ImmutableMap.copyOf(requirements);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModule.java b/src/main/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModule.java
new file mode 100644
index 0000000..7714d59
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModule.java
@@ -0,0 +1,65 @@
+// Copyright 2016 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.rules.test;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.BuiltinFunction;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
+
+/** A class that exposes testing infrastructure to skylark. */
+@SkylarkModule(
+  name = "testing",
+  doc = "Helper methods for skylark to access testing infrastructure."
+)
+public class SkylarkTestingModule {
+
+  // TODO(bazel-team): Change this BuiltinFunction to be the actual
+  // ExecutionInfoProvider.SKYLARK_CONSTRUCTOR.
+  @SkylarkSignature(
+    name = "ExecutionInfo",
+    objectType = SkylarkTestingModule.class,
+    returnType = ExecutionInfoProvider.class,
+    doc =
+        "Creates a new execution info provider. Use this provider to specify special"
+            + "environments requirements needed to run tests.",
+    parameters = {
+      @Param(name = "self", type = SkylarkTestingModule.class, doc = "The 'testing' instance."),
+      @Param(
+        name = "requirements",
+        type = SkylarkDict.class,
+        named = false,
+        positional = true,
+        doc =
+            "A map of string keys and values to indicate special execution requirements, such as"
+                + " hardware platforms, etc. These keys and values are passed to the executor of"
+                + " the test action as parameters to configure the execution environment."
+      )
+    }
+  )
+  public static final BuiltinFunction NEW_EXECUTION_INFO_PROVIDER =
+      new BuiltinFunction("ExecutionInfo") {
+        @SuppressWarnings("unused")
+        // This method is registered statically for skylark, and never called directly.
+        public ExecutionInfoProvider invoke(SkylarkTestingModule self, SkylarkDict requirements) {
+          return new ExecutionInfoProvider(requirements);
+        }
+      };
+
+  static {
+    SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkTestingModule.class);
+  }
+}