From 2bc51f6d671ab2577eedd1dadaff0ae3da8d4050 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 4 Jul 2022 14:14:10 +0200 Subject: [PATCH] use kotlin coroutines instead of fork-join pool and completable future (part 16 - fix gradle tests) GitOrigin-RevId: 54152b2b364a82ee1f3ec6465bdad59dc168a2a9 --- .../openapi/project/ex/ProjectManagerEx.kt | 10 +++-- .../project/impl/ProjectManagerImpl.kt | 15 +++---- .../impl/CodeInsightTestFixtureImpl.java | 5 ++- .../fixtures/impl/GradleTestFixtureImpl.kt | 41 +++++++++++++++---- .../testFramework/util/GradleProjectUtil.kt | 35 +++------------- 5 files changed, 54 insertions(+), 52 deletions(-) diff --git a/platform/ide-core-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.kt b/platform/ide-core-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.kt index 6f1bf7cfaa7f..fc84aca8a64c 100644 --- a/platform/ide-core-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.kt +++ b/platform/ide-core-impl/src/com/intellij/openapi/project/ex/ProjectManagerEx.kt @@ -56,13 +56,17 @@ abstract class ProjectManagerEx : ProjectManager() { /** * The project and the app settings will be not saved. */ - abstract fun forceCloseProject(project: Project): Boolean + @TestOnly + fun forceCloseProject(project: Project): Boolean = forceCloseProject(project, save = false) + + @TestOnly + abstract fun forceCloseProject(project: Project, save: Boolean): Boolean @Internal - abstract suspend fun forceCloseProjectAsync(project: Project): Boolean + abstract suspend fun forceCloseProjectAsync(project: Project, save: Boolean = false): Boolean @Internal - abstract fun saveAndForceCloseProject(project: Project): Boolean + fun saveAndForceCloseProject(project: Project): Boolean = forceCloseProject(project, save = true) // return true if successful abstract fun closeAndDisposeAllProjects(checkCanClose: Boolean): Boolean diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt index ab78f5c61617..54bcfe9332a9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.kt @@ -296,23 +296,20 @@ open class ProjectManagerImpl : ProjectManagerEx(), Disposable { return closeProject(project = project, saveProject = true, dispose = false, checkCanClose = true) } - override fun forceCloseProject(project: Project): Boolean { - return closeProject(project = project, saveProject = false, dispose = true, checkCanClose = false) + override fun forceCloseProject(project: Project, save: Boolean): Boolean { + return closeProject(project = project, saveProject = save, dispose = true, checkCanClose = false) } - override suspend fun forceCloseProjectAsync(project: Project): Boolean { - return withContext(Dispatchers.EDT) { + override suspend fun forceCloseProjectAsync(project: Project, save: Boolean): Boolean { + // ModalityState.NON_MODAL for write-safe context + return withContext(Dispatchers.EDT + ModalityState.NON_MODAL.asContextElement()) { if (project.isDisposed) { return@withContext false } - closeProject(project = project, saveProject = false, dispose = true, checkCanClose = false) + closeProject(project = project, saveProject = save, dispose = true, checkCanClose = false) } } - override fun saveAndForceCloseProject(project: Project): Boolean { - return closeProject(project = project, saveProject = true, dispose = true, checkCanClose = false) - } - // return true if successful override fun closeAndDisposeAllProjects(checkCanClose: Boolean): Boolean { var projects = openProjects diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java index 7e98760fc14a..fc0fae47659e 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.testFramework.fixtures.impl; import com.intellij.analysis.AnalysisScope; @@ -132,6 +132,7 @@ import com.intellij.util.indexing.FindSymbolParameters; import com.intellij.util.io.ReadOnlyAttributeUtil; import com.intellij.util.ui.UIUtil; import junit.framework.ComparisonFailure; +import kotlin.UninitializedPropertyAccessException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -1290,7 +1291,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig try { project = myProjectFixture.getProject(); } - catch (AssertionError ignore) { + catch (AssertionError | UninitializedPropertyAccessException ignore) { project = null; } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/fixtures/impl/GradleTestFixtureImpl.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/fixtures/impl/GradleTestFixtureImpl.kt index 9d096bead671..d3a53f329e6f 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/fixtures/impl/GradleTestFixtureImpl.kt +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/fixtures/impl/GradleTestFixtureImpl.kt @@ -1,6 +1,7 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.gradle.testFramework.fixtures.impl +import com.intellij.ide.impl.ProjectUtil import com.intellij.openapi.Disposable import com.intellij.openapi.externalSystem.importing.ImportSpecBuilder import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId @@ -13,6 +14,7 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.observable.operations.CompoundParallelOperationTrace import com.intellij.openapi.observable.operations.ObservableOperationTrace import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ex.ProjectManagerEx import com.intellij.openapi.project.modules import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.VirtualFile @@ -20,13 +22,18 @@ import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.fixtures.SdkTestFixture import com.intellij.testFramework.runAll import com.intellij.testFramework.runInEdtAndWait +import kotlinx.coroutines.runBlocking import org.gradle.util.GradleVersion import org.jetbrains.concurrency.AsyncPromise +import org.jetbrains.concurrency.asDeferred import org.jetbrains.plugins.gradle.testFramework.fixtures.FileTestFixture import org.jetbrains.plugins.gradle.testFramework.fixtures.GradleTestFixture import org.jetbrains.plugins.gradle.testFramework.fixtures.GradleTestFixtureFactory -import org.jetbrains.plugins.gradle.testFramework.util.* +import org.jetbrains.plugins.gradle.testFramework.util.closeProject +import org.jetbrains.plugins.gradle.testFramework.util.generateWrapper +import org.jetbrains.plugins.gradle.testFramework.util.withSuppressedErrors import org.jetbrains.plugins.gradle.util.GradleConstants +import org.jetbrains.plugins.gradle.util.getProjectDataLoadPromise import org.jetbrains.plugins.gradle.util.waitForProjectReload import java.util.concurrent.TimeUnit @@ -56,7 +63,7 @@ internal class GradleTestFixtureImpl private constructor( GradleTestFixtureFactory.getFixtureFactory().createFileTestFixture("GradleTestFixture/$gradleVersion/$projectName") { configureProject() withFiles { generateWrapper(it, gradleVersion) } - withFiles { createProjectCaches(it) } + withFiles { runBlocking { createProjectCaches(it) } } } ) @@ -69,7 +76,7 @@ internal class GradleTestFixtureImpl private constructor( installTaskExecutionWatcher() installProjectReloadWatcher() - _project = openProject(fileFixture.root) + _project = runBlocking { ProjectUtil.openOrImportAsync(fileFixture.root.toNioPath())!! } } override fun tearDown() { @@ -139,12 +146,30 @@ internal class GradleTestFixtureImpl private constructor( } } - private fun createProjectCaches(projectRoot: VirtualFile) { + private suspend fun createProjectCaches(projectRoot: VirtualFile) { val project = openProjectAndWait(projectRoot) - runAll( - { projectRoot.refreshAndWait() }, - { project.closeProject(save = true) } - ) + try { + projectRoot.refreshAndWait() + } + finally { + ProjectManagerEx.getInstanceEx().forceCloseProjectAsync(project = project, save = true) + } } } +} + +private suspend fun openProjectAndWait(projectRoot: VirtualFile): Project { + val project = ProjectUtil.openOrImportAsync(projectRoot.toNioPath())!! + try { + getProjectDataLoadPromise().asDeferred().await() + } + catch (e: Throwable) { + try { + ProjectManagerEx.getInstanceEx().forceCloseProjectAsync(project) + } + catch (ignore: Throwable) { + } + throw e + } + return project } \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleProjectUtil.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleProjectUtil.kt index cd15e46779b7..7693a9db3a66 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleProjectUtil.kt +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleProjectUtil.kt @@ -1,44 +1,19 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package org.jetbrains.plugins.gradle.testFramework.util -import com.intellij.configurationStore.StoreUtil -import com.intellij.ide.impl.ProjectUtil -import com.intellij.openapi.externalSystem.util.runInEdtAndWait import com.intellij.openapi.project.Project import com.intellij.openapi.project.ex.ProjectManagerEx -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.testFramework.runAll import com.intellij.util.createException import kotlinx.coroutines.runBlocking -import org.jetbrains.plugins.gradle.util.waitForProjectReload -fun openProject(projectRoot: VirtualFile): Project { - return runBlocking { ProjectUtil.openOrImportAsync(projectRoot.toNioPath())!! } -} - -fun Project.closeProject(save: Boolean = false) { - runInEdtAndWait { - val projectManager = ProjectManagerEx.getInstanceEx() - runAll( - { if (save) StoreUtil.saveSettings(this, forceSavingAllSettings = true) }, - { projectManager.forceCloseProject(this) } - ) +internal fun Project.closeProject(save: Boolean = false) { + val project = this + runBlocking { + ProjectManagerEx.getInstanceEx().forceCloseProjectAsync(project, save = save) } } -fun openProjectAndWait(projectRoot: VirtualFile): Project { - var project: Project? = null - return runCatching { - waitForProjectReload { - project = openProject(projectRoot) - project!! - } - }.onFailureCatching { - project?.closeProject() - }.getOrThrow() -} - -fun Result.onFailureCatching(action: (Throwable) -> Unit): Result { +internal fun Result.onFailureCatching(action: (Throwable) -> Unit): Result { val exception = exceptionOrNull() ?: return this val secondaryException = runCatching { action(exception) }.exceptionOrNull() val compound = createException(listOf(exception, secondaryException))!!