Skip to content

Explicitly set the child process working directory if we run the plugin #694 #695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.utbot.framework.plugin.services

import java.nio.file.Path
import java.nio.file.Paths

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<JdkInfo> {
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"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.utbot.framework.plugin.services

interface PluginService<T> {
fun provide(): T
}
Original file line number Diff line number Diff line change
@@ -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<Path> {
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"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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}" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 = """
Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
Expand All @@ -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
)
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -300,7 +300,7 @@ fun main(args: Array<String>) {
tools = listOf(Tool.UtBot)
}

JdkPathService.jdkPathProvider = ContestEstimatorJdkPathProvider(javaHome)
JdkInfoService.jdkInfoProvider = ContestEstimatorJdkInfoProvider(javaHome)
runEstimator(estimatorArgs, methodFilter, projectFilter, processedClassesThreshold, tools)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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
}

This file was deleted.