Creating a test simulating idea-jps-daemon processes, that should now fail on windows, some refactorings in the daemon client to simplify test writing
This commit is contained in:
@@ -25,6 +25,10 @@ import org.jetbrains.kotlin.rmi.kotlinr.KotlinCompilerClient
|
||||
import org.jetbrains.kotlin.test.JetTestUtils
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
val TIMEOUT_DAEMON_RUNNER_EXIT_MS = 10000L
|
||||
|
||||
public class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
@@ -32,6 +36,8 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
val compilerClassPath = listOf(
|
||||
File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar"))
|
||||
val daemonClientClassPath = listOf( File(KotlinIntegrationTestBase.getCompilerLib(), "kotlinr.jar"),
|
||||
File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler.jar"))
|
||||
val compilerId by lazy(LazyThreadSafetyMode.NONE) { CompilerId.makeCompilerId(compilerClassPath) }
|
||||
|
||||
private fun compileOnDaemon(compilerId: CompilerId, daemonJVMOptions: DaemonJVMOptions, daemonOptions: DaemonOptions, vararg args: String): CompilerResults {
|
||||
@@ -178,6 +184,53 @@ public class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
logFile2.assertLogContainsSequence("Shutdown complete")
|
||||
logFile2.delete()
|
||||
}
|
||||
|
||||
|
||||
/** Testing that running daemon in the child process doesn't block on s child process.waitFor()
|
||||
* that may happen on windows if simple processBuilder.start is used due to handles inheritance:
|
||||
* - process A starts process B using ProcessBuilder and waits for it using process.waitFor()
|
||||
* - process B starts daemon and exits
|
||||
* - due to default behavior of CreateProcess on windows, the handles of process B are inherited by the daemon
|
||||
* (in particular handles of stdin/out/err) and therefore these handles remain open while daemon is running
|
||||
* - (seems) due to the way how waiting for process is implemented, waitFor() hangs until daemon is killed
|
||||
* This seems a known problem, e.g. gradle uses a library with native code that prevents io handles inheritance when launching it's daemon
|
||||
* (the same solution is used in kotlin daemon client - see next commit)
|
||||
*/
|
||||
public fun testDaemonExecutionViaIntermediateProcess() {
|
||||
val clientAliveFile = createTempFile("kotlin-daemon-transitive-run-test", ".run")
|
||||
val runFilesPath = File(tmpdir, getTestName(true)).absolutePath
|
||||
val daemonOptions = DaemonOptions(runFilesPath = runFilesPath, clientAliveFlagPath = clientAliveFile.absolutePath)
|
||||
val args = listOf(
|
||||
File(File(System.getProperty("java.home"), "bin"), "java").absolutePath,
|
||||
"-D$COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY",
|
||||
"-cp",
|
||||
daemonClientClassPath.joinToString(File.pathSeparator) { it.absolutePath },
|
||||
KotlinCompilerClient::class.qualifiedName!!) +
|
||||
daemonOptions.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } +
|
||||
compilerId.mappers.flatMap { it.toArgs(COMPILE_DAEMON_CMDLINE_OPTIONS_PREFIX) } +
|
||||
File(getHelloAppBaseDir(), "hello.kt").absolutePath
|
||||
try {
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
var resOutput: String? = null
|
||||
var resCode: Int? = null
|
||||
// running intermediate process (daemon command line controller) that executes the daemon
|
||||
val runnerProcess = ProcessBuilder(args).redirectErrorStream(true).start()
|
||||
thread {
|
||||
resOutput = runnerProcess.inputStream.reader().readText()
|
||||
}
|
||||
val waitThread = thread {
|
||||
resCode = runnerProcess.waitFor()
|
||||
}
|
||||
waitThread.join(TIMEOUT_DAEMON_RUNNER_EXIT_MS)
|
||||
|
||||
TestCase.assertFalse("process.waitFor() hangs:\n$resOutput", waitThread.isAlive)
|
||||
TestCase.assertEquals("Compilation failed:\n$resOutput", 0, resCode)
|
||||
}
|
||||
finally {
|
||||
if (clientAliveFile.exists())
|
||||
clientAliveFile.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user