Skip to content

Commit

Permalink
Modify android_instrumentation_test.instrumentation to accept android…
Browse files Browse the repository at this point in the history
…_binary instead of android_instrumentation.

GITHUB: bazelbuild#903

RELNOTES: None.
PiperOrigin-RevId: 173572553
  • Loading branch information
jin authored and dslomov committed Oct 27, 2017
1 parent 67deac4 commit 19c5039
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,43 @@
import com.google.devtools.build.lib.analysis.test.ExecutionInfo;
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.BuildType;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.ResourceFileLoader;
import java.io.IOException;
import javax.annotation.Nullable;

/** An implementation of the {@code android_instrumentation} rule. */
/** An implementation of the {@code android_instrumentation_test} rule. */
public class AndroidInstrumentationTest implements RuleConfiguredTargetFactory {

private static final Template ANDROID_INSTRUMENTATION_TEST_STUB_SCRIPT =
Template.forResource(
AndroidInstrumentationTest.class, "android_instrumentation_test_template.txt");
private static final String TEST_SUITE_PROPERTY_NAME_FILE = "test_suite_property_name.txt";

/** Checks expected rule invariants, throws rule errors if anything is set wrong. */
private static void validateRuleContext(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
if (getInstrumentationProvider(ruleContext) == null) {
ruleContext.throwWithAttributeError(
"instrumentation",
String.format(
"The android_binary target at %s is missing an 'instruments' attribute. Please set "
+ "it as the label of the android_binary under test.",
ruleContext.attributes().get("instrumentation", BuildType.LABEL)));
}
}

@Override
public ConfiguredTarget create(RuleContext ruleContext)
throws InterruptedException, RuleErrorException {
validateRuleContext(ruleContext);

// The wrapper script that invokes the test entry point.
Artifact testExecutable = createTestExecutable(ruleContext);

ImmutableList<TransitiveInfoCollection> runfilesDeps =
ImmutableList.<TransitiveInfoCollection>builder()
.addAll(ruleContext.getPrerequisites("instrumentations", Mode.TARGET))
.addAll(ruleContext.getPrerequisites("fixtures", Mode.TARGET))
.add(ruleContext.getPrerequisite("target_device", Mode.HOST))
.add(ruleContext.getPrerequisite("$test_entry_point", Mode.HOST))
Expand All @@ -65,6 +80,8 @@ public ConfiguredTarget create(RuleContext ruleContext)
Runfiles runfiles =
new Runfiles.Builder(ruleContext.getWorkspaceName())
.addArtifact(testExecutable)
.addArtifact(getInstrumentationApk(ruleContext))
.addArtifact(getTargetApk(ruleContext))
.addTargets(runfilesDeps, RunfilesProvider.DEFAULT_RUNFILES)
.addTransitiveArtifacts(AndroidCommon.getSupportApks(ruleContext))
.addTransitiveArtifacts(getAdb(ruleContext).getFilesToRun())
Expand Down Expand Up @@ -105,9 +122,8 @@ private ImmutableList<Substitution> getTemplateSubstitutions(RuleContext ruleCon
.add(executableSubstitution("%adb%", getAdb(ruleContext)))
.add(executableSubstitution("%device_script%", getTargetDevice(ruleContext)))
.add(executableSubstitution("%test_entry_point%", getTestEntryPoint(ruleContext)))
.add(artifactListSubstitution("%target_apks%", getTargetApks(ruleContext)))
.add(
artifactListSubstitution("%instrumentation_apks%", getInstrumentationApks(ruleContext)))
.add(artifactSubstitution("%target_apk%", getTargetApk(ruleContext)))
.add(artifactSubstitution("%instrumentation_apk%", getInstrumentationApk(ruleContext)))
.add(artifactListSubstitution("%support_apks%", getAllSupportApks(ruleContext)))
.add(Substitution.ofSpaceSeparatedMap("%test_args%", getTestArgs(ruleContext)))
.add(Substitution.ofSpaceSeparatedMap("%fixture_args%", getFixtureArgs(ruleContext)))
Expand Down Expand Up @@ -167,6 +183,10 @@ private static Substitution executableSubstitution(
return Substitution.of(key, filesToRunProvider.getExecutable().getRunfilesPathString());
}

private static Substitution artifactSubstitution(String key, Artifact artifact) {
return Substitution.of(key, artifact.getRunfilesPathString());
}

private static Substitution artifactListSubstitution(String key, Iterable<Artifact> artifacts) {
return Substitution.ofSpaceSeparatedList(
key,
Expand All @@ -175,26 +195,25 @@ private static Substitution artifactListSubstitution(String key, Iterable<Artifa
.collect(ImmutableList.toImmutableList()));
}

/**
* The target APKs from each {@code android_instrumentation} in the {@code instrumentations}
* attribute.
*/
private static Iterable<Artifact> getTargetApks(RuleContext ruleContext) {
return Iterables.transform(
ruleContext.getPrerequisites(
"instrumentations", Mode.TARGET, AndroidInstrumentationInfo.PROVIDER),
AndroidInstrumentationInfo::getTargetApk);
@Nullable
private static AndroidInstrumentationInfo getInstrumentationProvider(RuleContext ruleContext) {
return ruleContext.getPrerequisite(
"instrumentation", Mode.TARGET, AndroidInstrumentationInfo.PROVIDER);
}

/** The target APK from the {@code android_binary} in the {@code instrumentation} attribute. */
@Nullable
private static Artifact getTargetApk(RuleContext ruleContext) {
return getInstrumentationProvider(ruleContext).getTargetApk();
}

/**
* The instrumentation APKs from each {@code android_instrumentation} in the {@code
* instrumentations} attribute.
* The instrumentation APK from the {@code android_binary} in the {@code instrumentation}
* attribute.
*/
private static Iterable<Artifact> getInstrumentationApks(RuleContext ruleContext) {
return Iterables.transform(
ruleContext.getPrerequisites(
"instrumentations", Mode.TARGET, AndroidInstrumentationInfo.PROVIDER),
AndroidInstrumentationInfo::getInstrumentationApk);
@Nullable
private static Artifact getInstrumentationApk(RuleContext ruleContext) {
return getInstrumentationProvider(ruleContext).getInstrumentationApk();
}

/** The support APKs from the {@code support_apks} and {@code fixtures} attributes. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
return builder
.setUndocumented()
.add(
attr("instrumentations", LABEL_LIST)
attr("instrumentation", LABEL)
.mandatory()
.allowedFileTypes(FileTypeSet.NO_FILE)
.allowedRuleClasses("android_instrumentation"))
.allowedRuleClasses("android_binary"))
.add(
attr("target_device", LABEL)
.mandatory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,14 @@ data_deps=$(join_paths ${WORKSPACE_DIR} "," ${data_deps})
device_broker_type="%device_broker_type%"
test_label="%test_label%"

target_apks="%target_apks%"
target_apks=$(join_paths ${WORKSPACE_DIR} "," ${target_apks})
target_apk="%target_apk%"

instrumentation_apks="%instrumentation_apks%"
instrumentation_apks=$(join_paths ${WORKSPACE_DIR} "," ${instrumentation_apks})
instrumentation_apk="%instrumentation_apk%"

support_apks="%support_apks%"
support_apks=$(join_paths ${WORKSPACE_DIR} "," ${support_apks})

apks_to_install="${support_apks}${target_apks}${instrumentation_apks}"
apks_to_install="${support_apks}${target_apk},${instrumentation_apk}"

declare -A device_script_fixtures=( %device_script_fixtures% )

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ public void setup() throws Exception {
scratch.file(
"java/com/app/BUILD",
"android_binary(",
" name = 'app1',",
" manifest = 'AndroidManifest.xml',",
")",
"android_binary(",
" name = 'app2',",
" name = 'app',",
" manifest = 'AndroidManifest.xml',",
")",
"android_binary(",
Expand All @@ -52,23 +48,10 @@ public void setup() throws Exception {
scratch.file(
"javatests/com/app/BUILD",
"android_binary(",
" name = 'instrumentation_app1',",
" manifest = 'AndroidManifest.xml',",
")",
"android_instrumentation(",
" name = 'instrumentation1',",
" target = '//java/com/app:app1',",
" instrumentation = ':instrumentation_app1',",
")",
"android_binary(",
" name = 'instrumentation_app2',",
" name = 'instrumentation_app',",
" instruments = '//java/com/app',",
" manifest = 'AndroidManifest.xml',",
")",
"android_instrumentation(",
" name = 'instrumentation2',",
" target = '//java/com/app:app2',",
" instrumentation = ':instrumentation_app2',",
")",
"android_device_script_fixture(",
" name = 'device_fixture',",
" cmd = 'foo bar',",
Expand All @@ -89,10 +72,7 @@ public void setup() throws Exception {
"javatests/com/app/ait/BUILD",
"android_instrumentation_test(",
" name = 'ait',",
" instrumentations = [",
" '//javatests/com/app:instrumentation1',",
" '//javatests/com/app:instrumentation2',",
" ],",
" instrumentation = '//javatests/com/app:instrumentation_app',",
" target_device = '//tools/android/emulated_device:nexus_6',",
" fixtures = [",
" '//javatests/com/app:device_fixture',",
Expand Down Expand Up @@ -168,10 +148,8 @@ public void testTestExecutableRunfiles() throws Exception {
assertThat(runfiles)
.containsAllOf(
getDeviceFixtureScript(getConfiguredTarget("//javatests/com/app:device_fixture")),
getInstrumentationApk(getConfiguredTarget("//javatests/com/app:instrumentation1")),
getTargetApk(getConfiguredTarget("//javatests/com/app:instrumentation1")),
getInstrumentationApk(getConfiguredTarget("//javatests/com/app:instrumentation2")),
getTargetApk(getConfiguredTarget("//javatests/com/app:instrumentation2")),
getInstrumentationApk(getConfiguredTarget("//javatests/com/app:instrumentation_app")),
getTargetApk(getConfiguredTarget("//javatests/com/app:instrumentation_app")),
Iterables.getOnlyElement(
getConfiguredTarget("//javatests/com/app/ait:foo.txt")
.getProvider(FileProvider.class)
Expand All @@ -192,13 +170,8 @@ public void testTestExecutableContents() throws Exception {
.getFileContents();

assertThat(testExecutableScript)
.contains(
"instrumentation_apks=\"javatests/com/app/instrumentation1-instrumentation.apk "
+ "javatests/com/app/instrumentation2-instrumentation.apk\"");
assertThat(testExecutableScript)
.contains(
"target_apks=\"javatests/com/app/instrumentation1-target.apk "
+ "javatests/com/app/instrumentation2-target.apk\"");
.contains("instrumentation_apk=\"javatests/com/app/instrumentation_app.apk\"");
assertThat(testExecutableScript).contains("target_apk=\"java/com/app/app.apk\"");
assertThat(testExecutableScript).contains("support_apks=\"java/com/app/support.apk\"");
assertThat(testExecutableScript)
.contains(
Expand All @@ -224,7 +197,7 @@ public void testAtMostOneHostServiceFixture() throws Exception {
")",
"android_instrumentation_test(",
" name = 'ait',",
" instrumentations = ['//javatests/com/app:instrumentation1'],",
" instrumentation = '//javatests/com/app:instrumentation_app',",
" target_device = '//tools/android/emulated_device:nexus_6',",
" fixtures = [",
" ':host_fixture',",
Expand All @@ -233,6 +206,25 @@ public void testAtMostOneHostServiceFixture() throws Exception {
")");
}

@Test
public void testInstrumentationBinaryIsInstrumenting() throws Exception {
checkError(
"javatests/com/app/instr",
"ait",
"The android_binary target at //javatests/com/app/instr:app "
+ "is missing an 'instruments' attribute",
"android_binary(",
" name = 'app',",
" srcs = ['a.java'],",
" manifest = 'AndroidManifest.xml',",
")",
"android_instrumentation_test(",
" name = 'ait',",
" instrumentation = ':app',",
" target_device = '//tools/android/emulated_device:nexus_6',",
")");
}

private static Artifact getDeviceFixtureScript(ConfiguredTarget deviceScriptFixture) {
return getFirstArtifactEndingWith(
deviceScriptFixture.getProvider(FileProvider.class).getFilesToBuild(), ".sh");
Expand Down

0 comments on commit 19c5039

Please sign in to comment.