| // 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.rules.android; |
| |
| import static com.google.common.collect.ImmutableList.toImmutableList; |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith; |
| |
| import com.google.devtools.build.lib.actions.Action; |
| import com.google.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.analysis.ConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.FileProvider; |
| import com.google.devtools.build.lib.analysis.FilesToRunProvider; |
| import com.google.devtools.build.lib.analysis.RunfilesProvider; |
| import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction; |
| import com.google.devtools.build.lib.rules.android.AndroidInstrumentationTestTest.WithPlatforms; |
| import com.google.devtools.build.lib.rules.android.AndroidInstrumentationTestTest.WithoutPlatforms; |
| import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData; |
| import java.util.List; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| import org.junit.runners.Suite; |
| import org.junit.runners.Suite.SuiteClasses; |
| |
| /** Tests for {@code android_instrumentation_test}. */ |
| @RunWith(Suite.class) |
| @SuiteClasses({WithoutPlatforms.class, WithPlatforms.class}) |
| public abstract class AndroidInstrumentationTestTest extends AndroidBuildViewTestCase { |
| /** Use legacy toolchain resolution. */ |
| @RunWith(JUnit4.class) |
| public static class WithoutPlatforms extends AndroidInstrumentationTestTest {} |
| |
| /** Use platform-based toolchain resolution. */ |
| @RunWith(JUnit4.class) |
| public static class WithPlatforms extends AndroidInstrumentationTestTest { |
| @Override |
| protected boolean platformBasedToolchains() { |
| return true; |
| } |
| } |
| |
| @Before |
| public void setupCcToolchain() throws Exception { |
| getAnalysisMock().ccSupport().setupCcToolchainConfigForCpu(mockToolsConfig, "armeabi-v7a"); |
| } |
| |
| @Before |
| public void setup() throws Exception { |
| scratch.file( |
| "java/com/app/BUILD", |
| "android_binary(", |
| " name = 'app',", |
| " manifest = 'AndroidManifest.xml',", |
| ")", |
| "android_binary(", |
| " name = 'support',", |
| " manifest = 'AndroidManifest.xml',", |
| ")"); |
| scratch.file( |
| "javatests/com/app/BUILD", |
| "android_binary(", |
| " name = 'instrumentation_app',", |
| " instruments = '//java/com/app',", |
| " manifest = 'AndroidManifest.xml',", |
| ")", |
| "android_device_script_fixture(", |
| " name = 'device_fixture',", |
| " cmd = 'foo bar',", |
| ")", |
| "android_host_service_fixture(", |
| " name = 'host_fixture',", |
| " executable = '//java/com/server',", |
| " service_names = ['foo', 'bar'],", |
| ")"); |
| scratch.file( |
| "java/com/server/BUILD", |
| "java_binary(", |
| " name = 'server',", |
| " main_class = 'does.not.exist',", |
| " srcs = [],", |
| ")"); |
| scratch.file( |
| "javatests/com/app/ait/BUILD", |
| "android_instrumentation_test(", |
| " name = 'ait',", |
| " test_app = '//javatests/com/app:instrumentation_app',", |
| " target_device = '//tools/android/emulated_device:nexus_6',", |
| " fixtures = [", |
| " '//javatests/com/app:device_fixture',", |
| " '//javatests/com/app:host_fixture',", |
| " ],", |
| " support_apks = [", |
| " '//java/com/app:support',", |
| " ],", |
| " data = [", |
| " 'foo.txt',", |
| " ],", |
| ")"); |
| setupTargetDevice(); |
| useConfiguration( |
| "--experimental_use_dex_splitter_for_incremental_dexing=false", |
| "--experimental_incremental_dexing_after_proguard_by_default=false", |
| "--experimental_incremental_dexing_after_proguard=1"); |
| setBuildLanguageOptions("--experimental_google_legacy_api"); |
| } |
| |
| // TODO(ajmichael): Share this with AndroidDeviceTest.java |
| private void setupTargetDevice() throws Exception { |
| scratch.file( |
| "tools/android/emulated_device/BUILD", |
| "filegroup(", |
| " name = 'emulator_images_android_21_x86',", |
| " srcs = [", |
| " 'android_21/x86/kernel-qemu',", |
| " 'android_21/x86/ramdisk.img',", |
| " 'android_21/x86/source.properties',", |
| " 'android_21/x86/system.img.tar.gz',", |
| " 'android_21/x86/userdata.img.tar.gz'", |
| " ],", |
| ")", |
| "android_device(", |
| " name = 'nexus_6',", |
| " ram = 2047,", |
| " horizontal_resolution = 720, ", |
| " vertical_resolution = 1280, ", |
| " cache = 32, ", |
| " system_image = ':emulator_images_android_21_x86',", |
| " screen_density = 280, ", |
| " vm_heap = 256", |
| ")"); |
| } |
| |
| @Test |
| public void testTestExecutableRunfiles() throws Exception { |
| ConfiguredTargetAndData androidInstrumentationTest = |
| getConfiguredTargetAndData("//javatests/com/app/ait"); |
| List<Artifact> runfiles = |
| androidInstrumentationTest |
| .getConfiguredTarget() |
| .getProvider(RunfilesProvider.class) |
| .getDefaultRunfiles() |
| .getAllArtifacts() |
| .toList(); |
| assertThat(runfiles) |
| .containsAtLeastElementsIn( |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| "//tools/android/emulated_device:nexus_6") |
| .getProvider(RunfilesProvider.class) |
| .getDefaultRunfiles() |
| .getAllArtifacts() |
| .toList()); |
| // The dependency chain is ait -> host_fixture -> server |
| ConfiguredTarget hostFixture = |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), "//javatests/com/app:host_fixture"); |
| assertThat(runfiles) |
| .containsAtLeastElementsIn( |
| getDirectPrerequisite(hostFixture, "//java/com/server") |
| .getProvider(RunfilesProvider.class) |
| .getDefaultRunfiles() |
| .getAllArtifacts() |
| .toList()); |
| |
| assertThat(runfiles) |
| .containsAtLeastElementsIn( |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| androidInstrumentationTest |
| .getTargetForTesting() |
| .getAssociatedRule() |
| .getAttrDefaultValue("$test_entry_point") |
| .toString()) |
| .getProvider(RunfilesProvider.class) |
| .getDefaultRunfiles() |
| .getAllArtifacts() |
| .toList()); |
| assertThat(runfiles.stream().map(Artifact::toString).collect(toImmutableList())) |
| .containsAtLeast( |
| getDeviceFixtureScript( |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| "//javatests/com/app:device_fixture")) |
| .toString(), |
| getInstrumentationApk( |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| "//javatests/com/app:instrumentation_app")) |
| .toString(), |
| getTargetApk( |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| "//javatests/com/app:instrumentation_app")) |
| .toString(), |
| getDirectPrerequisite( |
| androidInstrumentationTest.getConfiguredTarget(), |
| "//javatests/com/app/ait:foo.txt") |
| .getProvider(FileProvider.class) |
| .getFilesToBuild() |
| .getSingleton() |
| .toString()); |
| } |
| |
| @Test |
| public void testTestExecutableContents() throws Exception { |
| ConfiguredTarget androidInstrumentationTest = getConfiguredTarget("//javatests/com/app/ait"); |
| assertThat(androidInstrumentationTest).isNotNull(); |
| |
| String testExecutableScript = getTestStubContents(androidInstrumentationTest); |
| |
| assertThat(testExecutableScript) |
| .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( |
| "declare -A device_script_fixtures=( " |
| + "[javatests/com/app/cmd_device_fixtures/device_fixture/cmd.sh]=false,true )"); |
| assertThat(testExecutableScript).contains("host_service_fixture=\"java/com/server/server\""); |
| assertThat(testExecutableScript).contains("host_service_fixture_services=\"foo,bar\""); |
| assertThat(testExecutableScript) |
| .contains("device_script=\"${WORKSPACE_DIR}/tools/android/emulated_device/nexus_6\""); |
| assertThat(testExecutableScript).contains("data_deps=\"javatests/com/app/ait/foo.txt\""); |
| } |
| |
| @Test |
| public void testAtMostOneHostServiceFixture() throws Exception { |
| checkError( |
| "javatests/com/app/ait2", |
| "ait", |
| "android_instrumentation_test accepts at most one android_host_service_fixture", |
| "android_host_service_fixture(", |
| " name = 'host_fixture',", |
| " executable = '//java/com/server',", |
| " service_names = ['foo', 'bar'],", |
| ")", |
| "android_instrumentation_test(", |
| " name = 'ait',", |
| " test_app = '//javatests/com/app:instrumentation_app',", |
| " target_device = '//tools/android/emulated_device:nexus_6',", |
| " fixtures = [", |
| " ':host_fixture',", |
| " '//javatests/com/app:host_fixture',", |
| " ],", |
| ")"); |
| } |
| |
| @Test |
| public void testInstrumentationBinaryIsInstrumenting() throws Exception { |
| checkError( |
| "javatests/com/app/instr", |
| "ait", |
| "The android_binary target //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',", |
| " test_app = ':app',", |
| " target_device = '//tools/android/emulated_device:nexus_6',", |
| ")"); |
| } |
| |
| @Test |
| public void testAndroidInstrumentationTestWithStarlarkDevice() throws Exception { |
| scratch.file( |
| "javatests/com/app/starlarkdevice/local_adb_device.bzl", |
| "def _impl(ctx):", |
| " ctx.actions.write(output=ctx.outputs.executable, content='', is_executable=True)", |
| " return [android_common.create_device_broker_info('LOCAL_ADB_SERVER')]", |
| "local_adb_device = rule(implementation=_impl, executable=True)"); |
| scratch.file( |
| "javatests/com/app/starlarkdevice/BUILD", |
| "load(':local_adb_device.bzl', 'local_adb_device')", |
| "local_adb_device(name = 'local_adb_device')", |
| "android_instrumentation_test(", |
| " name = 'ait',", |
| " test_app = '//javatests/com/app:instrumentation_app',", |
| " target_device = ':local_adb_device',", |
| ")"); |
| String testExecutableScript = |
| getTestStubContents(getConfiguredTarget("//javatests/com/app/starlarkdevice:ait")); |
| assertThat(testExecutableScript).contains("device_broker_type=\"LOCAL_ADB_SERVER\""); |
| } |
| |
| private static Artifact getDeviceFixtureScript(ConfiguredTarget deviceScriptFixture) { |
| return getFirstArtifactEndingWith( |
| deviceScriptFixture.getProvider(FileProvider.class).getFilesToBuild(), ".sh"); |
| } |
| |
| private static Artifact getInstrumentationApk(ConfiguredTarget instrumentation) { |
| return instrumentation.get(AndroidInstrumentationInfo.PROVIDER).getTarget().getApk(); |
| } |
| |
| private static Artifact getTargetApk(ConfiguredTarget instrumentation) { |
| return instrumentation.get(ApkInfo.PROVIDER).getApk(); |
| } |
| |
| private String getTestStubContents(ConfiguredTarget androidInstrumentationTest) throws Exception { |
| Action templateAction = |
| getGeneratingAction( |
| androidInstrumentationTest.getProvider(FilesToRunProvider.class).getExecutable()); |
| return ((TemplateExpansionAction) templateAction).getFileContents(); |
| } |
| } |