Merge "Fixed how project sync handles invalid cached models." into studio-1.2-release
diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java
index 80ceb66..a3f2ee4 100644
--- a/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java
+++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java
@@ -38,6 +38,9 @@
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.externalSystem.model.DataNode;
+import com.intellij.openapi.externalSystem.model.project.ModuleData;
+import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -50,6 +53,7 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SystemProperties;
import junit.framework.Assert;
+import org.fest.reflect.reference.TypeRef;
import org.fest.swing.core.GenericTypeMatcher;
import org.fest.swing.core.matcher.DialogMatcher;
import org.fest.swing.data.TableCell;
@@ -60,6 +64,7 @@
import org.fest.swing.fixture.JButtonFixture;
import org.fest.swing.fixture.JTableFixture;
import org.fest.swing.timing.Condition;
+import org.jetbrains.android.AndroidPlugin.GuiTestSuiteState;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -100,6 +105,7 @@
import static com.intellij.util.SystemProperties.getLineSeparator;
import static junit.framework.Assert.*;
import static org.fest.assertions.Assertions.assertThat;
+import static org.fest.reflect.core.Reflection.field;
import static org.fest.swing.core.matcher.DialogMatcher.withTitle;
import static org.fest.swing.core.matcher.JButtonMatcher.withText;
import static org.fest.swing.data.TableCell.row;
@@ -108,13 +114,17 @@
import static org.fest.swing.timing.Pause.pause;
import static org.fest.util.Strings.quote;
import static org.jetbrains.android.AndroidPlugin.GRADLE_SYNC_COMMAND_LINE_OPTIONS_KEY;
+import static org.jetbrains.android.AndroidPlugin.getGuiTestSuiteState;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class GradleSyncTest extends GuiTestCase {
@Before
- public void disableSourceGenTask() {
+ public void resetIdeState() {
GradleExperimentalSettings.getInstance().SKIP_SOURCE_GEN_ON_PROJECT_SYNC = true;
+ GuiTestSuiteState state = getGuiTestSuiteState();
+ assertNotNull(state);
+ state.setUseCachedGradleModelOnly(false);
}
@After
@@ -917,6 +927,40 @@
assertThat(moduleDependency.getModuleName()).isEqualTo("library2");
}
+ // Verifies that if syncing using cached model, and if the cached model is missing data, we fall back to a full Gradle sync.
+ // See: https://code.google.com/p/android/issues/detail?id=160899
+ @Test @IdeGuiTest
+ public void testWithCacheMissingModules() throws IOException {
+ IdeFrameFixture projectFrame = openSimpleApplication();
+
+ // Remove a module from the cache.
+ Project project = projectFrame.getProject();
+ DataNode<ProjectData> cache = getCachedProjectData(project);
+ assertNotNull(cache);
+
+ List<DataNode<?>> cachedChildren = field("myChildren").ofType(new TypeRef<List<DataNode<?>>>(){}).in(cache).get();
+ assertThat(cachedChildren.size()).isGreaterThan(1);
+ DataNode<?> toRemove = null;
+ for (DataNode<?> child : cachedChildren) {
+ if (child.getData() instanceof ModuleData) {
+ toRemove = child;
+ break;
+ }
+ }
+ assertNotNull(toRemove);
+ cachedChildren.remove(toRemove);
+
+ // Force the IDE to use cache for sync.
+ GuiTestSuiteState state = getGuiTestSuiteState();
+ assertNotNull(state);
+ state.setUseCachedGradleModelOnly(true);
+
+ // Sync again, and a full sync should occur, since the cache is missing modules.
+ // 'waitForGradleProjectSyncToFinish' will never finish and test will time out and fail if the IDE never gets notified that the sync
+ // finished.
+ projectFrame.requestProjectSync().waitForGradleProjectSyncToFinish();
+ }
+
@NotNull
private static String getUnsupportedGradleHome() {
return getGradleHomeFromSystemProperty(UNSUPPORTED_GRADLE_HOME_PROPERTY, "2.1");
diff --git a/android/src/com/android/tools/idea/gradle/project/GradleProjectImporter.java b/android/src/com/android/tools/idea/gradle/project/GradleProjectImporter.java
index 5616f40..a3a179b 100755
--- a/android/src/com/android/tools/idea/gradle/project/GradleProjectImporter.java
+++ b/android/src/com/android/tools/idea/gradle/project/GradleProjectImporter.java
@@ -65,6 +65,7 @@
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.util.SystemProperties;
+import org.jetbrains.android.AndroidPlugin.GuiTestSuiteState;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.newProject.AndroidModuleBuilder;
import org.jetbrains.annotations.NotNull;
@@ -98,6 +99,8 @@
import static com.intellij.openapi.util.io.FileUtilRt.createIfNotExists;
import static com.intellij.ui.AppUIUtil.invokeLaterIfProjectAlive;
import static com.intellij.util.ui.UIUtil.invokeAndWaitIfNeeded;
+import static org.jetbrains.android.AndroidPlugin.getGuiTestSuiteState;
+import static org.jetbrains.android.AndroidPlugin.isGuiTestingMode;
/**
* Imports an Android-Gradle project without showing the "Import Project" Wizard UI.
@@ -107,7 +110,8 @@
private static final ProjectSystemId SYSTEM_ID = GradleConstants.SYSTEM_ID;
// When this system property is set, the sync operation always tries to use the cached project data unless any gradle files are modified.
- private static final boolean alwaysSyncWithCachedProjectData = Boolean.getBoolean("studio.sync.with.cached.project.data");
+ private static final boolean SYNC_WITH_CACHED_MODEL_ONLY =
+ SystemProperties.getBooleanProperty("studio.sync.with.cached.model.only", false);
private final ImporterDelegate myDelegate;
@@ -533,21 +537,19 @@
setHasSyncErrors(project, false);
setHasWrongJdk(project, false);
- if (alwaysSyncWithCachedProjectData || options.useCachedProjectData) {
+ if (forceSyncWithCachedModel() || options.useCachedProjectData) {
GradleProjectSyncData syncData = GradleProjectSyncData.getInstance((project));
if (syncData != null && syncData.canUseCachedProjectData()) {
DataNode<ProjectData> cache = getCachedProjectData(project);
- if (cache != null) {
+ if (cache != null && !isCacheMissingModels(cache, project)) {
PostProjectSetupTasksExecutor executor = PostProjectSetupTasksExecutor.getInstance(project);
executor.setGenerateSourcesAfterSync(false);
executor.setUsingCachedProjectData(true);
executor.setLastSyncTimestamp(syncData.getLastGradleSyncTimestamp());
- if (!isCacheMissingModels(cache, project)) {
- ProjectSetUpTask setUpTask = new ProjectSetUpTask(project, newProject, options.importingExistingProject, true, listener);
- setUpTask.onSuccess(cache);
- return;
- }
+ ProjectSetUpTask setUpTask = new ProjectSetUpTask(project, newProject, options.importingExistingProject, true, listener);
+ setUpTask.onSuccess(cache);
+ return;
}
}
}
@@ -561,6 +563,18 @@
myDelegate.importProject(project, setUpTask, progressExecutionMode);
}
+ private static boolean forceSyncWithCachedModel() {
+ if (SYNC_WITH_CACHED_MODEL_ONLY) {
+ return true;
+ }
+ if (isGuiTestingMode()) {
+ GuiTestSuiteState state = getGuiTestSuiteState();
+ assert state != null;
+ return state.syncWithCachedModelOnly();
+ }
+ return false;
+ }
+
@NotNull
private static String getProjectBasePath(Project project) {
String projectBasePath = toCanonicalPath(project.getBasePath());
@@ -577,11 +591,16 @@
ModuleManager moduleManager = ModuleManager.getInstance(project);
for (Module module : moduleManager.getModules()) {
DataNode<ModuleData> moduleDataNode = moduleDataNodesByName.get(module.getName());
- if (moduleDataNode != null) {
- if (isCacheMissingModels(moduleDataNode, module)) {
+ if (moduleDataNode == null) {
+ // When a Gradle facet is present, there should be a cache node for the module.
+ AndroidGradleFacet gradleFacet = AndroidGradleFacet.getInstance(module);
+ if (gradleFacet != null) {
return true;
}
}
+ else if (isCacheMissingModels(moduleDataNode, module)) {
+ return true;
+ }
}
return false;
}
diff --git a/android/src/org/jetbrains/android/AndroidPlugin.java b/android/src/org/jetbrains/android/AndroidPlugin.java
index 51462be..fa62876 100644
--- a/android/src/org/jetbrains/android/AndroidPlugin.java
+++ b/android/src/org/jetbrains/android/AndroidPlugin.java
@@ -67,6 +67,7 @@
public static class GuiTestSuiteState {
private boolean myOpenProjectWizardAlreadyTested;
private boolean myImportProjectWizardAlreadyTested;
+ private boolean myUseCachedGradleModelOnly;
public boolean isOpenProjectWizardAlreadyTested() {
return myOpenProjectWizardAlreadyTested;
@@ -83,5 +84,13 @@
public void setImportProjectWizardAlreadyTested(boolean importProjectWizardAlreadyTested) {
myImportProjectWizardAlreadyTested = importProjectWizardAlreadyTested;
}
+
+ public boolean syncWithCachedModelOnly() {
+ return myUseCachedGradleModelOnly;
+ }
+
+ public void setUseCachedGradleModelOnly(boolean useCachedGradleModelOnly) {
+ myUseCachedGradleModelOnly = useCachedGradleModelOnly;
+ }
}
}