| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * 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.android.tools.idea.gradle.project.sync; |
| |
| import static com.android.testutils.TestUtils.getKotlinVersionForTests; |
| import static com.android.tools.idea.gradle.project.sync.ng.NewGradleSync.NOT_ELIGIBLE_FOR_SINGLE_VARIANT_SYNC; |
| import static com.android.tools.idea.testing.TestProjectPaths.DEPENDENT_MODULES; |
| import static com.android.tools.idea.testing.TestProjectPaths.HELLO_JNI; |
| import static com.google.common.truth.Truth.assertThat; |
| import static com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction; |
| import static com.intellij.openapi.externalSystem.service.notification.NotificationCategory.ERROR; |
| import static com.intellij.openapi.util.io.FileUtil.appendToFile; |
| import static com.intellij.openapi.util.io.FileUtil.join; |
| import static com.intellij.openapi.util.io.FileUtil.writeToFile; |
| |
| import com.android.tools.idea.flags.StudioFlags; |
| import com.android.tools.idea.gradle.dsl.api.ProjectBuildModel; |
| import com.android.tools.idea.gradle.project.GradleExperimentalSettings; |
| import com.android.tools.idea.gradle.project.model.NdkModuleModel; |
| import com.android.tools.idea.gradle.project.sync.messages.GradleSyncMessagesStub; |
| import com.android.tools.idea.gradle.project.sync.ng.NewGradleSync; |
| import com.intellij.ide.util.PropertiesComponent; |
| import com.intellij.openapi.externalSystem.service.notification.NotificationData; |
| import com.intellij.openapi.module.Module; |
| import com.intellij.openapi.module.ModuleManager; |
| import com.intellij.openapi.project.Project; |
| import java.io.File; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.stream.Collectors; |
| import org.jetbrains.android.facet.AndroidFacet; |
| |
| public class SingleVariantSyncIntegrationTest extends NewGradleSyncIntegrationTest { |
| |
| @Override |
| protected boolean useSingleVariantSyncInfrastructure() { |
| return true; |
| } |
| |
| @Override |
| public void testSyncIssueWithNonMatchingVariantAttributes() throws Exception { |
| Project project = getProject(); |
| GradleSyncMessagesStub syncMessages = GradleSyncMessagesStub.replaceSyncMessagesService(project); |
| |
| // DEPENDENT_MODULES project has two modules, app and lib, app module has dependency on lib module. |
| loadProject(DEPENDENT_MODULES); |
| |
| // Define new buildType qa in app module. |
| // This causes sync issues, because app depends on lib module, but lib module doesn't have buildType qa. |
| File appBuildFile = getBuildFilePath("app"); |
| appendToFile(appBuildFile, "\nandroid.buildTypes { qa { } }\n"); |
| |
| // Make paidQa the selected variant, because only the selected variant is requested in Single-Variant sync. |
| Module appModule = getModule("app"); |
| AndroidFacet facet = AndroidFacet.getInstance(appModule); |
| facet.getProperties().SELECTED_BUILD_VARIANT = "paidQa"; |
| |
| try { |
| requestSyncAndWait(); |
| } |
| catch (AssertionError expected) { |
| // Sync issues are expected. |
| } |
| |
| // Verify sync issues are reported properly. |
| List<NotificationData> messages = syncMessages.getNotifications(); |
| assertThat(messages).hasSize(2); |
| NotificationData message = messages.get(0); |
| |
| assertEquals(ERROR, message.getNotificationCategory()); |
| assertEquals("Unresolved dependencies", message.getTitle()); |
| assertThat(message.getMessage()).contains( |
| "Unable to resolve dependency for ':app@paidQa/compileClasspath': Could not resolve project :lib.\nAffected Modules:"); |
| } |
| |
| public void testSingleVariantSyncAfterFailedIdeaSync() throws Exception { |
| StudioFlags.SINGLE_VARIANT_SYNC_ENABLED.override(false); |
| GradleExperimentalSettings.getInstance().USE_SINGLE_VARIANT_SYNC = false; |
| loadProject(HELLO_JNI); |
| |
| // Write empty CMakeLists file to force empty variants models from AGP. |
| File cmakeFile = new File(getProjectFolderPath(), join("app", "src", "main", "cpp", "CMakeLists.txt")); |
| writeToFile(cmakeFile, ""); |
| requestSyncAndWait(); |
| // Verify Ndk model only contains one dummy variant. |
| NdkModuleModel ndkModuleModel = NdkModuleModel.get(getModule("app")); |
| assertThat(ndkModuleModel.getVariants()).hasSize(1); |
| assertThat(ndkModuleModel.getNdkVariantNames()).contains(NdkModuleModel.DummyNdkVariant.variantNameWithAbi); |
| |
| // Switch to single-variant sync, and verify sync is succeeded. |
| StudioFlags.SINGLE_VARIANT_SYNC_ENABLED.override(true); |
| GradleExperimentalSettings.getInstance().USE_SINGLE_VARIANT_SYNC = true; |
| requestSyncAndWait(); |
| ndkModuleModel = NdkModuleModel.get(getModule("app")); |
| // Verify Single-variant sync is able to retrieve variant names with empty CMakeList. |
| assertThat(ndkModuleModel.getNdkVariantNames().size()).isGreaterThan(1); |
| assertThat(ndkModuleModel.getNdkVariantNames()).doesNotContain(NdkModuleModel.DummyNdkVariant.variantNameWithAbi); |
| } |
| |
| public void testAddKotlinPluginToNonKotlinProject() throws Exception { |
| loadSimpleApplication(); |
| // Verify that project is eligible for single-variant. |
| assertFalse(PropertiesComponent.getInstance(getProject()).getBoolean((NOT_ELIGIBLE_FOR_SINGLE_VARIANT_SYNC))); |
| assertTrue(NewGradleSync.isSingleVariantSync(getProject())); |
| |
| // Add kotlin-android plugin to top-level build file, and app module. |
| ProjectBuildModel buildModel = ProjectBuildModel.get(getProject()); |
| buildModel.getProjectBuildModel().buildscript().dependencies() |
| .addArtifact("classpath", "org.jetbrains.kotlin:kotlin-gradle-plugin:" + getKotlinVersionForTests()); |
| buildModel.getModuleBuildModel(getModule("app")).applyPlugin("kotlin-android"); |
| runWriteCommandAction(getProject(), buildModel::applyChanges); |
| |
| // Request Gradle sync. |
| requestSyncAndWait(); |
| |
| // Verify that project is not eligible for single-variant. |
| assertTrue(PropertiesComponent.getInstance(getProject()).getBoolean((NOT_ELIGIBLE_FOR_SINGLE_VARIANT_SYNC))); |
| assertFalse(NewGradleSync.isSingleVariantSync(getProject())); |
| } |
| |
| public void testSyncProjectWithBuildSrcModule() throws Exception { |
| loadSimpleApplication(); |
| // Verify that project is eligible for single-variant. |
| assertFalse(PropertiesComponent.getInstance(getProject()).getBoolean((NOT_ELIGIBLE_FOR_SINGLE_VARIANT_SYNC))); |
| assertTrue(NewGradleSync.isSingleVariantSync(getProject())); |
| |
| // Create buildSrc folder under root project. |
| File buildSrcDir = new File(getProject().getBasePath(), "buildSrc"); |
| File buildFile = new File(buildSrcDir, "build.gradle"); |
| writeToFile(buildFile, "repositories {}"); |
| |
| // Request Gradle sync. |
| requestSyncAndWait(); |
| |
| // Verify that project is set as not eligible for single-variant. |
| assertTrue(PropertiesComponent.getInstance(getProject()).getBoolean((NOT_ELIGIBLE_FOR_SINGLE_VARIANT_SYNC))); |
| assertFalse(NewGradleSync.isSingleVariantSync(getProject())); |
| |
| // Verify that buildSrc module exists. |
| List<String> moduleNames = |
| Arrays.stream(ModuleManager.getInstance(getProject()).getModules()).map(module -> module.getName()).collect(Collectors.toList()); |
| assertThat(moduleNames).contains("buildSrc"); |
| } |
| } |