Migrates TestEnvironmentProvider to using the new Skylark declared providers API. This enables creating a TestEnvironmentProvider from Skylark.

--
PiperOrigin-RevId: 141775285
MOS_MIGRATED_REVID=141775285
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 78877d3..61b8109 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
@@ -216,7 +216,10 @@
             .setInstrumentedFiles(providersBuilder.getProvider(InstrumentedFilesProvider.class));
 
     TestEnvironmentProvider environmentProvider =
-        providersBuilder.getProvider(TestEnvironmentProvider.class);
+        (TestEnvironmentProvider)
+            skylarkDeclaredProviders
+                .build()
+                .get(TestEnvironmentProvider.SKYLARK_CONSTRUCTOR.getKey());
     if (environmentProvider != null) {
       testActionBuilder.addExtraEnv(environmentProvider.getEnvironment());
     }
@@ -310,6 +313,21 @@
   }
 
   /**
+   * Adds "declared providers" defined in native code to the rule. Use this method for declared
+   * providers in definitions of native rules.
+   *
+   * <p>Use {@link #addSkylarkDeclaredProvider(SkylarkClassObject, Location)} for Skylark rule
+   * implementations.
+   */
+  public RuleConfiguredTargetBuilder addNativeDeclaredProviders(
+      Iterable<SkylarkClassObject> providers) {
+    for (SkylarkClassObject provider : providers) {
+      addNativeDeclaredProvider(provider);
+    }
+    return this;
+  }
+
+  /**
    * Adds a "declared provider" defined in native code to the rule.
    * Use this method for declared providers in definitions of native rules.
    *
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 d75b0b4..2902cdc 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
@@ -227,8 +227,8 @@
         .addProvider(xcodeProvider)
         .addProvider(RunfilesProvider.simple(runfiles))
         .addNativeDeclaredProvider(new ExecutionInfoProvider(execInfoMapBuilder.build()))
+        .addNativeDeclaredProviders(testSupport.getExtraProviders())
         .addProvider(InstrumentedFilesProvider.class, instrumentedFilesProvider)
-        .addProviders(testSupport.getExtraProviders())
         .setRunfilesSupport(runfilesSupport, executable)
         .build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
index 8dcab44..a1fb0ac 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/TestSupport.java
@@ -26,11 +26,11 @@
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.Runfiles.Builder;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
-import com.google.devtools.build.lib.analysis.TransitiveInfoProviderMap;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
 import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.packages.SkylarkClassObject;
 import com.google.devtools.build.lib.rules.apple.AppleConfiguration;
 import com.google.devtools.build.lib.rules.apple.DottedVersion;
 import com.google.devtools.build.lib.rules.objc.ObjcRuleClasses.SimulatorRule;
@@ -242,7 +242,7 @@
    * Returns any additional providers that need to be exported to the rule context to the passed
    * builder.
    */
-  public TransitiveInfoProviderMap getExtraProviders() {
+  public Iterable<SkylarkClassObject> getExtraProviders() {
     IosDeviceProvider deviceProvider =
         ruleContext.getPrerequisite(IosTest.TARGET_DEVICE, Mode.TARGET, IosDeviceProvider.class);
     DottedVersion xcodeVersion = deviceProvider.getXcodeVersion();
@@ -260,7 +260,7 @@
       envBuilder.put("APPLE_COVERAGE", "1");
     }
 
-    return TransitiveInfoProviderMap.of(new TestEnvironmentProvider(envBuilder.build()));
+    return ImmutableList.<SkylarkClassObject>of(new TestEnvironmentProvider(envBuilder.build()));
   }
 
   /**
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
index 7714d59..e9d7cdd 100644
--- 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
@@ -59,6 +59,37 @@
         }
       };
 
+  // TODO(bazel-team): Change this BuiltinFunction to be the actual
+  // TestEnvironmentProvider.SKYLARK_CONSTRUCTOR.
+  @SkylarkSignature(
+    name = "TestEnvironment",
+    objectType = SkylarkTestingModule.class,
+    returnType = TestEnvironmentProvider.class,
+    doc =
+        "Creates a new test environment provider. Use this provider to specify extra"
+            + "environment variables to be made available during test execution.",
+    parameters = {
+      @Param(name = "self", type = SkylarkTestingModule.class, doc = "The 'testing' instance."),
+      @Param(
+        name = "environment",
+        type = SkylarkDict.class,
+        named = false,
+        positional = true,
+        doc =
+            "A map of string keys and values that represent environment variables and their values."
+                + " These will be made available during the test execution."
+      )
+    }
+  )
+  public static final BuiltinFunction NEW_TEST_ENVIRONMENT_PROVIDER =
+      new BuiltinFunction("TestEnvironment") {
+        @SuppressWarnings("unused")
+        // This method is registered statically for skylark, and never called directly.
+        public TestEnvironmentProvider invoke(SkylarkTestingModule self, SkylarkDict environment) {
+          return new TestEnvironmentProvider(environment);
+        }
+      };
+
   static {
     SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkTestingModule.class);
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestEnvironmentProvider.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestEnvironmentProvider.java
index 0b8f019..9c81c0c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestEnvironmentProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestEnvironmentProvider.java
@@ -18,20 +18,24 @@
 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;
 
-/**
- * Provider containing any additional environment variables for use in the test action.
- */
+/** Provider containing any additional environment variables for use in the test action. */
 @Immutable
-public final class TestEnvironmentProvider implements TransitiveInfoProvider {
-  private final ImmutableMap<String, String> environment;
+public final class TestEnvironmentProvider extends SkylarkClassObject
+    implements TransitiveInfoProvider {
 
-  /**
-   * Constructs a new provider with the given variable name to variable value mapping.
-   */
-  public TestEnvironmentProvider(ImmutableMap<String, String> environment) {
+  /** Skylark constructor and identifier for TestEnvironmentProvider. */
+  public static final SkylarkClassObjectConstructor SKYLARK_CONSTRUCTOR =
+      SkylarkClassObjectConstructor.createNative("TestEnvironment");
+
+  private final Map<String, String> environment;
+
+  /** Constructs a new provider with the given variable name to variable value mapping. */
+  public TestEnvironmentProvider(Map<String, String> environment) {
+    super(SKYLARK_CONSTRUCTOR, ImmutableMap.<String, Object>of("environment", environment));
     this.environment = Preconditions.checkNotNull(environment);
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModuleTest.java b/src/test/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModuleTest.java
index 786c571..021a963 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/test/SkylarkTestingModuleTest.java
@@ -51,4 +51,31 @@
 
     assertThat(provider.getExecutionInfo().get("requires-darwin")).isEqualTo("1");
   }
+
+  @Test
+  public void testSkylarkRulePropagatesTestEnvironmentProvider() throws Exception {
+    scratch.file("examples/rule/BUILD");
+    scratch.file(
+        "examples/rule/apple_rules.bzl",
+        "def my_rule_impl(ctx):",
+        "   test_env = testing.TestEnvironment({'XCODE_VERSION_OVERRIDE': '7.3.1'})",
+        "   return [test_env]",
+        "my_rule = rule(implementation = my_rule_impl,",
+        "   attrs = {},",
+        ")");
+    scratch.file(
+        "examples/apple_skylark/BUILD",
+        "package(default_visibility = ['//visibility:public'])",
+        "load('/examples/rule/apple_rules', 'my_rule')",
+        "my_rule(",
+        "    name = 'my_target',",
+        ")");
+
+    ConfiguredTarget skylarkTarget = getConfiguredTarget("//examples/apple_skylark:my_target");
+    TestEnvironmentProvider provider =
+        (TestEnvironmentProvider)
+            skylarkTarget.get(TestEnvironmentProvider.SKYLARK_CONSTRUCTOR.getKey());
+
+    assertThat(provider.getEnvironment().get("XCODE_VERSION_OVERRIDE")).isEqualTo("7.3.1");
+  }
 }