// 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.bazel.rules.android;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileConfiguredTarget;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider;
import com.google.devtools.build.lib.rules.android.NativeLibsZipsProvider;
import com.google.devtools.build.lib.rules.android.ResourceContainer;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider.OutputJar;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link com.google.devtools.build.lib.rules.android.AarImport}. */
@RunWith(JUnit4.class)
public class AarImportTest extends BuildViewTestCase {
@Before
public void setup() throws Exception {
scratch.file("a/BUILD",
"aar_import(",
" name = 'foo',",
" aar = 'foo.aar',",
")",
"aar_import(",
" name = 'bar',",
" aar = 'bar.aar',",
" exports = [':foo', '//java:baz'],",
")");
scratch.file("java/BUILD",
"android_binary(",
" name = 'app',",
" manifest = 'AndroidManifest.xml',",
" deps = ['//a:bar'],",
")",
"android_library(",
" name = 'lib',",
" deps = ['//a:bar'],",
")",
"java_import(",
" name = 'baz',",
" jars = ['baz.jar'],",
" constraints = ['android'],",
")");
}
@Test
public void testResourcesProvided() throws Exception {
ConfiguredTarget aarImportTarget = getConfiguredTarget("//a:foo");
NestedSet<ResourceContainer> directResources = aarImportTarget
.getProvider(AndroidResourcesProvider.class)
.getDirectAndroidResources();
assertThat(directResources).hasSize(1);
ResourceContainer resourceContainer = directResources.iterator().next();
assertThat(resourceContainer.getManifest()).isNotNull();
Iterable<Artifact> resourceArtifacts = resourceContainer.getArtifacts();
assertThat(resourceArtifacts).hasSize(1);
Artifact resourceTreeArtifact = resourceArtifacts.iterator().next();
assertThat(resourceTreeArtifact.isTreeArtifact()).isTrue();
assertThat(resourceTreeArtifact.getExecPathString()).endsWith("_aar/unzipped/resources/foo");
}
@Test
public void testNativeLibsProvided() throws Exception {
ConfiguredTarget androidLibraryTarget = getConfiguredTarget("//java:lib");
NestedSet<Artifact> nativeLibs =
androidLibraryTarget.getProvider(NativeLibsZipsProvider.class).getAarNativeLibs();
assertThat(nativeLibs).containsExactly(
actionsTestUtil().getFirstArtifactEndingWith(nativeLibs, "foo/native_libs.zip"),
actionsTestUtil().getFirstArtifactEndingWith(nativeLibs, "bar/native_libs.zip"));
}
@Test
public void testNativeLibsZipMakesItIntoApk() throws Exception {
scratch.file("java/com/google/android/hello/BUILD",
"aar_import(",
" name = 'my_aar',",
" aar = 'my_aar.aar',",
")",
"android_binary(",
" name = 'my_app',",
" srcs = ['HelloApp.java'],",
" deps = [':my_aar'],",
" manifest = 'AndroidManifest.xml',",
")");
ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:my_app");
SpawnAction apkBuilderAction = (SpawnAction) actionsTestUtil()
.getActionForArtifactEndingWith(getFilesToBuild(binary), "my_app_unsigned.apk");
assertThat(
Iterables.find(
apkBuilderAction.getArguments(),
Predicates.containsPattern("_aar/my_aar/native_libs.zip$")))
.isNotEmpty();
}
@Test
public void testClassesJarProvided() throws Exception {
ConfiguredTarget aarImportTarget = getConfiguredTarget("//a:foo");
Iterable<OutputJar> outputJars =
aarImportTarget.getProvider(JavaRuleOutputJarsProvider.class).getOutputJars();
assertThat(outputJars).hasSize(1);
Artifact classesJar = outputJars.iterator().next().getClassJar();
assertThat(classesJar.getFilename()).isEqualTo("classes_and_libs_merged.jar");
SpawnAction jarMergingAction = ((SpawnAction) getGeneratingAction(classesJar));
assertThat(jarMergingAction.getArguments()).contains("--dont_change_compression");
}
@Test
public void testNoCustomJavaPackage() throws Exception {
ResourceContainer resourceContainer = getConfiguredTarget("//a:foo")
.getProvider(AndroidResourcesProvider.class)
.getDirectAndroidResources()
.iterator()
.next();
// aar_import should not set a custom java package. Instead aapt will read the
// java package from the manifest.
assertThat(resourceContainer.getJavaPackage()).isNull();
}
@Test
public void testExportsPropagatesMergedAarJars() throws Exception {
FileConfiguredTarget appTarget = getFileConfiguredTarget("//java:app.apk");
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(appTarget.getArtifact());
ConfiguredTarget bar = getConfiguredTarget("//a:bar");
Artifact barClassesJar =
ActionsTestUtil.getFirstArtifactEndingWith(artifacts, "bar/classes_and_libs_merged.jar");
// Verify that bar/classes_and_libs_merged.jar was in the artifact closure.
assertThat(barClassesJar).isNotNull();
assertThat(barClassesJar.getArtifactOwner().getLabel()).isEqualTo(bar.getLabel());
ConfiguredTarget foo = getConfiguredTarget("//a:foo");
Artifact fooClassesJar =
ActionsTestUtil.getFirstArtifactEndingWith(artifacts, "foo/classes_and_libs_merged.jar");
// Verify that foo/classes_and_libs_merged.jar was in the artifact closure.
assertThat(fooClassesJar).isNotNull();
assertThat(fooClassesJar.getArtifactOwner().getLabel()).isEqualTo(foo.getLabel());
ConfiguredTarget baz = getConfiguredTarget("//java:baz.jar");
Artifact bazJar =
ActionsTestUtil.getFirstArtifactEndingWith(artifacts, "baz.jar");
// Verify that baz.jar was in the artifact closure
assertThat(bazJar).isNotNull();
assertThat(bazJar.getArtifactOwner().getLabel()).isEqualTo(baz.getLabel());
}
@Test
public void testExportsPropagatesResources() throws Exception {
FileConfiguredTarget appTarget = getFileConfiguredTarget("//java:app.apk");
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(appTarget.getArtifact());
ConfiguredTarget bar = getConfiguredTarget("//a:bar");
Artifact barResources =
ActionsTestUtil.getFirstArtifactEndingWith(artifacts, "_aar/unzipped/resources/bar");
assertThat(barResources).isNotNull();
assertThat(barResources.getArtifactOwner().getLabel()).isEqualTo(bar.getLabel());
ConfiguredTarget foo = getConfiguredTarget("//a:foo");
Artifact fooResources =
ActionsTestUtil.getFirstArtifactEndingWith(artifacts, "_aar/unzipped/resources/foo");
assertThat(fooResources).isNotNull();
assertThat(fooResources.getArtifactOwner().getLabel()).isEqualTo(foo.getLabel());
}
@Test
public void testJavaCompilationArgsProvider() throws Exception {
ConfiguredTarget aarImportTarget = getConfiguredTarget("//a:bar");
JavaCompilationArgsProvider provider = aarImportTarget
.getProvider(JavaCompilationArgsProvider.class);
assertThat(provider).isNotNull();
assertThat(artifactsToStrings(provider.getJavaCompilationArgs().getRuntimeJars()))
.containsExactly(
"bin a/_aar/bar/classes_and_libs_merged.jar",
"bin a/_aar/foo/classes_and_libs_merged.jar",
"src java/baz.jar");
}
@Test
public void testFailsWithoutAndroidSdk() throws Exception {
scratch.file("sdk/BUILD",
"alias(",
" name = 'sdk',",
" actual = 'doesnotexist',",
")");
useConfiguration("--android_sdk=//sdk");
checkError("aar", "aar",
"No Android SDK found. Use the --android_sdk command line option to specify one.",
"aar_import(",
" name = 'aar',",
" aar = 'a.aar',",
")");
}
}