Skip to content

Commit

Permalink
Resolve issues with SpringAnalyzerProcess
Browse files Browse the repository at this point in the history
  • Loading branch information
IlyaMuravjov committed Apr 5, 2023
1 parent 8ffdeb4 commit 0a85c54
Show file tree
Hide file tree
Showing 17 changed files with 118 additions and 109 deletions.
21 changes: 0 additions & 21 deletions utbot-core/src/main/kotlin/org/utbot/common/StandardStreamUtil.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@ import java.io.File
import java.nio.file.Path
import kotlin.io.path.pathString

private val javaExecutablePathString: Path
get() = JdkInfoService.jdkInfoProvider.info.path.resolve("bin${File.separatorChar}${osSpecificJavaExecutable()}")
object CommonProcessArgs {
private val javaExecutablePathString: Path
get() = JdkInfoService.provide().path.resolve("bin${File.separatorChar}${osSpecificJavaExecutable()}")

fun obtainCommonProcessCommandLineArgs(
debugPort: Int,
runWithDebug: Boolean,
suspendExecutionInDebugMode: Boolean,
): List<String> = buildList {
val suspendValue = if (suspendExecutionInDebugMode) "y" else "n"
val debugArgument = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue},quiet=y,address=$debugPort"
.takeIf { runWithDebug }
fun obtainCommonProcessCommandLineArgs(
debugPort: Int,
runWithDebug: Boolean,
suspendExecutionInDebugMode: Boolean,
): List<String> = buildList {
val suspendValue = if (suspendExecutionInDebugMode) "y" else "n"
val debugArgument = "-agentlib:jdwp=transport=dt_socket,server=n,suspend=${suspendValue},quiet=y,address=$debugPort"
.takeIf { runWithDebug }

add(javaExecutablePathString.pathString)
val javaVersionSpecificArgs = OpenModulesContainer.javaVersionSpecificArguments
if (javaVersionSpecificArgs.isNotEmpty()) {
addAll(javaVersionSpecificArgs)
add(javaExecutablePathString.pathString)
val javaVersionSpecificArgs = OpenModulesContainer.javaVersionSpecificArguments
if (javaVersionSpecificArgs.isNotEmpty()) {
addAll(javaVersionSpecificArgs)
}
debugArgument?.let { add(it) }
}
debugArgument?.let { add(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import org.utbot.rd.ProcessWithRdServer
import org.utbot.rd.exceptions.InstantProcessDeathException
import org.utbot.rd.generated.LoggerModel
import org.utbot.rd.generated.loggerModel
import org.utbot.rd.generated.synchronizationModel
import org.utbot.rd.loggers.UtRdKLogger
import org.utbot.rd.loggers.setupRdLogger
import org.utbot.rd.loggers.setup
import org.utbot.rd.onSchedulerBlocking
import org.utbot.rd.rdPortArgument
import org.utbot.rd.startBlocking
Expand All @@ -28,6 +27,8 @@ class SpringAnalyzerProcessInstantDeathException :
InstantProcessDeathException(UtSettings.springAnalyzerProcessDebugPort, UtSettings.runSpringAnalyzerProcessWithDebug)

private const val SPRING_ANALYZER_JAR_FILENAME = "utbot-spring-analyzer-shadow.jar"
private const val SPRING_ANALYZER_JAR_PATH = "lib/$SPRING_ANALYZER_JAR_FILENAME"
private const val UNKNOWN_MODIFICATION_TIME = 0L
private val logger = KotlinLogging.logger {}
private val rdLogger = UtRdKLogger(logger, "")

Expand All @@ -36,16 +37,34 @@ class SpringAnalyzerProcess private constructor(
) : ProcessWithRdServer by rdProcess {

companion object {
private fun obtainProcessSpecificCommandLineArgs(port: Int): List<String> {
val jarFile =
Files.createDirectories(utBotTempDirectory.toFile().resolve("spring-analyzer").toPath())
.toFile().resolve(SPRING_ANALYZER_JAR_FILENAME)
FileUtils.copyURLToFile(
this::class.java.classLoader.getResource("lib/$SPRING_ANALYZER_JAR_FILENAME"),
jarFile
)
return listOf(
"-Dorg.apache.commons.logging.LogFactory=org.utbot.rd.loggers.RDApacheCommonsLogFactory",
private val jarFile by lazy {
Files.createDirectories(utBotTempDirectory.toFile().resolve("spring-analyzer").toPath())
.toFile().resolve(SPRING_ANALYZER_JAR_FILENAME).also { jarFile ->
val resource = this::class.java.classLoader.getResource(SPRING_ANALYZER_JAR_PATH)
?: error("Unable to find \"$SPRING_ANALYZER_JAR_PATH\" in resources, make sure it's on the classpath")
val resourceConnection = resource.openConnection()
val lastResourceModification = try {
resourceConnection.lastModified
} finally {
resourceConnection.getInputStream().close()
}
if (
!jarFile.exists() ||
jarFile.lastModified() == UNKNOWN_MODIFICATION_TIME ||
lastResourceModification == UNKNOWN_MODIFICATION_TIME ||
jarFile.lastModified() < lastResourceModification
)
FileUtils.copyURLToFile(resource, jarFile)
}
}

private fun obtainSpringAnalyzerProcessCommandLine(port: Int): List<String> {
return CommonProcessArgs.obtainCommonProcessCommandLineArgs(
debugPort = UtSettings.springAnalyzerProcessDebugPort,
runWithDebug = UtSettings.runSpringAnalyzerProcessWithDebug,
suspendExecutionInDebugMode = UtSettings.suspendSpringAnalyzerProcessExecutionInDebugMode,
) + listOf(
"-Dorg.apache.commons.logging.LogFactory=org.utbot.spring.loggers.RDApacheCommonsLogFactory",
"-jar",
jarFile.path,
rdPortArgument(port)
Expand All @@ -56,11 +75,7 @@ class SpringAnalyzerProcess private constructor(

suspend operator fun invoke(): SpringAnalyzerProcess = LifetimeDefinition().terminateOnException { lifetime ->
val rdProcess = startUtProcessWithRdServer(lifetime) { port ->
val cmd = obtainCommonProcessCommandLineArgs(
debugPort = UtSettings.springAnalyzerProcessDebugPort,
runWithDebug = UtSettings.runSpringAnalyzerProcessWithDebug,
suspendExecutionInDebugMode = UtSettings.suspendSpringAnalyzerProcessExecutionInDebugMode,
) + obtainProcessSpecificCommandLineArgs(port)
val cmd = obtainSpringAnalyzerProcessCommandLine(port)
val process = ProcessBuilder(cmd)
.directory(Files.createTempDirectory(utBotTempDirectory, "spring-analyzer").toFile())
.start()
Expand All @@ -73,20 +88,14 @@ class SpringAnalyzerProcess private constructor(
}
rdProcess.awaitProcessReady()
val proc = SpringAnalyzerProcess(rdProcess)
setupRdLogger(rdProcess, proc.loggerModel, rdLogger)
proc.loggerModel.setup(rdLogger, proc.lifetime)
return proc
}
}

private val springAnalyzerModel: SpringAnalyzerProcessModel = onSchedulerBlocking { protocol.springAnalyzerProcessModel }
private val loggerModel: LoggerModel = onSchedulerBlocking { protocol.loggerModel }

init {
lifetime.onTermination {
protocol.synchronizationModel.stopProcess.fire(Unit)
}
}

fun getBeanQualifiedNames(
classpath: List<String>,
configuration: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import org.utbot.rd.RdSettingsContainerFactory
import org.utbot.rd.findRdPort
import org.utbot.rd.generated.loggerModel
import org.utbot.rd.generated.settingsModel
import org.utbot.rd.generated.synchronizationModel
import org.utbot.rd.loggers.UtRdRemoteLoggerFactory
import org.utbot.rd.StandardStreamUtil
import java.io.File
import java.net.URLClassLoader
import java.security.AllPermission
Expand Down Expand Up @@ -83,7 +83,7 @@ object InstrumentedProcessMain
*/
fun main(args: Array<String>) = runBlocking {
// We don't want user code to litter the standard output, so we redirect it.
silentlyCloseStandardStreams()
StandardStreamUtil.silentlyCloseStandardStreams()

if (!args.contains(DISABLE_SANDBOX_OPTION)) {
permissions {
Expand All @@ -97,7 +97,7 @@ fun main(args: Array<String>) = runBlocking {

try {
ClientProtocolBuilder().withProtocolTimeout(messageFromMainTimeout).start(port) {
synchronizationModel.initRemoteLogging.adviseOnce(lifetime) {
loggerModel.initRemoteLogging.adviseOnce(lifetime) {
Logger.set(Lifetime.Eternal, UtRdRemoteLoggerFactory(loggerModel))
this.protocol.scheduler.queue { warmupMockito() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.utbot.common.scanForResourcesContaining
import org.utbot.common.utBotTempDirectory
import org.utbot.framework.UtSettings
import org.utbot.framework.plugin.services.WorkingDirService
import org.utbot.framework.process.obtainCommonProcessCommandLineArgs
import org.utbot.framework.process.CommonProcessArgs
import org.utbot.instrumentation.agent.DynamicClassTransformer
import org.utbot.rd.rdPortArgument
import java.io.File
Expand All @@ -15,7 +15,7 @@ private val logger = KotlinLogging.logger {}

class InstrumentedProcessRunner {
private val cmds: List<String> by lazy {
obtainCommonProcessCommandLineArgs(
CommonProcessArgs.obtainCommonProcessCommandLineArgs(
debugPort = UtSettings.instrumentedProcessDebugPort,
runWithDebug = UtSettings.runInstrumentedProcessWithDebug,
suspendExecutionInDebugMode = UtSettings.suspendInstrumentedProcessExecutionInDebugMode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import org.utbot.rd.ProcessWithRdServer
import org.utbot.rd.exceptions.InstantProcessDeathException
import org.utbot.rd.generated.LoggerModel
import org.utbot.rd.generated.loggerModel
import org.utbot.rd.generated.synchronizationModel
import org.utbot.rd.loggers.UtRdKLogger
import org.utbot.rd.loggers.UtRdRemoteLogger
import org.utbot.rd.loggers.setupRdLogger
import org.utbot.rd.loggers.setup
import org.utbot.rd.onSchedulerBlocking
import org.utbot.rd.startUtProcessWithRdServer
import org.utbot.rd.terminateOnException
Expand Down Expand Up @@ -64,7 +62,7 @@ class InstrumentedProcess private constructor(
logger.trace("rd process started")

val proc = InstrumentedProcess(classLoader, rdProcess)
setupRdLogger(rdProcess, proc.loggerModel, rdLogger)
proc.loggerModel.setup(rdLogger, proc.lifetime)

proc.lifetime.onTermination {
logger.trace { "process is terminating" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import org.utbot.framework.codegen.tree.ututils.UtilClassKind
import org.utbot.framework.plugin.api.*
import org.utbot.framework.plugin.services.JdkInfo
import org.utbot.framework.plugin.services.WorkingDirService
import org.utbot.framework.process.CommonProcessArgs
import org.utbot.framework.process.generated.*
import org.utbot.framework.process.generated.MethodDescription
import org.utbot.framework.process.obtainCommonProcessCommandLineArgs
import org.utbot.framework.util.Conflict
import org.utbot.framework.util.ConflictTriggers
import org.utbot.instrumentation.util.KryoHelper
Expand Down Expand Up @@ -102,25 +102,26 @@ class EngineProcess private constructor(val project: Project, private val classN

private const val startFileName = "org.utbot.framework.process.EngineProcessMainKt"

private fun obtainProcessSpecificCommandLineArgs(port: Int) = listOf(
"-ea",
log4j2ConfigSwitch,
"-cp",
pluginClasspath,
startFileName,
rdPortArgument(port)
)
private fun obtainEngineProcessCommandLine(port: Int): List<String> =
CommonProcessArgs.obtainCommonProcessCommandLineArgs(
debugPort = UtSettings.engineProcessDebugPort,
runWithDebug = UtSettings.runEngineProcessWithDebug,
suspendExecutionInDebugMode = UtSettings.suspendEngineProcessExecutionInDebugMode,
) + listOf(
"-ea",
log4j2ConfigSwitch,
"-cp",
pluginClasspath,
startFileName,
rdPortArgument(port)
)

fun createBlocking(project: Project, classNameToPath: Map<String, String?>): EngineProcess = runBlocking { EngineProcess(project, classNameToPath) }

suspend operator fun invoke(project: Project, classNameToPath: Map<String, String?>): EngineProcess =
LifetimeDefinition().terminateOnException { lifetime ->
val rdProcess = startUtProcessWithRdServer(lifetime) { port ->
val cmd = obtainCommonProcessCommandLineArgs(
debugPort = UtSettings.engineProcessDebugPort,
runWithDebug = UtSettings.runEngineProcessWithDebug,
suspendExecutionInDebugMode = UtSettings.suspendEngineProcessExecutionInDebugMode,
) + obtainProcessSpecificCommandLineArgs(port)
val cmd = obtainEngineProcessCommandLine(port)
val directory = WorkingDirService.provide().toFile()
val builder = ProcessBuilder(cmd).directory(directory)
val process = builder.start()
Expand Down
1 change: 0 additions & 1 deletion utbot-rd/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ dependencies {
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: rdVersion

implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlinLoggingVersion
implementation group: 'commons-logging', name: 'commons-logging', version: commonsLoggingVersion

processWithRdServerMockImplementation project(':utbot-rd')

Expand Down
24 changes: 24 additions & 0 deletions utbot-rd/src/main/kotlin/org/utbot/rd/StandardStreamUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.utbot.rd

import org.utbot.common.silent
import java.io.OutputStream
import java.io.PrintStream

object StandardStreamUtil {
fun silentlyCloseStandardStreams() {
// we should change out/err streams as not to spend time on user output
// and also because rd default logging system writes some initial values to stdout, polluting it as well
val tmpStream = PrintStream(object : OutputStream() {
override fun write(b: Int) {}
})
val prevOut = System.out
val prevError = System.err
System.setOut(tmpStream)
System.setErr(tmpStream)
// stdin/stderr should be closed as not to leave hanging descriptors
// and we cannot log any exceptions here as rd remote logging is still not configured
// so we pass any exceptions
silent { prevOut.close() }
silent { prevError.close() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import kotlin.jvm.JvmStatic
* #### Generated from [LoggerModel.kt:8]
*/
class LoggerModel private constructor(
private val _initRemoteLogging: RdSignal<Unit>,
private val _log: RdSignal<LogArguments>,
private val _getCategoryMinimalLogLevel: RdCall<String, Int>
) : RdExtBase() {
Expand Down Expand Up @@ -47,13 +48,14 @@ class LoggerModel private constructor(
}


const val serializationHash = -6259198217478203203L
const val serializationHash = 1686273842005935878L

}
override val serializersOwner: ISerializersOwner get() = LoggerModel
override val serializationHash: Long get() = LoggerModel.serializationHash

//fields
val initRemoteLogging: IAsyncSignal<Unit> get() = _initRemoteLogging
val log: IAsyncSignal<LogArguments> get() = _log

/**
Expand All @@ -64,18 +66,21 @@ class LoggerModel private constructor(
//methods
//initializer
init {
_initRemoteLogging.async = true
_log.async = true
_getCategoryMinimalLogLevel.async = true
}

init {
bindableChildren.add("initRemoteLogging" to _initRemoteLogging)
bindableChildren.add("log" to _log)
bindableChildren.add("getCategoryMinimalLogLevel" to _getCategoryMinimalLogLevel)
}

//secondary constructor
private constructor(
) : this(
RdSignal<Unit>(FrameworkMarshallers.Void),
RdSignal<LogArguments>(LogArguments),
RdCall<String, Int>(FrameworkMarshallers.String, FrameworkMarshallers.Int)
)
Expand All @@ -86,6 +91,7 @@ class LoggerModel private constructor(
override fun print(printer: PrettyPrinter) {
printer.println("LoggerModel (")
printer.indent {
print("initRemoteLogging = "); _initRemoteLogging.print(printer); println()
print("log = "); _log.print(printer); println()
print("getCategoryMinimalLogLevel = "); _getCategoryMinimalLogLevel.print(printer); println()
}
Expand All @@ -94,6 +100,7 @@ class LoggerModel private constructor(
//deepClone
override fun deepClone(): LoggerModel {
return LoggerModel(
_initRemoteLogging.deepClonePolymorphic(),
_log.deepClonePolymorphic(),
_getCategoryMinimalLogLevel.deepClonePolymorphic()
)
Expand Down
Loading

0 comments on commit 0a85c54

Please sign in to comment.