From 820456993293eba7a9ff485a45a0cf0becc2186e Mon Sep 17 00:00:00 2001 From: Anastasia Katsman Date: Mon, 31 Jul 2023 16:55:00 +0200 Subject: [PATCH] [rdct-tests]: allow running from background GitOrigin-RevId: dee7a5efa21ed8ffef92f4483007fac2d67302cf --- .../tests/impl/DistributedTestHost.kt | 82 +++++++++++-------- .../DistributedTestModel.Generated.kt | 12 ++- .../modelSources/DistributedTestModel.kt | 1 + 3 files changed, 60 insertions(+), 35 deletions(-) diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt index 1900900806b6..1e02e94ec331 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt @@ -30,6 +30,7 @@ import com.jetbrains.rd.util.lifetime.EternalLifetime import com.jetbrains.rd.util.lifetime.Lifetime import com.jetbrains.rd.util.measureTimeMillis import com.jetbrains.rd.util.reactive.viewNotNull +import com.jetbrains.rd.util.threading.SynchronousScheduler import org.jetbrains.annotations.ApiStatus import java.awt.Component import java.awt.image.BufferedImage @@ -128,65 +129,80 @@ open class DistributedTestHost { testClassObject.performInit(testMethod) testMethod.invoke(testClassObject) - // Advice for processing events - session.runNextAction.set { _, _ -> - var actionTitle: String? = null + fun runAction(agentAction: AgentAction, expectIsDispatchThread: Boolean): RdTask { + val actionTitle = agentAction.title try { assert(ClientId.current.isLocal) { "ClientId '${ClientId.current}' should be local when test method starts" } + assert(application.isDispatchThread == expectIsDispatchThread) { + "Expected to be started on EDT: $expectIsDispatchThread, actual: ${Thread.currentThread()}" + } - val action = queue.remove() - actionTitle = action.title + if (expectIsDispatchThread) { + logger.info("'$actionTitle': preparing to start action") - - logger.info("'$actionTitle': preparing to start action") - - val isNotRdHost = !(session.agentInfo.productTypeType == RdProductType.REMOTE_DEVELOPMENT && session.agentInfo.agentType == RdAgentType.HOST) - if (!application.isHeadlessEnvironment && isNotRdHost) { - IdeEventQueue.getInstance().flushQueue() - requestFocus(actionTitle) + val isNotRdHost = !(session.agentInfo.productTypeType == RdProductType.REMOTE_DEVELOPMENT && session.agentInfo.agentType == RdAgentType.HOST) + if (!application.isHeadlessEnvironment && isNotRdHost) { + IdeEventQueue.getInstance().flushQueue() + requestFocus(actionTitle) + } } showNotification("${session.agentInfo.id}: $actionTitle") - // Flush all events to process pending protocol events and other things - // before actual test method execution - IdeEventQueue.getInstance().flushQueue() + if (expectIsDispatchThread) { + // Flush all events to process pending protocol events and other things + // before actual test method execution + IdeEventQueue.getInstance().flushQueue() + } - // Execute test method - lateinit var result: RdTask - val context = when (session.agentInfo.agentType) { + val agentContext = when (session.agentInfo.agentType) { RdAgentType.HOST -> HostAgentContextImpl(session.agentInfo, application, projectOrNull, protocol) RdAgentType.CLIENT -> ClientAgentContextImpl(session.agentInfo, application, projectOrNull, protocol) RdAgentType.GATEWAY -> GatewayAgentContextImpl(session.agentInfo, application, projectOrNull, protocol) } + + // Execute test method + lateinit var result: RdTask logger.info("'$actionTitle': starting action") val elapsedAction = measureTimeMillis { - result = action.action.invoke(context) + result = agentAction.action.invoke(agentContext) } logger.info("'$actionTitle': completed action in ${elapsedAction}ms") - projectOrNull?.let { - // Sync state across all IDE agents to maintain proper order in protocol events - logger.info("'$actionTitle': Sync protocol events after execution...") - val elapsedSync = measureTimeMillis { - DistributedTestBridge.getInstance(it).syncProtocolEvents() - IdeEventQueue.getInstance().flushQueue() + if (expectIsDispatchThread) { + projectOrNull?.let { + // Sync state across all IDE agents to maintain proper order in protocol events + logger.info("'$actionTitle': Sync protocol events after execution...") + val elapsedSync = measureTimeMillis { + DistributedTestBridge.getInstance(it).syncProtocolEvents() + IdeEventQueue.getInstance().flushQueue() + } + logger.info("'$actionTitle': Protocol state sync completed in ${elapsedSync}ms") } - logger.info("'$actionTitle': Protocol state sync completed in ${elapsedSync}ms") } // Assert state assertLoggerFactory() - return@set result + return result } catch (ex: Throwable) { - val msg = "${session.agentInfo.id}: ${actionTitle?.let { "'$it' " }.orEmpty()}hasn't finished successfully" + val msg = "${session.agentInfo.id}: ${actionTitle.let { "'$it' " }.orEmpty()}hasn't finished successfully" logger.warn(msg, ex) if (!application.isHeadlessEnvironment) - actionTitle?.let { makeScreenshot("${it}_$screenshotOnFailureFileName") } - return@set RdTask.faulted(AssertionError(msg, ex)) + makeScreenshot("${actionTitle}_$screenshotOnFailureFileName") + return RdTask.faulted(AssertionError(msg, ex)) } } + + // Advice for processing events + session.runNextAction.set { _, _ -> + runAction(queue.remove(), true) + } + + // Special handler to be used in + session.runNextActionBackground.set(SynchronousScheduler, SynchronousScheduler) { _, _ -> + runAction(queue.remove(), false) + } } session.isResponding.set { _, _ -> @@ -238,9 +254,9 @@ open class DistributedTestHost { // Initialize loggers DebugLogManager.getInstance().applyCategories( - session.traceCategories.map { DebugLogManager.Category(it, DebugLogManager.DebugLogLevel.TRACE)} + - session.debugCategories.map { DebugLogManager.Category(it, DebugLogManager.DebugLogLevel.DEBUG) } - ) + session.traceCategories.map { DebugLogManager.Category(it, DebugLogManager.DebugLogLevel.TRACE) } + + session.debugCategories.map { DebugLogManager.Category(it, DebugLogManager.DebugLogLevel.DEBUG) } + ) logger.info("Test session ready!") session.ready.value = true } diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt index 0e510a67f774..76a7d7c885ad 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt @@ -54,7 +54,7 @@ class DistributedTestModel private constructor( private val __RdTestSessionNullableSerializer = RdTestSession.nullable() - const val serializationHash = -4063022036171224345L + const val serializationHash = -195273050868380088L } override val serializersOwner: ISerializersOwner get() = DistributedTestModel @@ -218,6 +218,7 @@ class RdTestSession private constructor( private val _closeProject: RdCall, private val _closeProjectIfOpened: RdCall, private val _runNextAction: RdCall, + private val _runNextActionBackground: RdCall, private val _makeScreenshot: RdCall, private val _isResponding: RdCall ) : RdBindableBase() { @@ -240,9 +241,10 @@ class RdTestSession private constructor( val _closeProject = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) val _closeProjectIfOpened = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) val _runNextAction = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, __StringNullableSerializer) + val _runNextActionBackground = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, __StringNullableSerializer) val _makeScreenshot = RdCall.read(ctx, buffer, FrameworkMarshallers.String, FrameworkMarshallers.Bool) val _isResponding = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) - return RdTestSession(agentInfo, testClassName, testMethodName, traceCategories, debugCategories, _ready, _sendException, _shutdown, _closeProject, _closeProjectIfOpened, _runNextAction, _makeScreenshot, _isResponding).withId(_id) + return RdTestSession(agentInfo, testClassName, testMethodName, traceCategories, debugCategories, _ready, _sendException, _shutdown, _closeProject, _closeProjectIfOpened, _runNextAction, _runNextActionBackground, _makeScreenshot, _isResponding).withId(_id) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: RdTestSession) { @@ -258,6 +260,7 @@ class RdTestSession private constructor( RdCall.write(ctx, buffer, value._closeProject) RdCall.write(ctx, buffer, value._closeProjectIfOpened) RdCall.write(ctx, buffer, value._runNextAction) + RdCall.write(ctx, buffer, value._runNextActionBackground) RdCall.write(ctx, buffer, value._makeScreenshot) RdCall.write(ctx, buffer, value._isResponding) } @@ -273,6 +276,7 @@ class RdTestSession private constructor( val closeProject: RdCall get() = _closeProject val closeProjectIfOpened: RdCall get() = _closeProjectIfOpened val runNextAction: RdCall get() = _runNextAction + val runNextActionBackground: RdCall get() = _runNextActionBackground val makeScreenshot: RdCall get() = _makeScreenshot val isResponding: RdCall get() = _isResponding //methods @@ -292,6 +296,7 @@ class RdTestSession private constructor( bindableChildren.add("closeProject" to _closeProject) bindableChildren.add("closeProjectIfOpened" to _closeProjectIfOpened) bindableChildren.add("runNextAction" to _runNextAction) + bindableChildren.add("runNextActionBackground" to _runNextActionBackground) bindableChildren.add("makeScreenshot" to _makeScreenshot) bindableChildren.add("isResponding" to _isResponding) } @@ -315,6 +320,7 @@ class RdTestSession private constructor( RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, __StringNullableSerializer), + RdCall(FrameworkMarshallers.Void, __StringNullableSerializer), RdCall(FrameworkMarshallers.String, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool) ) @@ -336,6 +342,7 @@ class RdTestSession private constructor( print("closeProject = "); _closeProject.print(printer); println() print("closeProjectIfOpened = "); _closeProjectIfOpened.print(printer); println() print("runNextAction = "); _runNextAction.print(printer); println() + print("runNextActionBackground = "); _runNextActionBackground.print(printer); println() print("makeScreenshot = "); _makeScreenshot.print(printer); println() print("isResponding = "); _isResponding.print(printer); println() } @@ -355,6 +362,7 @@ class RdTestSession private constructor( _closeProject.deepClonePolymorphic(), _closeProjectIfOpened.deepClonePolymorphic(), _runNextAction.deepClonePolymorphic(), + _runNextActionBackground.deepClonePolymorphic(), _makeScreenshot.deepClonePolymorphic(), _isResponding.deepClonePolymorphic() ) diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt index 799d58a8aaa8..967097b65bfe 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt @@ -62,6 +62,7 @@ object DistributedTestModel : Ext(TestRoot) { call("closeProject", void, bool) call("closeProjectIfOpened", void, bool) call("runNextAction", void, string.nullable) + call("runNextActionBackground", void, string.nullable) call("makeScreenshot", string, bool) call("isResponding", void, bool) }