From a5d46b92c7dca97ce1cb41f7d63ff88497cbf7ec Mon Sep 17 00:00:00 2001 From: Nikita Kudrin Date: Wed, 29 Oct 2025 15:25:13 +0200 Subject: [PATCH] [split tests] AT-3386 Start different IDE instance depending on the ide mode: split, monolith GitOrigin-RevId: 896372420c21ed899da488affbfa71f4630bc8ef --- .../junit/ExecuteInMonolithAndSplitMode.kt | 8 ++- .../MonolithAndSplitModeContextProvider.kt | 18 ++--- ...olithAndSplitModeIdeInstanceInitializer.kt | 68 +++++++++++-------- .../testFramework/junit/UltimateTestCases.kt | 22 ++++++ 4 files changed, 74 insertions(+), 42 deletions(-) create mode 100644 tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/UltimateTestCases.kt diff --git a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/ExecuteInMonolithAndSplitMode.kt b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/ExecuteInMonolithAndSplitMode.kt index 8dbcebd00066..2fefa231c522 100644 --- a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/ExecuteInMonolithAndSplitMode.kt +++ b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/ExecuteInMonolithAndSplitMode.kt @@ -1,13 +1,15 @@ package com.intellij.lambda.testFramework.junit import com.intellij.ide.starter.junit5.RemoteDevRun -import com.intellij.remoteDev.tests.modelGenerated.LambdaRdIdeType -import com.intellij.remoteDev.tests.modelGenerated.LambdaRdIdeType.* import com.intellij.testFramework.junit5.impl.TestApplicationExtension import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith import java.lang.annotation.Inherited +enum class IdeRunMode { + MONOLITH, SPLIT +} + /** * Test will be executed in monolith and in split mode. */ @@ -20,4 +22,4 @@ import java.lang.annotation.Inherited MonolithAndSplitModeIdeInstanceInitializer::class, RemoteDevRun::class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) -annotation class ExecuteInMonolithAndSplitMode(vararg val mode: LambdaRdIdeType = [FRONTEND, BACKEND, MONOLITH]) +annotation class ExecuteInMonolithAndSplitMode(vararg val mode: IdeRunMode = [IdeRunMode.MONOLITH, IdeRunMode.SPLIT]) \ No newline at end of file diff --git a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeContextProvider.kt b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeContextProvider.kt index dd6562095c04..df6378027571 100644 --- a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeContextProvider.kt +++ b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeContextProvider.kt @@ -2,7 +2,6 @@ package com.intellij.lambda.testFramework.junit import com.intellij.lambda.testFramework.utils.BackgroundRunWithLambda import com.intellij.openapi.diagnostic.currentClassLogger -import com.intellij.remoteDev.tests.modelGenerated.LambdaRdIdeType import org.junit.jupiter.api.extension.* import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.ArgumentsProvider @@ -16,7 +15,7 @@ import java.util.stream.Stream class MonolithAndSplitModeContextProvider : TestTemplateInvocationContextProvider { override fun supportsTestTemplate(context: ExtensionContext): Boolean = getModesToRun(context).isNotEmpty() - private fun getModesToRun(context: ExtensionContext): List { + private fun getModesToRun(context: ExtensionContext): List { val methodAnnotation = AnnotationUtils.findAnnotation(context.testMethod, ExecuteInMonolithAndSplitMode::class.java) if (methodAnnotation.isPresent) { return methodAnnotation.get().mode.toList() @@ -41,7 +40,7 @@ class MonolithAndSplitModeContextProvider : TestTemplateInvocationContextProvide try { // PARAMETERIZED CASE: Generate tests for each argument in each LambdaRdIdeType provider.provideArguments(context).flatMap { args: Arguments -> - modesToRun.stream().map { mode -> createInvocationContext(mode, args.get()) } + modesToRun.stream().map { mode -> createInvocationContext(mode, args.get(), context) } } } catch (e: Exception) { @@ -51,12 +50,14 @@ class MonolithAndSplitModeContextProvider : TestTemplateInvocationContextProvide if (parametrizedRuns.isPresent) return parametrizedRuns.get() // SIMPLE CASE - test without parameters: Generate one test for each LambdaRdIdeType - return modesToRun.stream().map { mode -> createInvocationContext(mode, emptyArray()) } + return modesToRun.stream().map { mode -> createInvocationContext(mode, emptyArray(), context) } } - private fun createInvocationContext(mode: LambdaRdIdeType, args: Array): TestTemplateInvocationContext { + private fun createInvocationContext(mode: IdeRunMode, args: Array, context: ExtensionContext): TestTemplateInvocationContext { return object : TestTemplateInvocationContext { override fun getDisplayName(invocationIndex: Int): String { + MonolithAndSplitModeIdeInstanceInitializer.startIde(mode, context) + val params = if (args.isNotEmpty()) " with params: " + listOf(*args) else "" return if (params.isNotEmpty()) "[$mode] $params" else "[$mode]" } @@ -67,18 +68,17 @@ class MonolithAndSplitModeContextProvider : TestTemplateInvocationContextProvide val type = paramCtx.parameter.type return type.isAssignableFrom(BackgroundRunWithLambda::class.java) || type.isAssignableFrom(mode::class.java) || - (paramCtx.index > 0 && paramCtx.index - 1 < args.size) + (paramCtx.index > 0 && paramCtx.index - 1 < args.size) } override fun resolveParameter(paramCtx: ParameterContext, extCtx: ExtensionContext): Any { return when { paramCtx.parameter.type.isAssignableFrom(mode::class.java) -> mode paramCtx.parameter.type.isAssignableFrom(BackgroundRunWithLambda::class.java) -> { - // Assuming BackgroundRunWithLambda requires specific instantiation logic - MonolithAndSplitModeIdeInstanceInitializer.ideBackgroundRun + MonolithAndSplitModeIdeInstanceInitializer.startIde(mode, context) } else -> { - // The first parameter is the LambdaRdIdeType, so offset argument index by 1 + // The first parameter is the IdeRunMode, so offset argument index by 1 args[paramCtx.index - 1] } } diff --git a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeIdeInstanceInitializer.kt b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeIdeInstanceInitializer.kt index fe1973551c7a..7e605b31359a 100644 --- a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeIdeInstanceInitializer.kt +++ b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/MonolithAndSplitModeIdeInstanceInitializer.kt @@ -1,49 +1,57 @@ package com.intellij.lambda.testFramework.junit -import com.intellij.ide.starter.ide.IdeProductProvider -import com.intellij.ide.starter.models.TestCase -import com.intellij.ide.starter.project.LocalProjectInfo -import com.intellij.ide.starter.project.TestCaseTemplate +import com.intellij.ide.starter.config.ConfigurationStorage +import com.intellij.ide.starter.config.splitMode import com.intellij.ide.starter.runner.Starter import com.intellij.ide.starter.utils.catchAll import com.intellij.lambda.testFramework.starter.newContextWithLambda import com.intellij.lambda.testFramework.utils.BackgroundRunWithLambda import com.intellij.lambda.testFramework.utils.IdeLambdaStarter import com.intellij.lambda.testFramework.utils.IdeLambdaStarter.runIdeWithLambda -import com.intellij.openapi.application.PathManager import org.junit.jupiter.api.extension.AfterAllCallback -import org.junit.jupiter.api.extension.BeforeAllCallback import org.junit.jupiter.api.extension.ExtensionContext -import java.nio.file.Paths -import kotlin.io.path.createDirectories -class MonolithAndSplitModeIdeInstanceInitializer : BeforeAllCallback, AfterAllCallback { +class MonolithAndSplitModeIdeInstanceInitializer : AfterAllCallback { companion object { lateinit var ideBackgroundRun: BackgroundRunWithLambda - } + private set + lateinit var currentIdeMode: IdeRunMode + private set + + fun startIde(runMode: IdeRunMode, context: ExtensionContext): BackgroundRunWithLambda { + synchronized(this) { + if (this::ideBackgroundRun.isInitialized && currentIdeMode == runMode) { + println("IDE is already running in mode: $runMode. Reusing the current instance of IDE.") + return ideBackgroundRun + } + + stopIde() + currentIdeMode = runMode + ConfigurationStorage.splitMode(currentIdeMode == IdeRunMode.SPLIT) + + println("Starting IDE in mode: $runMode") + + val testContext = Starter.newContextWithLambda(context.testClass.get().simpleName, + UltimateTestCases.JpsEmptyProject, + additionalPluginModule = IdeLambdaStarter.ADDITIONAL_LAMBDA_TEST_PLUGIN) + ideBackgroundRun = testContext.runIdeWithLambda() + + return ideBackgroundRun + } + } + + private fun stopIde() { + synchronized(this) { + if (!this::ideBackgroundRun.isInitialized) return + + println("Stopping IDE that is running in mode: $currentIdeMode") + catchAll { ideBackgroundRun.closeIdeAndWait() } + } + } - override fun beforeAll(context: ExtensionContext) { - val testContext = Starter.newContextWithLambda(context.testClass.get().simpleName, - UltimateTestCases.JpsEmptyProject, - additionalPluginModule = IdeLambdaStarter.ADDITIONAL_LAMBDA_TEST_PLUGIN) - ideBackgroundRun = testContext.runIdeWithLambda() } override fun afterAll(context: ExtensionContext) { - catchAll { ideBackgroundRun.closeIdeAndWait() } + stopIde() } -} - - -object UltimateTestCases : TestCaseTemplate(IdeProductProvider.IU) { - val JpsEmptyProject: TestCase = withProject( - projectInfo = LocalProjectInfo( - projectDir = Paths.get(PathManager.getHomePath(), "out/ide-tests/cache/empty-project").createDirectories() - ) - ) - val JavaTestProject: TestCase = withProject( - projectInfo = LocalProjectInfo( - projectDir = Paths.get(PathManager.getHomePath(), "out/ide-tests/cache/projects/unpacked/java-ui-automation-data").createDirectories() - ) - ) } \ No newline at end of file diff --git a/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/UltimateTestCases.kt b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/UltimateTestCases.kt new file mode 100644 index 000000000000..4393cf548bcd --- /dev/null +++ b/tools/intellij.lambda.testFramework/src/com/intellij/lambda/testFramework/junit/UltimateTestCases.kt @@ -0,0 +1,22 @@ +package com.intellij.lambda.testFramework.junit + +import com.intellij.ide.starter.ide.IdeProductProvider +import com.intellij.ide.starter.models.TestCase +import com.intellij.ide.starter.project.LocalProjectInfo +import com.intellij.ide.starter.project.TestCaseTemplate +import com.intellij.openapi.application.PathManager +import java.nio.file.Paths +import kotlin.io.path.createDirectories + +object UltimateTestCases : TestCaseTemplate(IdeProductProvider.IU) { + val JpsEmptyProject: TestCase = withProject( + projectInfo = LocalProjectInfo( + projectDir = Paths.get(PathManager.getHomePath(), "out/ide-tests/cache/empty-project").createDirectories() + ) + ) + val JavaTestProject: TestCase = withProject( + projectInfo = LocalProjectInfo( + projectDir = Paths.get(PathManager.getHomePath(), "out/ide-tests/cache/projects/unpacked/java-ui-automation-data").createDirectories() + ) + ) +} \ No newline at end of file