mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-13 15:52:01 +07:00
IJPL-578 wait for project activities on project start in tests
Otherwise, some tests that expect project activities to complete, will fail. E.g. CMakeWorkspaceOutputConsoleTest GitOrigin-RevId: 851c334a64d11ebbbfe579e61d9dbe794f719f20
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ecacc8bbd2
commit
b7a4fa5972
@@ -36,6 +36,7 @@ import com.intellij.platform.diagnostic.telemetry.Scope
|
||||
import com.intellij.platform.diagnostic.telemetry.TelemetryManager
|
||||
import com.intellij.serviceContainer.ComponentManagerImpl
|
||||
import com.intellij.util.ModalityUiUtil
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.concurrency.ThreadingAssertions
|
||||
import io.opentelemetry.api.common.AttributeKey
|
||||
import io.opentelemetry.api.common.Attributes
|
||||
@@ -48,6 +49,7 @@ import org.jetbrains.annotations.VisibleForTesting
|
||||
import java.awt.event.InvocationEvent
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
|
||||
@@ -175,14 +177,10 @@ open class StartupManagerImpl(private val project: Project, private val coroutin
|
||||
}
|
||||
else {
|
||||
val activities = runPostStartupActivities(async = true)
|
||||
if (coroutineContext.contextModality() == null || coroutineContext.contextModality() == ModalityState.nonModal()) {
|
||||
withTimeout(2.minutes) {
|
||||
activities.joinAll()
|
||||
}
|
||||
withTimeout(2.minutes) {
|
||||
activities.joinAll()
|
||||
}
|
||||
|
||||
// don't wait, because waiting under modal progress may result in a deadlock
|
||||
// (for example, if activities are waiting for smart mode which will only start in non-modal context)
|
||||
CompletableDeferred(activities)
|
||||
}
|
||||
}
|
||||
@@ -258,7 +256,9 @@ open class StartupManagerImpl(private val project: Project, private val coroutin
|
||||
|
||||
if (activity is ProjectActivity) {
|
||||
if (async) {
|
||||
val job = launchActivity(activity = activity, project = project, pluginId = pluginDescriptor.pluginId)
|
||||
val job = blockingContext {
|
||||
launchActivity(activity = activity, project = project, pluginId = pluginDescriptor.pluginId)
|
||||
}
|
||||
launchedActivities.add(job)
|
||||
}
|
||||
else {
|
||||
@@ -466,8 +466,13 @@ private fun launchBackgroundPostStartupActivity(activity: Any, pluginId: PluginI
|
||||
}
|
||||
|
||||
private fun launchActivity(activity: ProjectActivity, project: Project, pluginId: PluginId): Job {
|
||||
// we propagate modality only in unit tests, because in unit tests activities are often started in modal context (see TestProjectManager),
|
||||
// so any "invokeAndWait" will hang without modality propagation. In the future we want to avoid .joinAll in runPostStartupActivities at all.
|
||||
val launchTaskModality = if (application.isUnitTestMode) currentThreadContextModality() else null
|
||||
val launchTaskModalityContext = launchTaskModality?.asContextElement() ?: EmptyCoroutineContext
|
||||
|
||||
return (project as ComponentManagerImpl).pluginCoroutineScope(activity.javaClass.classLoader).launch(
|
||||
tracer.rootSpan(name = "run activity", arrayOf("class", activity.javaClass.name, "plugin", pluginId.idString))
|
||||
launchTaskModalityContext + tracer.rootSpan(name = "run activity", arrayOf("class", activity.javaClass.name, "plugin", pluginId.idString)),
|
||||
) {
|
||||
activity.execute(project)
|
||||
}
|
||||
|
||||
@@ -27,16 +27,12 @@ import com.intellij.openapi.project.impl.runInitProjectActivities
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.testFramework.LeakHunter
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import com.intellij.testFramework.TestApplicationManager.Companion.publishHeapDump
|
||||
import com.intellij.testFramework.common.LEAKED_PROJECTS
|
||||
import com.intellij.util.ModalityUiUtil
|
||||
import com.intellij.util.application
|
||||
import com.intellij.util.containers.UnsafeWeakList
|
||||
import com.intellij.util.ref.GCUtil
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.future.asCompletableFuture
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
@@ -118,7 +114,7 @@ open class TestProjectManager : ProjectManagerImpl() {
|
||||
|
||||
val app = ApplicationManager.getApplication()
|
||||
try {
|
||||
val launchedActivities: List<Job> = runUnderModalProgressIfIsEdt {
|
||||
runUnderModalProgressIfIsEdt {
|
||||
coroutineScope {
|
||||
runInitProjectActivities(project = project)
|
||||
}
|
||||
@@ -129,17 +125,6 @@ open class TestProjectManager : ProjectManagerImpl() {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
// wait outside the modal progress, because some activities will be waiting for smart mode
|
||||
// which on start will only start in non-modal context
|
||||
launchedActivities.forEach {
|
||||
if (application.isDispatchThread) {
|
||||
PlatformTestUtil.waitForFuture(it.asCompletableFuture())
|
||||
}
|
||||
else {
|
||||
it.asCompletableFuture().get(2, TimeUnit.MINUTES)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e: ProcessCanceledException) {
|
||||
app.invokeAndWait { closeProject(project, saveProject = false, checkCanClose = false) }
|
||||
|
||||
Reference in New Issue
Block a user