From 4b5a4a8a97992a5919bbd37fd59d54b5e1dc2ed5 Mon Sep 17 00:00:00 2001 From: Sergei Vorobyov Date: Tue, 17 Sep 2024 15:03:23 +0200 Subject: [PATCH] [NPW|Assets] fix: wait for project wizard tracked project configurations (Reformat code, VF and PSI file resolution) Issues: IDEA-349863, IDEA-341180 GitOrigin-RevId: bf359aaea23f21c2843d17aab12c0bc656224190 --- .../intellij.java.testFramework.iml | 1 + .../projectWizard/ProjectWizardTestCase.java | 11 ++- .../intellij/testFramework/TestObservation.kt | 70 +++++++++++++++++++ .../util/GradleOperationTestUtil.kt | 34 ++------- 4 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 java/testFramework/src/com/intellij/testFramework/TestObservation.kt diff --git a/java/testFramework/intellij.java.testFramework.iml b/java/testFramework/intellij.java.testFramework.iml index dee3d92f098e..60eca31c508d 100644 --- a/java/testFramework/intellij.java.testFramework.iml +++ b/java/testFramework/intellij.java.testFramework.iml @@ -33,6 +33,7 @@ + diff --git a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java index 438c32b32c86..fc04192c4bea 100644 --- a/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java +++ b/java/testFramework/src/com/intellij/ide/projectWizard/ProjectWizardTestCase.java @@ -28,6 +28,7 @@ import com.intellij.projectImport.ProjectImportProvider; import com.intellij.testFramework.HeavyPlatformTestCase; import com.intellij.testFramework.IndexingTestUtil; import com.intellij.testFramework.PlatformTestUtil; +import com.intellij.testFramework.TestObservation; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; @@ -37,6 +38,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Supplier; @@ -124,6 +126,7 @@ public abstract class ProjectWizardTestCase ext UIUtil.dispatchAllInvocationEvents(); IndexingTestUtil.waitUntilIndexesAreReady(myCreatedProject); + TestObservation.waitForConfiguration(TimeUnit.MINUTES.toMillis(10), myCreatedProject, LOG::debug); return myCreatedProject; } @@ -133,7 +136,13 @@ public abstract class ProjectWizardTestCase ext } private Module createModuleFromWizard(@NotNull Project project) { - return new NewModuleAction().createModuleFromWizard(project, null, myWizard); + Module createdModule = new NewModuleAction().createModuleFromWizard(project, null, myWizard); + + UIUtil.dispatchAllInvocationEvents(); + IndexingTestUtil.waitUntilIndexesAreReady(project); + TestObservation.waitForConfiguration(TimeUnit.MINUTES.toMillis(10), project, LOG::debug); + + return createdModule; } private static void setSelectedTemplate(@NotNull Step step, @NotNull String group, @Nullable String name) { diff --git a/java/testFramework/src/com/intellij/testFramework/TestObservation.kt b/java/testFramework/src/com/intellij/testFramework/TestObservation.kt new file mode 100644 index 000000000000..c15b2c8cf17a --- /dev/null +++ b/java/testFramework/src/com/intellij/testFramework/TestObservation.kt @@ -0,0 +1,70 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.testFramework + +import com.intellij.diagnostic.ThreadDumper +import com.intellij.diagnostic.dumpCoroutines +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.platform.backend.observation.Observation +import com.intellij.testFramework.concurrency.waitForPromiseAndPumpEdt +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout +import org.jetbrains.concurrency.asPromise +import java.util.function.Consumer +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds + +object TestObservation { + + @JvmStatic + @JvmOverloads + fun waitForConfiguration(timeout: Long, project: Project, messageCallback: Consumer? = null) { + waitForConfiguration(timeout.milliseconds, project, messageCallback?.let { it::accept }) + } + + fun waitForConfiguration(timeout: Duration, project: Project, messageCallback: ((String) -> Unit)? = null) { + val coroutineScope = CoroutineScopeService.getCoroutineScope(project) + val job = coroutineScope.launch { + awaitConfiguration(timeout, project, messageCallback) + } + val promise = job.asPromise() + promise.waitForPromiseAndPumpEdt(Duration.INFINITE) + } + + suspend fun awaitConfiguration(timeout: Duration, project: Project, messageCallback: ((String) -> Unit)? = null) { + try { + withTimeout(timeout) { + Observation.awaitConfiguration(project, messageCallback) + } + } + catch (_: TimeoutCancellationException) { + throwWaitingTimoutError(timeout) + } + } + + private fun throwWaitingTimoutError(timeout: Duration): Nothing { + val coroutineDump = dumpCoroutines() + val threadDump = ThreadDumper.dumpThreadsToString() + throw AssertionError(""" + |The waiting takes too long. Expected to take no more than $timeout ms. + |------- Thread dump begin ------- + |$threadDump + |-------- Thread dump end -------- + |------ Coroutine dump begin ----- + |$coroutineDump + |------- Coroutine dump end ------ + """.trimMargin()) + } + + @Service(Service.Level.PROJECT) + private class CoroutineScopeService(private val coroutineScope: CoroutineScope) { + companion object { + fun getCoroutineScope(project: Project): CoroutineScope { + return project.service().coroutineScope + } + } + } +} \ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleOperationTestUtil.kt b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleOperationTestUtil.kt index 17ad16487338..cd9990f13d52 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleOperationTestUtil.kt +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testFramework/util/GradleOperationTestUtil.kt @@ -5,8 +5,6 @@ package org.jetbrains.plugins.gradle.testFramework.util import com.intellij.build.BuildProgressListener import com.intellij.build.output.BuildOutputParser -import com.intellij.diagnostic.ThreadDumper -import com.intellij.diagnostic.dumpCoroutines import com.intellij.execution.ExecutionListener import com.intellij.execution.ExecutionManager import com.intellij.execution.process.ProcessHandler @@ -26,14 +24,12 @@ import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.ThrowableComputable import com.intellij.openapi.util.use import com.intellij.platform.backend.observation.ActivityKey -import com.intellij.platform.backend.observation.Observation import com.intellij.platform.backend.observation.trackActivity import com.intellij.testFramework.ExtensionTestUtil +import com.intellij.testFramework.TestObservation import com.intellij.testFramework.common.DEFAULT_TEST_TIMEOUT import com.intellij.testFramework.observable.operation.core.waitForOperationAndPumpEdt import com.intellij.testFramework.withProjectAsync -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.withTimeout import org.jetbrains.annotations.Nls import org.jetbrains.plugins.gradle.execution.build.output.GradleOutputDispatcherFactory import org.jetbrains.plugins.gradle.util.GradleConstants @@ -43,41 +39,21 @@ import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes private val DEFAULT_SYNC_TIMEOUT: Duration = 10.minutes +private val LOG = Logger.getInstance(TestGradleProjectConfigurationActivityKey::class.java) private object TestGradleProjectConfigurationActivityKey: ActivityKey { override val presentableName: @Nls String get() = "The test Gradle project configuration" } -val LOG = Logger.getInstance(TestGradleProjectConfigurationActivityKey::class.java) + suspend fun awaitGradleOpenProjectConfiguration(openProject: suspend () -> Project): Project { return openProject() - .withProjectAsync { awaitConfiguration(DEFAULT_SYNC_TIMEOUT, it, LOG::debug) } + .withProjectAsync { TestObservation.awaitConfiguration(DEFAULT_SYNC_TIMEOUT, it, LOG::debug) } } suspend fun awaitGradleProjectConfiguration(project: Project, action: suspend () -> R): R { return project.trackActivity(TestGradleProjectConfigurationActivityKey, action) - .also { awaitConfiguration(DEFAULT_SYNC_TIMEOUT, project, LOG::debug) } -} - -suspend fun awaitConfiguration(timeout: Duration, project: Project, messageCallback: ((String) -> Unit)? = null) { - try { - withTimeout(timeout) { - Observation.awaitConfiguration(project, messageCallback) - } - } - catch (e: TimeoutCancellationException) { - val coroutineDump = dumpCoroutines() - val threadDump = ThreadDumper.dumpThreadsToString() - throw AssertionError(""" - |The waiting takes too long - |------- Thread dump begin ------- - |$threadDump - |-------- Thread dump end -------- - |------ Coroutine dump begin ----- - |$coroutineDump - |------- Coroutine dump end ------ - """.trimMargin()) - } + .also { TestObservation.awaitConfiguration(DEFAULT_SYNC_TIMEOUT, project, LOG::debug) } } fun waitForAnyGradleTaskExecution(action: ThrowableComputable): R {