private AndroidInstrumentationApk( BuildRuleParams buildRuleParams, String manifest, AndroidBinaryRule apkUnderTest) { super( buildRuleParams, manifest, apkUnderTest.getTarget(), apkUnderTest.getKeystorePropertiesPath(), PackageType.INSTRUMENTED, // Do not include the classes that will already be in the classes.dex of the APK under test. ImmutableSet.<BuildRule>builder() .addAll(apkUnderTest.getBuildRulesToExcludeFromDex()) .addAll(Classpaths.getClasspathEntries(apkUnderTest.getDeps()).keySet()) .build(), // Do not split the test apk even if the tested apk is split new DexSplitMode( /* shouldSplitDex */ false, ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR), apkUnderTest.isUseAndroidProguardConfigWithOptimizations(), apkUnderTest.getProguardConfig(), apkUnderTest.isCompressResources(), apkUnderTest.getPrimaryDexSubstrings(), apkUnderTest.getResourceFilter(), apkUnderTest.getCpuFilter()); this.apkUnderTest = apkUnderTest; }
private void createAndroidBinaryRuleAndTestCopyNativeLibraryCommand( ImmutableSet<String> cpuFilters, String sourceDir, String destinationDir, ImmutableList<String> expectedShellCommands) { BuildRuleResolver ruleResolver = new BuildRuleResolver(); AndroidBinaryRule.Builder builder = AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//:fbandroid_with_dash_debug_fbsign")) .setManifest("AndroidManifest.xml") .setKeystore(addKeystoreRule(ruleResolver)) .setTarget("Google Inc:Google APIs:16"); for (String filter : cpuFilters) { builder.addCpuFilter(filter); } ImmutableList.Builder<Step> commands = ImmutableList.builder(); AndroidBinaryRule buildRule = ruleResolver.buildAndAddToIndex(builder); buildRule.copyNativeLibrary(sourceDir, destinationDir, commands); ImmutableList<Step> steps = commands.build(); assertEquals(steps.size(), expectedShellCommands.size()); ExecutionContext context = createMock(ExecutionContext.class); replay(context); for (int i = 0; i < steps.size(); ++i) { Iterable<String> observedArgs = ((BashStep) steps.get(i)).getShellCommand(context); String observedCommand = Joiner.on(' ').join(observedArgs); assertEquals(expectedShellCommands.get(i), observedCommand); } verify(context); }
/** * Tests an android_binary with zero dependent android_library rules that contains an assets * directory. */ @Test public void testCreateAllAssetsDirectoryWithZeroAssetsDirectories() throws IOException { BuildRuleResolver ruleResolver = new BuildRuleResolver(); // Two android_library deps, neither with an assets directory. JavaLibraryRule libraryOne = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryOne", ruleResolver, null, /* resDirectory */ null, /* assetDirectory */ null /* nativeLibsDirectory */); JavaLibraryRule libraryTwo = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryTwo", ruleResolver, null, /* resDirectory */ null, /* assetDirectory */ null /* nativeLibsDirectory */); // One android_binary rule that depends on the two android_library rules. BuildTarget binaryBuildTarget = BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk"); AndroidBinaryRule androidBinary = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(binaryBuildTarget) .addClasspathDep(libraryOne.getBuildTarget()) .addClasspathDep(libraryTwo.getBuildTarget()) .setManifest("java/src/com/facebook/base/AndroidManifest.xml") .setTarget("Google Inc.:Google APIs:16") .setKeystore(addKeystoreRule(ruleResolver)) .setPackageType("debug")); // Build up the parameters needed to invoke createAllAssetsDirectory(). Set<String> assetsDirectories = ImmutableSet.of(); ImmutableList.Builder<Step> commands = ImmutableList.builder(); DirectoryTraverser traverser = new DirectoryTraverser() { @Override public void traverse(DirectoryTraversal traversal) { throw new RuntimeException("Unexpected: no assets directories to traverse!"); } }; // Invoke createAllAssetsDirectory(), the method under test. Optional<String> allAssetsDirectory = androidBinary.createAllAssetsDirectory( assetsDirectories, ImmutableMap.<String, File>of(), commands, traverser); // Verify that no assets/ directory is used. assertFalse( "There should not be an assets/ directory to pass to aapt.", allAssetsDirectory.isPresent()); assertTrue( "There should not be any commands to build up an assets/ directory.", commands.build().isEmpty()); }
@Test public void testGetInputsToCompareToOutput() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); AndroidBinaryRule.Builder androidBinaryRuleBuilder = AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//java/src/com/facebook:app")) .setManifest("java/src/com/facebook/AndroidManifest.xml") .setTarget("Google Inc.:Google APIs:16") .setKeystore(addKeystoreRule(ruleResolver)); BuildContext context = createMock(BuildContext.class); replay(context); MoreAsserts.assertListEquals( "getInputsToCompareToOutput() should include manifest.", ImmutableList.of("java/src/com/facebook/AndroidManifest.xml"), ruleResolver.buildAndAddToIndex(androidBinaryRuleBuilder).getInputsToCompareToOutput()); SourcePath proguardConfig = new FileSourcePath("java/src/com/facebook/proguard.cfg"); androidBinaryRuleBuilder.setProguardConfig(Optional.of(proguardConfig)); MoreAsserts.assertListEquals( "getInputsToCompareToOutput() should include Proguard config, if present.", ImmutableList.of( "java/src/com/facebook/AndroidManifest.xml", "java/src/com/facebook/proguard.cfg"), ruleResolver.buildAndAddToIndex(androidBinaryRuleBuilder).getInputsToCompareToOutput()); verify(context); }
@Test public void testDexingCommand() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); AndroidBinaryRule splitDexRule = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget( BuildTargetFactory.newInstance("//:fbandroid_with_dash_debug_fbsign")) .setManifest("AndroidManifest.xml") .setKeystore(addKeystoreRule(ruleResolver)) .setTarget("Google Inc.:Google APIs:16") .setDexSplitMode( new DexSplitMode( /* shouldSplitDex */ true, ZipSplitter.DexSplitStrategy.MAXIMIZE_PRIMARY_DEX_SIZE, DexStore.JAR, /* useLinearAllocSplitDex */ false))); Set<String> classpath = Sets.newHashSet(); ImmutableSet.Builder<String> secondaryDexDirectories = ImmutableSet.builder(); ImmutableList.Builder<Step> commandsBuilder = ImmutableList.builder(); String primaryDexPath = BIN_DIR + "/.dex/classes.dex"; splitDexRule.addDexingCommands( classpath, secondaryDexDirectories, commandsBuilder, primaryDexPath, /* sourcePathResolver */ new Function<SourcePath, Path>() { @Override public Path apply(SourcePath input) { throw new UnsupportedOperationException("This resolver should not be used."); } }); assertEquals( "Expected 2 new assets paths (one for metadata.txt and the other for the " + "secondary zips)", 2, secondaryDexDirectories.build().size()); List<Step> steps = commandsBuilder.build(); assertCommandsInOrder( steps, ImmutableList.<Class<?>>of(SplitZipStep.class, SmartDexingStep.class)); }
@Test public void testGetProguardOutputFromInputClasspath() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); AndroidBinaryRule rule = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget( BuildTargetFactory.newInstance("//:fbandroid_with_dash_debug_fbsign")) .setManifest("AndroidManifest.xml") .setKeystore(addKeystoreRule(ruleResolver)) .setTarget("Google Inc.:Google APIs:16")); String proguardDir = rule.getProguardOutputFromInputClasspath( BIN_DIR + "/first-party/orca/lib-base/lib__lib-base__classes"); assertEquals( GEN_DIR + "/.proguard/fbandroid_with_dash_debug_fbsign/" + BIN_DIR + "/first-party/orca/lib-base/lib__lib-base__classes-obfuscated.jar", proguardDir); }
@Test public void testGetUnsignedApkPath() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); AndroidBinaryRule ruleInRootDirectory = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//:fb4a")) .setManifest("AndroidManifest.xml") .setKeystore(addKeystoreRule(ruleResolver)) .setTarget("Google Inc.:Google APIs:16")); assertEquals(GEN_DIR + "/fb4a.apk", ruleInRootDirectory.getApkPath()); AndroidBinaryRule ruleInNonRootDirectory = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(BuildTargetFactory.newInstance("//java/com/example:fb4a")) .setManifest("AndroidManifest.xml") .setKeystore(addKeystoreRule(ruleResolver)) .setTarget("Google Inc.:Google APIs:16")); assertEquals(GEN_DIR + "/java/com/example/fb4a.apk", ruleInNonRootDirectory.getApkPath()); }
@Test public void testAndroidBinaryNoDx() { BuildRuleResolver ruleResolver = new BuildRuleResolver(); // Two android_library deps, neither with an assets directory. JavaLibraryRule libraryOne = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryOne", ruleResolver, null, /* resDirectory */ null, /* assetDirectory */ null /* nativeLibsDirectory */); JavaLibraryRule libraryTwo = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryTwo", ruleResolver, null, /* resDirectory */ null, /* assetDirectory */ null /* nativeLibsDirectory */); // One android_binary rule that depends on the two android_library rules. BuildTarget binaryBuildTarget = BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk"); AndroidBinaryRule androidBinary = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(binaryBuildTarget) .addClasspathDep(libraryOne.getBuildTarget()) .addClasspathDep(libraryTwo.getBuildTarget()) .addBuildRuleToExcludeFromDex( BuildTargetFactory.newInstance("//java/src/com/facebook/base:libraryTwo")) .setManifest("java/src/com/facebook/base/AndroidManifest.xml") .setTarget("Google Inc.:Google APIs:16") .setKeystore(addKeystoreRule(ruleResolver)) .setPackageType("debug")); DependencyGraph graph = RuleMap.createGraphFromBuildRules(ruleResolver); AndroidTransitiveDependencies transitiveDependencies = androidBinary.findTransitiveDependencies(graph); AndroidDexTransitiveDependencies dexTransitiveDependencies = androidBinary.findDexTransitiveDependencies(graph); ImmutableList.Builder<Step> commands = ImmutableList.builder(); BuildContext context = createMock(BuildContext.class); replay(context); androidBinary.addProguardCommands( context, dexTransitiveDependencies.classpathEntriesToDex, transitiveDependencies.proguardConfigs, commands, ImmutableSet.<String>of()); verify(context); MakeCleanDirectoryStep expectedClean = new MakeCleanDirectoryStep("buck-out/gen/java/src/com/facebook/base/.proguard/apk"); GenProGuardConfigStep expectedGenProguard = new GenProGuardConfigStep( "buck-out/bin/java/src/com/facebook/base/__manifest_apk__/AndroidManifest.xml", ImmutableSet.<String>of(), "buck-out/gen/java/src/com/facebook/base/.proguard/apk/proguard.txt"); ProGuardObfuscateStep expectedObfuscation = new ProGuardObfuscateStep( "buck-out/gen/java/src/com/facebook/base/.proguard/apk/proguard.txt", ImmutableSet.<String>of(), false, ImmutableMap.of( "buck-out/gen/java/src/com/facebook/base/lib__libraryOne__output/libraryOne.jar", "buck-out/gen/java/src/com/facebook/base/.proguard/apk/buck-out/gen/java/src/com/" + "facebook/base/lib__libraryOne__output/libraryOne-obfuscated.jar"), ImmutableSet.of( "buck-out/gen/java/src/com/facebook/base/lib__libraryTwo__output/libraryTwo.jar"), "buck-out/gen/java/src/com/facebook/base/.proguard/apk"); assertEquals( ImmutableList.of(expectedClean, expectedGenProguard, expectedObfuscation), commands.build()); }
/** * Tests an android_binary with multiple dependent android_library rules, each with its own assets * directory. */ @Test public void testCreateAllAssetsDirectoryWithMultipleAssetsDirectories() throws IOException { BuildRuleResolver ruleResolver = new BuildRuleResolver(); // Two android_library deps, each with an assets directory. JavaLibraryRule libraryOne = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryOne", ruleResolver, null, /* resDirectory */ "java/src/com/facebook/base/assets1", null /* nativeLibsDirectory */); JavaLibraryRule libraryTwo = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryTwo", ruleResolver, null, /* resDirectory */ "java/src/com/facebook/base/assets2", null /* nativeLibsDirectory */); // One android_binary rule that depends on the two android_library rules. BuildTarget binaryBuildTarget = BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk"); AndroidBinaryRule androidBinary = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(binaryBuildTarget) .addClasspathDep(libraryOne.getBuildTarget()) .addClasspathDep(libraryTwo.getBuildTarget()) .setManifest("java/src/com/facebook/base/AndroidManifest.xml") .setTarget("Google Inc.:Google APIs:16") .setKeystore(addKeystoreRule(ruleResolver)) .setPackageType("debug")); AndroidResourceRule resourceOne = (AndroidResourceRule) ruleResolver.get( BuildTargetFactory.newInstance( "//java/src/com/facebook/base:libraryOne_resources")); AndroidResourceRule resourceTwo = (AndroidResourceRule) ruleResolver.get( BuildTargetFactory.newInstance( "//java/src/com/facebook/base:libraryTwo_resources")); // Build up the parameters needed to invoke createAllAssetsDirectory(). Set<String> assetsDirectories = ImmutableSet.of(resourceOne.getAssets(), resourceTwo.getAssets()); ImmutableList.Builder<Step> commands = ImmutableList.builder(); DirectoryTraverser traverser = new DirectoryTraverser() { @Override public void traverse(DirectoryTraversal traversal) throws IOException { String rootPath = Paths.normalizePathSeparator(traversal.getRoot().getPath()); if ("java/src/com/facebook/base/assets1".equals(rootPath)) { traversal.visit( new File("java/src/com/facebook/base/assets1", "guava-10.0.1-fork.dex.1.jar"), "guava-10.0.1-fork.dex.1.jar"); } else if ("java/src/com/facebook/base/assets2".equals(rootPath)) { traversal.visit( new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Medium.otf"), "fonts/Theinhardt-Medium.otf"); traversal.visit( new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Regular.otf"), "fonts/Theinhardt-Regular.otf"); } else { throw new RuntimeException("Unexpected path: " + rootPath); } } }; // Invoke createAllAssetsDirectory(), the method under test. Optional<String> allAssetsDirectory = androidBinary.createAllAssetsDirectory( assetsDirectories, ImmutableMap.<String, File>of(), commands, traverser); // Verify that an assets/ directory will be created and passed to aapt. assertTrue(allAssetsDirectory.isPresent()); assertEquals(BIN_DIR + "/java/src/com/facebook/base/__assets_apk__", allAssetsDirectory.get()); List<? extends Step> expectedCommands = ImmutableList.of( new MakeCleanDirectoryStep(BIN_DIR + "/java/src/com/facebook/base/__assets_apk__"), new MkdirAndSymlinkFileStep( "java/src/com/facebook/base/assets1/guava-10.0.1-fork.dex.1.jar", BIN_DIR + "/java/src/com/facebook/base/__assets_apk__/guava-10.0.1-fork.dex.1.jar"), new MkdirAndSymlinkFileStep( "java/src/com/facebook/base/assets2/fonts/Theinhardt-Medium.otf", BIN_DIR + "/java/src/com/facebook/base/__assets_apk__/fonts/Theinhardt-Medium.otf"), new MkdirAndSymlinkFileStep( "java/src/com/facebook/base/assets2/fonts/Theinhardt-Regular.otf", BIN_DIR + "/java/src/com/facebook/base/__assets_apk__/fonts/Theinhardt-Regular.otf")); MoreAsserts.assertListEquals(expectedCommands, commands.build()); }
/** * Tests an android_binary with one dependent android_library rule that contains an assets * directory. */ @Test public void testCreateAllAssetsDirectoryWithOneAssetsDirectory() throws IOException { BuildRuleResolver ruleResolver = new BuildRuleResolver(); // Two android_library deps, one of which has an assets directory. JavaLibraryRule libraryOne = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryOne", ruleResolver, null, /* resDirectory */ null, /* assetDirectory */ null /* nativeLibsDirectory */); JavaLibraryRule libraryTwo = createAndroidLibraryRule( "//java/src/com/facebook/base:libraryTwo", ruleResolver, null, /* resDirectory */ "java/src/com/facebook/base/assets2", null /* nativeLibsDirectory */); AndroidResourceRule resourceOne = (AndroidResourceRule) ruleResolver.get( BuildTargetFactory.newInstance( "//java/src/com/facebook/base:libraryTwo_resources")); // One android_binary rule that depends on the two android_library rules. BuildTarget binaryBuildTarget = BuildTargetFactory.newInstance("//java/src/com/facebook/base:apk"); AndroidBinaryRule androidBinary = ruleResolver.buildAndAddToIndex( AndroidBinaryRule.newAndroidBinaryRuleBuilder(new FakeAbstractBuildRuleBuilderParams()) .setBuildTarget(binaryBuildTarget) .addClasspathDep(libraryOne.getBuildTarget()) .addClasspathDep(libraryTwo.getBuildTarget()) .setManifest("java/src/com/facebook/base/AndroidManifest.xml") .setTarget("Google Inc.:Google APIs:16") .setKeystore(addKeystoreRule(ruleResolver)) .setPackageType("debug")); // Build up the parameters needed to invoke createAllAssetsDirectory(). Set<String> assetsDirectories = ImmutableSet.of(resourceOne.getAssets()); ImmutableList.Builder<Step> commands = ImmutableList.builder(); DirectoryTraverser traverser = new DirectoryTraverser() { @Override public void traverse(DirectoryTraversal traversal) throws IOException { String rootPath = Paths.normalizePathSeparator(traversal.getRoot().getPath()); if ("java/src/com/facebook/base/assets2".equals(rootPath)) { traversal.visit( new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Medium.otf"), "fonts/Theinhardt-Medium.otf"); traversal.visit( new File("java/src/com/facebook/base/assets2", "fonts/Theinhardt-Regular.otf"), "fonts/Theinhardt-Regular.otf"); } else { throw new RuntimeException("Unexpected path: " + rootPath); } } }; // Invoke createAllAssetsDirectory(), the method under test. Optional<String> allAssetsDirectory = androidBinary.createAllAssetsDirectory( assetsDirectories, ImmutableMap.<String, File>of(), commands, traverser); // Verify that the existing assets/ directory will be passed to aapt. assertTrue(allAssetsDirectory.isPresent()); assertEquals( "Even though there is only one assets directory, the one in " + BIN_DIR + " should be used.", androidBinary.getPathToAllAssetsDirectory(), allAssetsDirectory.get()); }