blob: 87d73998758e5fdefbafbbdabdb7b553b67eb197 [file] [log] [blame]
// 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.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.getFirstArtifactEndingWith;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode;
import java.util.Set;
import org.junit.Before;
/** Base class for testing the multidex code of android_binary and android_test. */
public class AndroidMultidexBaseTest extends BuildViewTestCase {
@Before
public final void createFiles() throws Exception {
scratch.file(
"java/android/BUILD",
"android_binary(name = 'app',",
" srcs = ['A.java'],",
" manifest = 'AndroidManifest.xml',",
" resource_files = glob(['res/**']),",
" )");
scratch.file(
"java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
scratch.file("java/android/A.java", "package android; public class A {};");
}
/**
* Internal helper method: given an android_binary rule label, check that it builds in multidex
* mode. Three multidex variations are possible: "legacy", "manual_main_dex" and "native".
*
* @param ruleLabel the android_binary rule label to test against
* @param multidexMode the multidex mode used in the rule
*/
protected void internalTestMultidexBuildStructure(String ruleLabel, MultidexMode multidexMode)
throws Exception {
ConfiguredTarget binary = getConfiguredTarget(ruleLabel);
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(binary));
Artifact finalDexOutput = getFirstArtifactEndingWith(artifacts, "/classes.dex.zip");
assertThat(finalDexOutput).isNotNull();
// Only created in legacy mode:
Artifact strippedJar = getFirstArtifactEndingWith(artifacts, "main_dex_intermediate.jar");
Artifact mainDexList = getFirstArtifactEndingWith(artifacts, "main_dex_list.txt");
String ruleName = Label.parseAbsolute(ruleLabel, ImmutableMap.of()).getName();
Artifact mainDexProguardSpec =
getFirstArtifactEndingWith(artifacts, "main_dex_" + ruleName + "_proguard.cfg");
if (multidexMode == MultidexMode.LEGACY) {
// First action: check that the stripped jar is generated through Proguard.
assertThat(mainDexProguardSpec).isNotNull();
AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(getRuleContext(binary));
assertThat(strippedJar).isNotNull();
SpawnAction stripAction = getGeneratingSpawnAction(strippedJar);
assertThat(stripAction.getCommandFilename())
.isEqualTo(sdk.getProguard().getExecutable().getExecPathString());
assertThat(stripAction.getInputs().toList()).contains(mainDexProguardSpec);
// Second action: The dexer consumes the stripped jar to create the main dex class list.
assertThat(mainDexList).isNotNull();
SpawnAction mainDexAction = getGeneratingSpawnAction(mainDexList);
assertThat(mainDexAction.getArguments())
.containsAtLeast(mainDexList.getExecPathString(), strippedJar.getExecPathString())
.inOrder();
} else if (multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
// Manual main dex mode: strippedJar shouldn't exist and mainDexList should be provided.
assertThat(strippedJar).isNull();
assertThat(mainDexList).isNotNull();
} else {
// Native mode: these shouldn't exist.
assertThat(strippedJar).isNull();
assertThat(mainDexList).isNull();
}
Artifact dexMergerInput = getFirstArtifactEndingWith(artifacts, "classes.jar");
SpawnAction dexMergerAction = getGeneratingSpawnAction(finalDexOutput);
ImmutableList.Builder<String> argsBuilder =
ImmutableList.<String>builder()
.add(
"--input",
dexMergerInput.getExecPathString(),
"--output",
finalDexOutput.getExecPathString());
if (multidexMode != MultidexMode.OFF) {
argsBuilder.add("--multidex=minimal");
}
if (multidexMode == MultidexMode.LEGACY || multidexMode == MultidexMode.MANUAL_MAIN_DEX) {
argsBuilder.add("--main-dex-list", mainDexList.getExecPathString());
}
assertThat(dexMergerAction.getRemainingArguments())
.containsExactlyElementsIn(argsBuilder.build())
.inOrder();
}
/**
* Internal helper method: given an android_binary rule label, check that the dex merger runs is
* invoked with {@code --multidex=off}.
*/
protected void internalTestNonMultidexBuildStructure(String ruleLabel) throws Exception {
ConfiguredTarget binary = getConfiguredTarget(ruleLabel);
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(getFilesToBuild(binary));
Artifact dexInput = getFirstArtifactEndingWith(artifacts, "classes.jar");
Artifact dexOutput = getFirstArtifactEndingWith(artifacts, "classes.dex.zip");
SpawnAction dexAction = getGeneratingSpawnAction(dexOutput);
assertThat(dexAction.getRemainingArguments())
.containsAtLeast(
"--input",
dexInput.getExecPathString(),
"--output",
dexOutput.getExecPathString(),
"--multidex=off")
.inOrder();
}
}