From 9d5ee22397aff00ecd5cfca95733061d6757b61c Mon Sep 17 00:00:00 2001 From: Eugene Morozov Date: Mon, 27 Oct 2025 15:43:36 +0100 Subject: [PATCH] [perf-tests] AT-3378 Check if Project View has already been initialized before waiting for it (cherry picked from commit 625c67011827adcb1fdc71640d477a2b7950e4ad) IJ-CR-180256 GitOrigin-RevId: e5eba674585fbb16aaeef69be4097e2b060807dd --- .../ide/projectView/impl/ProjectViewInitNotifier.kt | 7 ++++++- .../commands/WaitForProjectViewCommand.kt | 10 +++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewInitNotifier.kt b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewInitNotifier.kt index 8ef2ac452765..c0a135fc4e68 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewInitNotifier.kt +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewInitNotifier.kt @@ -12,12 +12,14 @@ import io.opentelemetry.api.trace.Span import io.opentelemetry.api.trace.Tracer import io.opentelemetry.context.Context import org.jetbrains.annotations.ApiStatus.Internal +import org.jetbrains.annotations.TestOnly import java.util.concurrent.atomic.AtomicBoolean private val projectViewInit: Scope = Scope("projectViewInit") @Service(Service.Level.PROJECT) -internal class ProjectViewInitNotifier(private val project: Project) { +@Internal +class ProjectViewInitNotifier(private val project: Project) { private val startedOccurred = AtomicBoolean() private val cachedNodesLoadedOccurred = AtomicBoolean() private val completedOccurred = AtomicBoolean() @@ -45,6 +47,9 @@ internal class ProjectViewInitNotifier(private val project: Project) { project.messageBus.syncPublisher(ProjectViewListener.TOPIC).initCompleted() } + @TestOnly + fun isInitCompleted(): Boolean = completedOccurred.get() + private inner class TracingHelper { private val mainSpan = Ref() private val cachedNodesSpan = Ref() diff --git a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/WaitForProjectViewCommand.kt b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/WaitForProjectViewCommand.kt index 13fe9f4f1934..95f1e8ec4cc2 100644 --- a/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/WaitForProjectViewCommand.kt +++ b/plugins/performanceTesting/core/src/com/jetbrains/performancePlugin/commands/WaitForProjectViewCommand.kt @@ -1,15 +1,17 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.jetbrains.performancePlugin.commands +import com.intellij.ide.projectView.impl.ProjectViewInitNotifier import com.intellij.ide.projectView.impl.ProjectViewListener import com.intellij.openapi.ui.playback.PlaybackContext import com.intellij.openapi.ui.playback.commands.PlaybackCommandCoroutineAdapter import kotlinx.coroutines.sync.Mutex +import org.jetbrains.annotations.TestOnly /** * Wait till a project tree is fully initialized. - * Command should be executed as soon as possible since project view initialization happens very early and the command might hang. */ +@TestOnly class WaitForProjectViewCommand(text: String, line: Int) : PlaybackCommandCoroutineAdapter(text, line) { companion object { @@ -17,6 +19,9 @@ class WaitForProjectViewCommand(text: String, line: Int) : PlaybackCommandCorout } override suspend fun doExecute(context: PlaybackContext) { + val notifier = context.project.getService(ProjectViewInitNotifier::class.java) + if (notifier.isInitCompleted()) return + val connection = context.project.messageBus.connect() val mutex = Mutex(true) connection.subscribe(ProjectViewListener.TOPIC, object : ProjectViewListener { @@ -24,6 +29,9 @@ class WaitForProjectViewCommand(text: String, line: Int) : PlaybackCommandCorout mutex.unlock() } }) + + if (notifier.isInitCompleted()) mutex.unlock() + mutex.lock() connection.disconnect() }