/* * Copyright 2017-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.assertThat; import static org.junit.Assert.fail; import com.facebook.buck.jvm.java.testutil.AbiCompilationModeTest; import com.facebook.buck.testutil.integration.ProjectWorkspace; import com.facebook.buck.testutil.integration.TemporaryPaths; import com.facebook.buck.testutil.integration.TestDataHelper; import com.facebook.buck.util.ObjectMappers; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; /** Tests for AndroidLibraryDescription with query_deps */ public class AndroidLibraryAsAnnotationProcessorHostIntegrationTest extends AbiCompilationModeTest { @Rule public TemporaryPaths tmpFolder = new TemporaryPaths(); private ProjectWorkspace workspace; @Before public void setUp() throws IOException { workspace = TestDataHelper.createProjectWorkspaceForScenario( this, "android_library_as_ap_host", tmpFolder); workspace.setUp(); workspace.enableDirCache(); workspace.addBuckConfigLocalOption("build", "depfiles", "cache"); setWorkspaceCompilationMode(workspace); } @Test public void testAddingResourceFileInvalidatesManifestBasedCacheHit() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res1"); workspace.runBuckCommand("clean").assertSuccess(); // Now, add a new config and assert we get a cache miss and the new file is read workspace.replaceFileContents("BUCK", "#add_res", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res2"); } @Test public void testAddingDepInvalidatesManifestBasedCacheHit() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res1"); workspace.runBuckCommand("clean").assertSuccess(); // Now, add a new config via a dep and assert we get a cache miss and the new file is read workspace.replaceFileContents("BUCK", "#add_dep", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib2"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res2"); } @Test public void testAddingResourceFileRebuildsDependents() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res1"); //Now, edit a config and assert we rebuild workspace.replaceFileContents("res/META-INF/res1.json", "res1", "replaced"); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "replaced"); // Now, add a new config and assert we re-run the processor workspace.replaceFileContents("BUCK", "#add_res", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res2"); //Now, add an unrelated file and assert dep files are working workspace.replaceFileContents("BUCK", "#add_file", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetHadMatchingDepfileRuleKey("//:top_level"); } @Test public void testAddingDepRebuildsDependents() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res1"); //Now, edit a used config and assert we rebuild workspace.replaceFileContents("res/META-INF/res1.json", "res1", "replaced"); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "replaced"); // Now, add a new config via a dep and assert we re-run the processor workspace.replaceFileContents("BUCK", "#add_dep", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib2"); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); expectGenruleOutputContains("//:extract_resulting_config", "res2"); } @Test public void testAddingNonResourceFileDoesNotRebuildDependents() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); //Now, add an unrelated file and assert dep files are working workspace.replaceFileContents("BUCK", "#add_file", ""); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetHadMatchingDepfileRuleKey("//:top_level"); } @Test public void testEditingUnreadResourceFileDoesNotRebuildDependents() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); // Edit the unread metadata file and assert no dep file false negative workspace.replaceFileContents("res/META-INF/unread.json", "replace_me", "foobar"); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetHadMatchingDepfileRuleKey("//:top_level"); } @Test public void testEditingUnreadResourceFileDoesNotChangeManifestKey() throws Exception { AssumeAndroidPlatform.assumeSdkIsAvailable(); // Build once to warm cache workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:top_level"); workspace.runBuckCommand("clean").assertSuccess(); // Edit the unread metadata file and assert we can get a manifest hit workspace.replaceFileContents("res/META-INF/unread.json", "replace_me", "foobar"); workspace.runBuckCommand("build", "//:top_level").assertSuccess(); workspace.getBuildLog().assertTargetBuiltLocally("//:lib"); workspace.getBuildLog().assertTargetWasFetchedFromCacheByManifestMatch("//:top_level"); } private void expectGenruleOutputContains(String genrule, String expectedOutputFragment) throws Exception { ProjectWorkspace.ProcessResult buildResult = workspace.runBuckCommand("build", genrule); buildResult.assertSuccess(); String outputFileContents = workspace.getFileContents(getOutputFile(genrule)); assertThat(outputFileContents, Matchers.containsString(expectedOutputFragment)); } private Path getOutputFile(String targetName) { try { ProjectWorkspace.ProcessResult buildResult = workspace.runBuckCommand("targets", targetName, "--show-full-output", "--json"); buildResult.assertSuccess(); JsonNode jsonNode = ObjectMappers.READER.readTree(buildResult.getStdout()).get(0); assert jsonNode.has("buck.outputPath"); return Paths.get(jsonNode.get("buck.outputPath").asText()); } catch (Exception e) { fail(e.getMessage()); return Paths.get(""); } } }