blob: c1de5ba3b10daa3dd1f819235dd3eea7f4657243 [file] [log] [blame]
/*
* Copyright 2012-present Facebook, Inc.
*
* 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.facebook.buck.android;
import static org.junit.Assert.assertEquals;
import com.facebook.buck.java.DefaultJavaLibraryRule;
import com.facebook.buck.java.Keystore;
import com.facebook.buck.java.PrebuiltJarRule;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.model.BuildTargetPattern;
import com.facebook.buck.rules.BuildRule;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.DependencyGraph;
import com.facebook.buck.rules.FakeAbstractBuildRuleBuilderParams;
import com.facebook.buck.testutil.RuleMap;
import com.facebook.buck.util.BuckConstant;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
public class AndroidTransitiveDependencyGraphTest {
/**
* This is a regression test to ensure that an additional 1 second startup cost is not
* re-introduced to fb4a.
*/
@Test
public void testFindTransitiveDependencies() {
BuildRuleResolver ruleResolver = new BuildRuleResolver();
// Create an AndroidBinaryRule that transitively depends on two prebuilt JARs. One of the two
// prebuilt JARs will be listed in the AndroidBinaryRule's no_dx list.
PrebuiltJarRule guavaRule = ruleResolver.buildAndAddToIndex(
PrebuiltJarRule.newPrebuiltJarRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//third_party/guava:guava"))
.setBinaryJar("third_party/guava/guava-10.0.1.jar")
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
PrebuiltJarRule jsr305Rule = ruleResolver.buildAndAddToIndex(
PrebuiltJarRule.newPrebuiltJarRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//third_party/jsr-305:jsr-305"))
.setBinaryJar("third_party/jsr-305/jsr305.jar")
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
BuildRule ndkLibrary = ruleResolver.buildAndAddToIndex(
NdkLibrary.newNdkLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//java/com/facebook/native_library:library"))
.addSrc("Android.mk")
.setIsAsset(false)
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
BuildRule prebuiltNativeLibraryBuild = ruleResolver.buildAndAddToIndex(
PrebuiltNativeLibrary.newPrebuiltNativeLibrary(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//java/com/facebook/prebuilt_native_library:library"))
.setNativeLibsDirectory("/java/com/facebook/prebuilt_native_library/libs")
.setIsAsset(true)
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
DefaultJavaLibraryRule libraryRule = ruleResolver.buildAndAddToIndex(
DefaultJavaLibraryRule.newJavaLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//java/src/com/facebook:example"))
.addDep(guavaRule.getBuildTarget())
.addDep(jsr305Rule.getBuildTarget())
.addDep(prebuiltNativeLibraryBuild.getBuildTarget())
.addDep(ndkLibrary.getBuildTarget()));
AndroidResourceRule manifestRule = ruleResolver.buildAndAddToIndex(
AndroidResourceRule.newAndroidResourceRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//java/src/com/facebook:res"))
.setManifestFile("java/src/com/facebook/module/AndroidManifest.xml")
.setAssetsDirectory("assets/"));
BuildTarget keystoreTarget = BuildTargetFactory.newInstance("//keystore:debug");
ruleResolver.buildAndAddToIndex(
Keystore.newKeystoreBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(keystoreTarget)
.setStore("keystore/debug.keystore")
.setProperties("keystore/debug.keystore.properties")
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
AndroidBinaryRule binaryRule = ruleResolver.buildAndAddToIndex(
AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(BuildTargetFactory.newInstance("//java/src/com/facebook:app"))
.addClasspathDep(libraryRule.getBuildTarget())
.addClasspathDep(manifestRule.getBuildTarget())
.addBuildRuleToExcludeFromDex(BuildTargetFactory.newInstance("//third_party/guava:guava"))
.setManifest("java/src/com/facebook/AndroidManifest.xml")
.setTarget("Google Inc.:Google APIs:16")
.setKeystore(keystoreTarget));
// Verify that the correct transitive dependencies are found.
DependencyGraph graph = RuleMap.createGraphFromBuildRules(ruleResolver);
AndroidTransitiveDependencies transitiveDeps = binaryRule.findTransitiveDependencies(graph);
AndroidDexTransitiveDependencies dexTransitiveDeps =
binaryRule.findDexTransitiveDependencies(graph);
assertEquals(
"Because guava was passed to no_dx, it should not be in the classpathEntriesToDex list",
ImmutableSet.of("third_party/jsr-305/jsr305.jar"),
dexTransitiveDeps.classpathEntriesToDex);
assertEquals(
"Because guava was passed to no_dx, it should not be treated as a third-party JAR whose " +
"resources need to be extracted and repacked in the APK. If this is done, then code in " +
"the guava-10.0.1.dex.1.jar in the APK's assets/ tmp may try to load the resource " +
"from the APK as a ZipFileEntry rather than as a resource within guava-10.0.1.dex.1.jar. " +
"Loading a resource in this way could take substantially longer. Specifically, this was " +
"observed to take over one second longer to load the resource in fb4a. Because the " +
"resource was loaded on startup, this introduced a substantial regression in the startup " +
"time for the fb4a app.",
ImmutableSet.of("third_party/jsr-305/jsr305.jar"),
dexTransitiveDeps.pathsToThirdPartyJars);
assertEquals(
"Because assets directory was passed an AndroidResourceRule it should be added to the " +
"transitive dependencies",
ImmutableSet.of("assets/"),
transitiveDeps.assetsDirectories);
assertEquals(
"Because manifest file was passed an AndroidResourceRule it should be added to the " +
"transitive dependencies",
ImmutableSet.of("java/src/com/facebook/module/AndroidManifest.xml"),
transitiveDeps.manifestFiles);
assertEquals(
"Because a native library was declared as a dependency, it should be added to the " +
"transitive dependencies.",
ImmutableSet.of(((NativeLibraryBuildable)ndkLibrary.getBuildable()).getLibraryPath()),
transitiveDeps.nativeLibsDirectories);
assertEquals(
"Because a prebuilt native library was declared as a dependency (and asset), it should " +
"be added to the transitive dependecies.",
ImmutableSet.of(((NativeLibraryBuildable)prebuiltNativeLibraryBuild.getBuildable())
.getLibraryPath()),
transitiveDeps.nativeLibAssetsDirectories);
}
/**
* If the keystore rule depends on an android_library, and an android_binary uses that keystore,
* the keystore's android_library should not contribute to the classpath of the android_binary.
*/
@Test
public void testGraphForAndroidBinaryExcludesKeystoreDeps() {
BuildRuleResolver ruleResolver = new BuildRuleResolver();
BuildTarget androidLibraryKeystoreTarget = new BuildTarget("//java/com/keystore/base", "base");
ruleResolver.buildAndAddToIndex(
AndroidLibraryRule.newAndroidLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(androidLibraryKeystoreTarget)
.addSrc("java/com/facebook/keystore/Base.java")
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
BuildTarget keystoreTarget = new BuildTarget("//keystore", "debug");
ruleResolver.buildAndAddToIndex(
Keystore.newKeystoreBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(keystoreTarget)
.setStore("keystore/debug.keystore")
.setProperties("keystore/debug.keystore.properties")
.addDep(androidLibraryKeystoreTarget)
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
BuildTarget androidLibraryTarget = new BuildTarget("//java/com/facebook/base", "base");
ruleResolver.buildAndAddToIndex(
AndroidLibraryRule.newAndroidLibraryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(androidLibraryTarget)
.addSrc("java/com/facebook/base/Base.java")
.addVisibilityPattern(BuildTargetPattern.MATCH_ALL));
AndroidBinaryRule androidBinaryRule = ruleResolver.buildAndAddToIndex(
AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams())
.setBuildTarget(new BuildTarget("//apps/sample", "app"))
.setManifest("apps/sample/AndroidManifest.xml")
.setTarget("Google Inc.:Google APIs:16")
.setKeystore(keystoreTarget)
.addClasspathDep(androidLibraryTarget));
DependencyGraph dependencyGraph = RuleMap.createGraphFromBuildRules(ruleResolver);
AndroidDexTransitiveDependencies androidTransitiveDeps = androidBinaryRule
.findDexTransitiveDependencies(dependencyGraph);
assertEquals(
"Classpath entries should include facebook/base but not keystore/base.",
ImmutableSet.of(BuckConstant.GEN_DIR + "/java/com/facebook/base/lib__base__output/base.jar"),
androidTransitiveDeps.classpathEntriesToDex);
}
}