aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar dannark <dannark@google.com>2018-12-31 08:17:04 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2017-12-31 08:19:06 -0800
commit2ef5d2170e0558468b0c0e989b910fbb52e95368 (patch)
tree1d72840b73d97f1a32e81bd29c961f44b04ea1cc /src/main
parent192583d5fbf49f43bc7646e5750647362dfaecfe (diff)
Add android_local_test rule to Bazel.
This rule enables testing android_librarys locally in the jvm (as opposed to on a device). To use this rule with robolectric (robolectric.org), add the following to your WORKSPACE file: http_archive( name = "bazel_android", url = "...", ) load("@bazel_android//:setup_robolectric.bzl", "setup_robolectric") setup_robolectric() and then an android_local_test rule would need to add: "@bazel_android//:robolectric", to its dependencies. android_local_test( name = "MyTest", srcs = ["MyTest.java"], deps = [ "//java/app:lib", "@bazel_android//:robolectric", ], ) RELNOTES[NEW]: New android test rule, android_local_test. PiperOrigin-RevId: 180438995
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTest.java141
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTestRule.java101
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java25
5 files changed, 261 insertions, 9 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 4ca45d08e8..07438ee69b 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -967,6 +967,7 @@ java_library(
"rules/android/android_device_stub_template.txt",
"rules/android/android_instrumentation_test_template.txt",
"rules/android/databinding_annotation_template.txt",
+ "rules/android/robolectric_properties_template.txt",
"rules/android/test_suite_property_name.txt",
],
deps = [
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 1acd502f82..5826e9987f 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
@@ -33,6 +33,7 @@ import com.google.devtools.build.lib.bazel.rules.android.AndroidSdkRepositoryRul
import com.google.devtools.build.lib.bazel.rules.android.BazelAarImportRule;
import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidBinaryRule;
import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidLibraryRule;
+import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidLocalTestRule;
import com.google.devtools.build.lib.bazel.rules.android.BazelAndroidSemantics;
import com.google.devtools.build.lib.bazel.rules.common.BazelFilegroupRule;
import com.google.devtools.build.lib.bazel.rules.cpp.BazelCcBinaryRule;
@@ -485,6 +486,7 @@ public class BazelRuleClassProvider {
builder.addRuleDefinition(new BazelAarImportRule());
builder.addRuleDefinition(new AndroidDeviceRule());
builder.addRuleDefinition(new AndroidLocalTestBaseRule());
+ builder.addRuleDefinition(new BazelAndroidLocalTestRule());
builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon());
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTest.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTest.java
new file mode 100644
index 0000000000..927467a6cd
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTest.java
@@ -0,0 +1,141 @@
+// Copyright 2017 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.bazel.rules.android;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaSemantics;
+import com.google.devtools.build.lib.rules.android.AndroidLocalTestBase;
+import com.google.devtools.build.lib.rules.android.AndroidSdkProvider;
+import com.google.devtools.build.lib.rules.android.AndroidSemantics;
+import com.google.devtools.build.lib.rules.java.JavaCommon;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts.Builder;
+import com.google.devtools.build.lib.rules.java.JavaCompilationHelper;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.util.ShellEscaper;
+
+/** An implementation for the "android_local_test" rule. */
+public class BazelAndroidLocalTest extends AndroidLocalTestBase {
+
+ Artifact androidAllJarsPropFile;
+
+ @Override
+ protected AndroidSemantics createAndroidSemantics() {
+ return BazelAndroidSemantics.INSTANCE;
+ }
+
+ @Override
+ protected JavaSemantics createJavaSemantics() {
+ return BazelJavaSemantics.INSTANCE;
+ }
+
+ @Override
+ protected ImmutableList<String> getJvmFlags(RuleContext ruleContext, String testClass)
+ throws RuleErrorException {
+ Artifact androidAllJarsPropertiesFile = getAndroidAllJarsPropertiesFile(ruleContext);
+
+ return ImmutableList.<String>builder()
+ .addAll(JavaCommon.getJvmFlags(ruleContext))
+ .add("-ea")
+ .add("-Dbazel.test_suite=" + ShellEscaper.escapeString(testClass))
+ .add("-Drobolectric.offline=true")
+ .add(
+ "-Drobolectric-deps.properties=" + androidAllJarsPropertiesFile.getRunfilesPathString())
+ .build();
+ }
+
+ @Override
+ protected String getMainClass(
+ RuleContext ruleContext,
+ JavaSemantics javaSemantics,
+ JavaCompilationHelper helper,
+ Artifact executable,
+ Artifact instrumentationMetadata,
+ Builder javaArtifactsBuilder,
+ JavaTargetAttributes.Builder attributesBuilder)
+ throws InterruptedException, RuleErrorException {
+ // coverage does not yet work with android_local_test
+ if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
+ ruleContext.throwWithRuleError("android_local_test does not yet support coverage");
+ }
+ return "com.google.testing.junit.runner.BazelTestRunner";
+ }
+
+ @Override
+ protected JavaCompilationHelper getJavaCompilationHelperWithDependencies(
+ RuleContext ruleContext,
+ JavaSemantics javaSemantics,
+ JavaCommon javaCommon,
+ JavaTargetAttributes.Builder javaTargetAttributesBuilder) {
+
+ JavaCompilationHelper javaCompilationHelper =
+ new JavaCompilationHelper(
+ ruleContext, javaSemantics, javaCommon.getJavacOpts(), javaTargetAttributesBuilder);
+ javaCompilationHelper.addLibrariesToAttributes(
+ ImmutableList.copyOf(javaCommon.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)));
+
+ javaCompilationHelper.addLibrariesToAttributes(
+ ImmutableList.of(getAndCheckTestSupport(ruleContext)));
+
+ javaTargetAttributesBuilder.setBootClassPath(
+ ImmutableList.of(AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar()));
+ javaTargetAttributesBuilder.addRuntimeClassPathEntry(
+ AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar());
+
+ return javaCompilationHelper;
+ }
+
+ @Override
+ protected TransitiveInfoCollection getAndCheckTestSupport(RuleContext ruleContext) {
+ // Add the unit test support to the list of dependencies.
+ return Iterables.getOnlyElement(ruleContext.getPrerequisites("$testsupport", Mode.TARGET));
+ }
+
+ @Override
+ // Bazel needs the android-all jars properties file in order for robolectric to
+ // run. If it does not find it in the deps of the android_local_test rule, it will
+ // throw an error.
+ protected Artifact getAndroidAllJarsPropertiesFile(RuleContext ruleContext)
+ throws RuleErrorException {
+ if (androidAllJarsPropFile == null) {
+ androidAllJarsPropFile = getAndroidAllJarsPropertiesFileHelper(ruleContext);
+ }
+ return androidAllJarsPropFile;
+ }
+
+ private Artifact getAndroidAllJarsPropertiesFileHelper(RuleContext ruleContext)
+ throws RuleErrorException {
+ Iterable<RunfilesProvider> runfilesProviders =
+ ruleContext.getPrerequisites("deps", Mode.TARGET, RunfilesProvider.class);
+ for (RunfilesProvider runfilesProvider : runfilesProviders) {
+ Runfiles dataRunfiles = runfilesProvider.getDataRunfiles();
+ for (Artifact artifact : dataRunfiles.getAllArtifacts()) {
+ if (artifact.getFilename().equals("robolectric-deps.properties")) {
+ return artifact;
+ }
+ }
+ }
+ ruleContext.throwWithRuleError(
+ "'robolectric-deps.properties' not found in" + " the deps of the rule.");
+ return null;
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTestRule.java
new file mode 100644
index 0000000000..7f1bc69ff1
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/android/BazelAndroidLocalTestRule.java
@@ -0,0 +1,101 @@
+// Copyright 2017 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.bazel.rules.android;
+
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+import static com.google.devtools.build.lib.packages.BuildType.TRISTATE;
+import static com.google.devtools.build.lib.packages.ImplicitOutputsFunction.fromFunctions;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.analysis.BaseRuleClasses;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.bazel.rules.java.BazelJavaRuleClasses.BaseJavaBinaryRule;
+import com.google.devtools.build.lib.packages.ImplicitOutputsFunction;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
+import com.google.devtools.build.lib.packages.TriState;
+import com.google.devtools.build.lib.rules.android.AndroidFeatureFlagSetProvider;
+import com.google.devtools.build.lib.rules.android.AndroidLocalTestBaseRule;
+import com.google.devtools.build.lib.rules.config.ConfigFeatureFlagTransitionFactory;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
+import com.google.devtools.build.lib.rules.java.JavaInfo;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.Jvm;
+
+/** Rule definition for Bazel android_local_test */
+public class BazelAndroidLocalTestRule implements RuleDefinition {
+
+ protected static final String JUNIT_TESTRUNNER = "//tools/jdk:TestRunner_deploy.jar";
+
+ private static final ImmutableCollection<String> ALLOWED_RULES_IN_DEPS =
+ ImmutableSet.of(
+ "aar_import",
+ "android_library",
+ "java_import",
+ "java_library",
+ "java_lite_proto_library");
+
+ static final ImplicitOutputsFunction ANDROID_ROBOLECTRIC_IMPLICIT_OUTPUTS =
+ fromFunctions(JavaSemantics.JAVA_BINARY_CLASS_JAR, JavaSemantics.JAVA_BINARY_SOURCE_JAR);
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .requiresConfigurationFragments(JavaConfiguration.class, Jvm.class)
+ .setImplicitOutputsFunction(ANDROID_ROBOLECTRIC_IMPLICIT_OUTPUTS)
+ .override(
+ attr("deps", LABEL_LIST)
+ .allowedFileTypes()
+ .allowedRuleClasses(ALLOWED_RULES_IN_DEPS)
+ .mandatoryProvidersList(
+ ImmutableList.of(
+ ImmutableList.of(
+ SkylarkProviderIdentifier.forKey(JavaInfo.PROVIDER.getKey())))))
+ .override(attr("$testsupport", LABEL).value(environment.getToolsLabel(JUNIT_TESTRUNNER)))
+ .override(attr("stamp", TRISTATE).value(TriState.NO))
+ .removeAttribute("$experimental_testsupport")
+ .removeAttribute("classpath_resources")
+ .removeAttribute("create_executable")
+ .removeAttribute("deploy_manifest_lines")
+ .removeAttribute("distribs")
+ .removeAttribute("launcher")
+ .removeAttribute("main_class")
+ .removeAttribute("resources")
+ .removeAttribute("use_testrunner")
+ .removeAttribute(":java_launcher")
+ .cfg(
+ new ConfigFeatureFlagTransitionFactory(AndroidFeatureFlagSetProvider.FEATURE_FLAG_ATTR))
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name("android_local_test")
+ .type(RuleClassType.TEST)
+ .ancestors(
+ AndroidLocalTestBaseRule.class,
+ BaseJavaBinaryRule.class,
+ BaseRuleClasses.TestBaseRule.class)
+ .factoryClass(BazelAndroidLocalTest.class)
+ .build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index ad084013fc..338f878963 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -65,6 +65,7 @@ import com.google.devtools.build.lib.util.OS;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
import java.util.List;
+import javax.annotation.Nullable;
/** A base implementation for the "android_local_test" rule. */
public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactory {
@@ -82,8 +83,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
// Use the regular Java javacopts. Enforcing android-compatible Java
// (-source 7 -target 7 and no TWR) is unnecessary for robolectric tests
// since they run on a JVM, not an android device.
- JavaTargetAttributes.Builder attributesBuilder =
- getJavaTargetAttributes(ruleContext, javaCommon);
+ JavaTargetAttributes.Builder attributesBuilder = javaCommon.initCommon();
// Create the final merged manifest
ResourceDependencies resourceDependencies =
@@ -351,7 +351,6 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
private void compileResourceJar(
RuleContext ruleContext, ResourceApk resourceApk, Artifact resourceClassJar)
throws InterruptedException, RuleErrorException {
-
if (resourceApk.getResourceJavaClassJar() == null) {
new RClassGeneratorActionBuilder(ruleContext)
.targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext))
@@ -435,6 +434,12 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
if (ruleContext.isAttrDefined("$robolectric", LABEL_LIST)) {
depsForRunfiles.addAll(ruleContext.getPrerequisites("$robolectric", Mode.TARGET));
}
+
+ Artifact androidAllJarsPropertiesFile = getAndroidAllJarsPropertiesFile(ruleContext);
+ if (androidAllJarsPropertiesFile != null) {
+ builder.addArtifact(androidAllJarsPropertiesFile);
+ }
+
depsForRunfiles.addAll(ruleContext.getPrerequisites("runtime_deps", Mode.TARGET));
builder.addArtifacts(getRuntimeJarsForTargets(getAndCheckTestSupport(ruleContext)));
@@ -520,12 +525,9 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
/** Get AndroidSemantics */
protected abstract AndroidSemantics createAndroidSemantics();
- /** Get JavaTargetAttributes Builder */
- protected abstract JavaTargetAttributes.Builder getJavaTargetAttributes(
- RuleContext ruleContext, JavaCommon javaCommon);
-
/** Set test and robolectric specific jvm flags */
- protected abstract ImmutableList<String> getJvmFlags(RuleContext ruleContext, String testClass);
+ protected abstract ImmutableList<String> getJvmFlags(RuleContext ruleContext, String testClass)
+ throws RuleErrorException;
/** Return the testrunner main class */
protected abstract String getMainClass(
@@ -536,7 +538,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
Artifact instrumentationMetadata,
JavaCompilationArtifacts.Builder javaArtifactsBuilder,
JavaTargetAttributes.Builder attributesBuilder)
- throws InterruptedException;
+ throws InterruptedException, RuleErrorException;
/**
* Add compilation dependencies to the java compilation helper.
@@ -553,4 +555,9 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
/** Get the testrunner from the rule */
protected abstract TransitiveInfoCollection getAndCheckTestSupport(RuleContext ruleContext)
throws RuleErrorException;
+
+ /** Get the android-all jars properties file from the deps */
+ @Nullable
+ protected abstract Artifact getAndroidAllJarsPropertiesFile(RuleContext ruleContext)
+ throws RuleErrorException;
}