From 05ac1684e8b04e79b6437b6d36443d52062cca04 Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Tue, 9 Aug 2022 15:32:39 +0300 Subject: [PATCH 1/2] Explicitly setting the child process working dir if we run the plugin Refactor services a bit --- .../utbot/framework/JdkPathDefaultProvider.kt | 12 ------- .../org/utbot/framework/JdkPathProvider.kt | 14 --------- .../org/utbot/framework/JdkPathService.kt | 22 ------------- .../plugin/services/JdkInfoService.kt | 31 +++++++++++++++++++ .../plugin/services/PluginService.kt | 5 +++ .../plugin/services/WorkingDirService.kt | 26 ++++++++++++++++ .../process/ChildProcessRunner.kt | 17 +++++++--- .../generator/UtTestsDialogProcessor.kt | 10 ++++-- ...thProvider.kt => PluginJdkInfoProvider.kt} | 18 +++++------ .../plugin/util/PluginWorkingDirProvider.kt | 19 ++++++++++++ .../org/utbot/contest/ContestEstimator.kt | 4 +-- .../ContestEstimatorJdkInfoProvider.kt | 14 +++++++++ .../ContestEstimatorJdkPathProvider.kt | 14 --------- 13 files changed, 125 insertions(+), 81 deletions(-) delete mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathDefaultProvider.kt delete mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathProvider.kt delete mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathService.kt create mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt create mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/PluginService.kt create mode 100644 utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/WorkingDirService.kt rename utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/{PluginJdkPathProvider.kt => PluginJdkInfoProvider.kt} (66%) create mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginWorkingDirProvider.kt create mode 100644 utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkInfoProvider.kt delete mode 100644 utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkPathProvider.kt diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathDefaultProvider.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathDefaultProvider.kt deleted file mode 100644 index 4262202b34..0000000000 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathDefaultProvider.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.utbot.framework - -import java.nio.file.Path -import java.nio.file.Paths - -open class JdkPathDefaultProvider: JdkPathProvider() { - override val jdkPath: Path - get() = Paths.get(System.getProperty("java.home")) - - override val jdkVersion: String - get() = System.getProperty("java.version") -} diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathProvider.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathProvider.kt deleted file mode 100644 index 96c9e36184..0000000000 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.utbot.framework - -import java.nio.file.Path -import kotlin.reflect.KProperty - -abstract class JdkPathProvider { - operator fun getValue(service: JdkPathService, property: KProperty<*>): Path { - return jdkPath - } - - abstract val jdkPath: Path - - abstract val jdkVersion: String -} diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathService.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathService.kt deleted file mode 100644 index 60c7b071f2..0000000000 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/JdkPathService.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.utbot.framework - -import java.nio.file.Path - -/** - * Singleton to enable abstract access to path to JDK. - * - * Used in [org.utbot.instrumentation.process.ChildProcessRunner]. - * The purpose is to use the same JDK in [org.utbot.instrumentation.ConcreteExecutor] - * and in the test runs. - * This is necessary because the engine can be run from the various starting points, like IDEA plugin, CLI, etc. - */ -object JdkPathService { - var jdkPathProvider: JdkPathProvider = JdkPathDefaultProvider() - - // Kotlin delegates do not support changing in runtime, so use simple getter - val jdkPath: Path - get() = jdkPathProvider.jdkPath - - val jdkVersion: String - get() = jdkPathProvider.jdkVersion -} diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt new file mode 100644 index 0000000000..146e1351b8 --- /dev/null +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt @@ -0,0 +1,31 @@ +package org.utbot.framework.plugin.services + +import java.nio.file.Path +import java.nio.file.Paths + +/** + * Singleton to enable abstract access to path to JDK. + + * and in the test runs. + * This is necessary because the engine can be run from the various starting points, like IDEA plugin, CLI, etc. + */ +data class JdkInfo( + val path: Path, + @Suppress("unused") + val version: String +) + +object JdkInfoService : PluginService { + var jdkInfoProvider: JdkInfoProvider = JdkInfoDefaultProvider() + + override fun provide(): JdkInfo = jdkInfoProvider.info +} + +interface JdkInfoProvider { + val info: JdkInfo +} + +open class JdkInfoDefaultProvider : JdkInfoProvider { + override val info: JdkInfo = + JdkInfo(Paths.get(System.getProperty("java.home")), System.getProperty("java.version")) +} diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/PluginService.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/PluginService.kt new file mode 100644 index 0000000000..2b4796117a --- /dev/null +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/PluginService.kt @@ -0,0 +1,5 @@ +package org.utbot.framework.plugin.services + +interface PluginService { + fun provide(): T +} \ No newline at end of file diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/WorkingDirService.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/WorkingDirService.kt new file mode 100644 index 0000000000..a714fa64b4 --- /dev/null +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/WorkingDirService.kt @@ -0,0 +1,26 @@ +package org.utbot.framework.plugin.services + +import java.nio.file.Path +import java.nio.file.Paths + +/** + * Singleton to enable abstract access to the working directory. + * + * Used in [org.utbot.instrumentation.process.ChildProcessRunner]. + * The purpose is to use the same working directory in [org.utbot.instrumentation.ConcreteExecutor] + * and in the test runs. + */ +object WorkingDirService : PluginService { + var workingDirProvider: WorkingDirProvider = WorkingDirDefaultProvider() + + override fun provide(): Path = workingDirProvider.workingDir +} + +abstract class WorkingDirProvider { + abstract val workingDir: Path +} + +open class WorkingDirDefaultProvider : WorkingDirProvider() { + override val workingDir: Path + get() = Paths.get(System.getProperty("user.dir")) +} \ No newline at end of file diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcessRunner.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcessRunner.kt index 9b46a8d5cf..f0ab31e0b4 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcessRunner.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcessRunner.kt @@ -9,12 +9,12 @@ import org.utbot.common.packageName import org.utbot.common.pid import org.utbot.common.scanForResourcesContaining import org.utbot.common.utBotTempDirectory -import org.utbot.framework.JdkPathService +import org.utbot.framework.plugin.services.JdkInfoService import org.utbot.framework.UtSettings +import org.utbot.framework.plugin.services.WorkingDirService import org.utbot.instrumentation.Settings import org.utbot.instrumentation.agent.DynamicClassTransformer import java.io.File -import java.nio.file.Paths private val logger = KotlinLogging.logger {} private var processSeqN = 0 @@ -27,8 +27,10 @@ class ChildProcessRunner { emptyList() } - listOf(Paths.get(JdkPathService.jdkPath.toString(),"bin", "java").toString()) + - debugCmd + listOf("-javaagent:$jarFile", "-ea", "-jar", "$jarFile") + listOf( + JdkInfoService.provide().path.resolve("bin${File.separatorChar}java").toString(), + "-javaagent:$jarFile", "-ea", "-jar", "$jarFile" + ) + debugCmd } var errorLogFile: File = NULL_FILE @@ -42,7 +44,12 @@ class ChildProcessRunner { errorLogFile = File(UT_BOT_TEMP_DIR, "${hashCode()}-${processSeqN}.log") } - val processBuilder = ProcessBuilder(cmds).redirectError(errorLogFile) + val directory = WorkingDirService.provide().toFile() + + val processBuilder = ProcessBuilder(cmds) + .redirectError(errorLogFile) + .directory(directory) + return processBuilder.start().also { logger.debug { "Process started with PID=${it.pid}" } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt index 4e7bc3407a..74ffc966cd 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt @@ -26,7 +26,7 @@ import com.intellij.util.concurrency.AppExecutorUtil import mu.KotlinLogging import org.jetbrains.kotlin.idea.util.module import org.utbot.engine.util.mockListeners.ForceMockListener -import org.utbot.framework.JdkPathService +import org.utbot.framework.plugin.services.JdkInfoService import org.utbot.framework.UtSettings import org.utbot.framework.plugin.api.TestCaseGenerator import org.utbot.framework.plugin.api.UtMethod @@ -39,7 +39,7 @@ import org.utbot.intellij.plugin.models.GenerateTestsModel import org.utbot.intellij.plugin.ui.GenerateTestsDialogWindow import org.utbot.intellij.plugin.ui.utils.showErrorDialogLater import org.utbot.intellij.plugin.util.IntelliJApiHelper -import org.utbot.intellij.plugin.util.PluginJdkPathProvider +import org.utbot.intellij.plugin.util.PluginJdkInfoProvider import org.utbot.intellij.plugin.util.signature import org.utbot.summary.summarize import java.io.File @@ -50,9 +50,11 @@ import java.util.concurrent.TimeUnit import org.utbot.common.filterWhen import org.utbot.engine.util.mockListeners.ForceStaticMockListener import org.utbot.framework.plugin.api.testFlow +import org.utbot.framework.plugin.services.WorkingDirService import org.utbot.intellij.plugin.settings.Settings import org.utbot.intellij.plugin.ui.utils.isGradle import org.utbot.intellij.plugin.ui.utils.suitableTestSourceRoots +import org.utbot.intellij.plugin.util.PluginWorkingDirProvider import org.utbot.intellij.plugin.util.isAbstract import org.utbot.intellij.plugin.ui.utils.testModules import kotlin.reflect.KClass @@ -80,7 +82,9 @@ object UtTestsDialogProcessor { val srcModule = findSrcModule(srcClasses) val testModules = srcModule.testModules(project) - JdkPathService.jdkPathProvider = PluginJdkPathProvider(project) + JdkInfoService.jdkInfoProvider = PluginJdkInfoProvider(project) + // we want to start the child process in the same directory as the test runner + WorkingDirService.workingDirProvider = PluginWorkingDirProvider(project) if (project.isGradle() && testModules.flatMap { it.suitableTestSourceRoots() }.isEmpty()) { val errorMessage = """ diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkPathProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkInfoProvider.kt similarity index 66% rename from utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkPathProvider.kt rename to utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkInfoProvider.kt index ba3d7ee80c..fc116940a2 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkPathProvider.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginJdkInfoProvider.kt @@ -1,16 +1,16 @@ package org.utbot.intellij.plugin.util import org.utbot.common.PathUtil.toPath -import org.utbot.framework.JdkPathDefaultProvider import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.roots.ProjectRootManager -import java.nio.file.Path +import org.utbot.framework.plugin.services.JdkInfo +import org.utbot.framework.plugin.services.JdkInfoDefaultProvider -class PluginJdkPathProvider( +class PluginJdkInfoProvider( private val project: Project -) : JdkPathDefaultProvider() { +) : JdkInfoDefaultProvider() { private val sdk: Sdk? get() { @@ -28,9 +28,9 @@ class PluginJdkPathProvider( return ProjectRootManager.getInstance(project).projectSdk } - override val jdkPath: Path - get() = sdk?.let { it.homePath?.toPath() } ?: super.jdkPath // Return default JDK in case of failure - - override val jdkVersion: String - get() = sdk?.versionString ?: super.jdkVersion // Return default JDK in case of failure + override val info: JdkInfo + get() = JdkInfo( + sdk?.homePath?.toPath() ?: super.info.path, // Return default JDK in case of failure + sdk?.versionString ?: super.info.version // Return default JDK in case of failure + ) } \ No newline at end of file diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginWorkingDirProvider.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginWorkingDirProvider.kt new file mode 100644 index 0000000000..cb09d2065d --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/PluginWorkingDirProvider.kt @@ -0,0 +1,19 @@ +package org.utbot.intellij.plugin.util + +import com.intellij.openapi.project.Project +import org.utbot.common.PathUtil.toPath +import org.utbot.framework.plugin.services.WorkingDirDefaultProvider +import java.nio.file.Path + +class PluginWorkingDirProvider( + project: Project, +) : WorkingDirDefaultProvider() { + + /** + * We believe that in most cases the test runner working dir is the project root, otherwise we need to parse test + * configuration, but it's not easy. + */ + override val workingDir: Path = + project.basePath?.toPath() + ?: super.workingDir +} \ No newline at end of file diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt index 94e67f0dce..7a77b05ec2 100644 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimator.kt @@ -34,7 +34,7 @@ import java.util.zip.ZipInputStream import kotlin.concurrent.thread import kotlin.math.min import kotlin.system.exitProcess -import org.utbot.framework.JdkPathService +import org.utbot.framework.plugin.services.JdkInfoService import org.utbot.predictors.StateRewardPredictorFactoryImpl import org.utbot.framework.PathSelectorType import org.utbot.framework.UtSettings @@ -300,7 +300,7 @@ fun main(args: Array) { tools = listOf(Tool.UtBot) } - JdkPathService.jdkPathProvider = ContestEstimatorJdkPathProvider(javaHome) + JdkInfoService.jdkInfoProvider = ContestEstimatorJdkInfoProvider(javaHome) runEstimator(estimatorArgs, methodFilter, projectFilter, processedClassesThreshold, tools) } diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkInfoProvider.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkInfoProvider.kt new file mode 100644 index 0000000000..4af7ede55b --- /dev/null +++ b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkInfoProvider.kt @@ -0,0 +1,14 @@ +package org.utbot.contest + +import org.utbot.common.PathUtil.toPath +import org.utbot.framework.plugin.services.JdkInfo +import org.utbot.framework.plugin.services.JdkInfoDefaultProvider + +/** + * This class is used to provide a path to jdk and its version in [ContestEstimator] + * into the child process for concrete execution. + */ +class ContestEstimatorJdkInfoProvider(private val path: String) : JdkInfoDefaultProvider() { + override val info: JdkInfo + get() = JdkInfo(path.toPath(), super.info.version) // TODO: retrieve the correct version +} \ No newline at end of file diff --git a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkPathProvider.kt b/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkPathProvider.kt deleted file mode 100644 index 26f74eb32e..0000000000 --- a/utbot-junit-contest/src/main/kotlin/org/utbot/contest/ContestEstimatorJdkPathProvider.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.utbot.contest - -import org.utbot.common.PathUtil.toPath -import org.utbot.framework.JdkPathDefaultProvider -import java.nio.file.Path - -/** - * This class is used to provide jdkPath set in [ContestEstimator] - * into the child process for concrete execution. - */ -class ContestEstimatorJdkPathProvider(private val path: String) : JdkPathDefaultProvider() { - override val jdkPath: Path - get() = path.toPath() -} \ No newline at end of file From d460e30b28a050bd5f35a55c2d3a2c45e8d4b2eb Mon Sep 17 00:00:00 2001 From: Sergey Pospelov Date: Thu, 11 Aug 2022 12:00:07 +0300 Subject: [PATCH 2/2] Fix comment --- .../framework/plugin/services/JdkInfoService.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt index 146e1351b8..7aef4469b9 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/services/JdkInfoService.kt @@ -3,18 +3,19 @@ package org.utbot.framework.plugin.services import java.nio.file.Path import java.nio.file.Paths -/** - * Singleton to enable abstract access to path to JDK. - - * and in the test runs. - * This is necessary because the engine can be run from the various starting points, like IDEA plugin, CLI, etc. - */ data class JdkInfo( val path: Path, @Suppress("unused") val version: String ) +/** + * Singleton to enable abstract access to path to JDK. + + * Used in [org.utbot.instrumentation.process.ChildProcessRunner]. + * The purpose is to use the same JDK in [org.utbot.instrumentation.ConcreteExecutor] and in the test runs. + * This is necessary because the engine can be run from the various starting points, like IDEA plugin, CLI, etc. + */ object JdkInfoService : PluginService { var jdkInfoProvider: JdkInfoProvider = JdkInfoDefaultProvider()