Refactor daemon tests, some minor fixes in the client and daemon
Tests refactored for better readability and code reuse Some shutdown livelock is fixed Some logging added
This commit is contained in:
+3
@@ -145,6 +145,7 @@ object KotlinCompilerClient {
|
||||
compilerService.releaseCompileSession(sessionId)
|
||||
}
|
||||
|
||||
@Deprecated("Use other compile method", ReplaceWith("compile"))
|
||||
fun compile(compilerService: CompileService,
|
||||
sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
@@ -158,6 +159,7 @@ object KotlinCompilerClient {
|
||||
}
|
||||
|
||||
|
||||
@Deprecated("Use non-deprecated compile method", ReplaceWith("compile"))
|
||||
fun incrementalCompile(compileService: CompileService,
|
||||
sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
@@ -308,6 +310,7 @@ object KotlinCompilerClient {
|
||||
|
||||
// --- Implementation ---------------------------------------
|
||||
|
||||
@Synchronized
|
||||
private inline fun <R> connectLoop(reportingTargets: DaemonReportingTargets, body: () -> R?): R? {
|
||||
try {
|
||||
var attempts = 0
|
||||
|
||||
@@ -335,6 +335,7 @@ class CompileServiceImpl(
|
||||
val daemonReporter = DaemonMessageReporter(servicesFacade, compilationOptions)
|
||||
val compilerMode = compilationOptions.compilerMode
|
||||
val targetPlatform = compilationOptions.targetPlatform
|
||||
log.info("Starting compilation with args: " + compilerArguments.joinToString(" "))
|
||||
val k2PlatformArgs = try {
|
||||
when (targetPlatform) {
|
||||
CompileService.TargetPlatform.JVM -> K2JVMCompilerArguments().apply { K2JVMCompiler().parseArguments(compilerArguments, this) }
|
||||
@@ -709,6 +710,10 @@ class CompileServiceImpl(
|
||||
|
||||
private fun shutdownImpl() {
|
||||
log.info("Shutdown started")
|
||||
fun Long.mb() = this / (1024 * 1024)
|
||||
with (Runtime.getRuntime()) {
|
||||
log.info("Memory stats: total: ${totalMemory().mb()}mb, free: ${freeMemory().mb()}mb, max: ${maxMemory().mb()}mb")
|
||||
}
|
||||
state.alive.set(Aliveness.Dying.ordinal)
|
||||
|
||||
UnicastRemoteObject.unexportObject(this, true)
|
||||
@@ -869,9 +874,18 @@ class CompileServiceImpl(
|
||||
ifAliveChecksImpl(minAliveness, ignoreCompilerChanged, body)
|
||||
}
|
||||
|
||||
inline private fun<R> ifAliveChecksImpl(minAliveness: Aliveness = Aliveness.Alive, ignoreCompilerChanged: Boolean = false, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> =
|
||||
when {
|
||||
state.alive.get() < minAliveness.ordinal -> CompileService.CallResult.Dying()
|
||||
inline private fun<R> ifAliveChecksImpl(minAliveness: Aliveness = Aliveness.Alive, ignoreCompilerChanged: Boolean = false, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> {
|
||||
val curState = state.alive.get()
|
||||
return when {
|
||||
curState < minAliveness.ordinal -> {
|
||||
log.info("Cannot perform operation, requested state: ${minAliveness.name} > actual: ${try {
|
||||
Aliveness.values()[curState].name
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
"invalid($curState)"
|
||||
}}")
|
||||
CompileService.CallResult.Dying()
|
||||
}
|
||||
!ignoreCompilerChanged && classpathWatcher.isChanged -> {
|
||||
log.info("Compiler changed, scheduling shutdown")
|
||||
shutdownWithDelay()
|
||||
@@ -887,6 +901,7 @@ class CompileServiceImpl(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun<R> withValidClientOrSessionProxy(sessionId: Int,
|
||||
body: (ClientOrSessionProxy<Any>?) -> CompileService.CallResult<R>
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.daemon
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.cli.AbstractCliTest
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.daemon.client.*
|
||||
import org.jetbrains.kotlin.daemon.common.*
|
||||
@@ -26,6 +28,7 @@ import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.net.URL
|
||||
import java.net.URLClassLoader
|
||||
import java.rmi.server.UnicastRemoteObject
|
||||
@@ -58,7 +61,9 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(clientAliveFile.absolutePath)
|
||||
val strm = ByteArrayOutputStream()
|
||||
val code = KotlinCompilerClient.compile(daemon!!, CompileService.NO_SESSION, CompileService.TargetPlatform.JVM, args, strm)
|
||||
val code = KotlinCompilerClient.compile(daemon!!, CompileService.NO_SESSION, CompileService.TargetPlatform.JVM,
|
||||
args, PrintingMessageCollector(PrintStream(strm), MessageRenderer.WITHOUT_PATHS, true),
|
||||
reportSeverity = ReportSeverity.DEBUG)
|
||||
return CompilerResults(code, strm.toString())
|
||||
}
|
||||
|
||||
@@ -75,46 +80,61 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
private fun run(logName: String, vararg args: String): Int = runJava(getTestBaseDir(), logName, *args)
|
||||
|
||||
fun makeTestDaemonOptions(testName: String, shutdownDelay: Int = 5) =
|
||||
DaemonOptions(runFilesPath = File(tmpdir, testName).absolutePath,
|
||||
shutdownDelayMilliseconds = shutdownDelay.toLong(),
|
||||
verbose = true,
|
||||
reportPerf = true)
|
||||
|
||||
fun makeTestDaemonJvmOptions(logFile: File? = null, xmx: Int = 256): DaemonJVMOptions {
|
||||
val additionalArgs = arrayListOf<String>()
|
||||
if (logFile != null) {
|
||||
additionalArgs.add("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"")
|
||||
}
|
||||
val baseOpts = if (xmx > 0) DaemonJVMOptions(maxMemory = "${xmx}m") else DaemonJVMOptions()
|
||||
return configureDaemonJVMOptions(
|
||||
baseOpts,
|
||||
*additionalArgs.toTypedArray(),
|
||||
inheritMemoryLimits = xmx > 0,
|
||||
inheritAdditionalProperties = false)
|
||||
}
|
||||
|
||||
fun testHelloApp() {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(runFilesPath = File(tmpdir, getTestName(true)).absolutePath,
|
||||
shutdownDelayMilliseconds = 1,
|
||||
verbose = true,
|
||||
reportPerf = true)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test.", ".log")
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
var daemonShotDown = false
|
||||
|
||||
val daemonJVMOptions = configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
var daemonShotDown = false
|
||||
try {
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
|
||||
runDaemonCompilerTwice(flagFile, compilerId, daemonJVMOptions, daemonOptions,
|
||||
"-include-runtime", File(getTestBaseDir(), "hello.kt").absolutePath, "-d", jar)
|
||||
|
||||
try {
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
|
||||
runDaemonCompilerTwice(flagFile, compilerId, daemonJVMOptions, daemonOptions,
|
||||
"-include-runtime", File(getTestBaseDir(), "hello.kt").absolutePath, "-d", jar)
|
||||
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
Thread.sleep(100)
|
||||
daemonShotDown = true
|
||||
var compileTime1 = 0L
|
||||
var compileTime2 = 0L
|
||||
logFile.assertLogContainsSequence(
|
||||
LinePattern("Kotlin compiler daemon version"),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups[1]?.value?.toLong()?.let { compileTime1 = it }; true }),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups[1]?.value?.toLong()?.let { compileTime2 = it }; true }),
|
||||
LinePattern("Shutdown started"))
|
||||
assertTrue("Expecting that compilation 1 ($compileTime1 ms) is at least two times longer than compilation 2 ($compileTime2 ms)",
|
||||
compileTime1 > compileTime2 * 2)
|
||||
logFile.delete()
|
||||
run("hello.run", "-cp", jar, "Hello.HelloKt")
|
||||
}
|
||||
finally {
|
||||
if (!daemonShotDown)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
Thread.sleep(100)
|
||||
daemonShotDown = true
|
||||
var compileTime1 = 0L
|
||||
var compileTime2 = 0L
|
||||
logFile.assertLogContainsSequence(
|
||||
LinePattern("Kotlin compiler daemon version"),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups[1]?.value?.toLong()?.let { compileTime1 = it }; true }),
|
||||
LinePattern("Starting compilation with args: "),
|
||||
LinePattern("Compile on daemon: (\\d+) ms", { it.groups[1]?.value?.toLong()?.let { compileTime2 = it }; true }),
|
||||
LinePattern("Shutdown started"))
|
||||
assertTrue("Expecting that compilation 1 ($compileTime1 ms) is at least two times longer than compilation 2 ($compileTime2 ms)",
|
||||
compileTime1 > compileTime2 * 2)
|
||||
logFile.delete()
|
||||
run("hello.run", "-cp", jar, "Hello.HelloKt")
|
||||
}
|
||||
finally {
|
||||
if (!daemonShotDown)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,45 +169,42 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
fun testDaemonInstancesSimple() {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
val compilerId2 = CompilerId.makeCompilerId(compilerClassPath +
|
||||
File(KotlinIntegrationTestBase.getCompilerLib(), "kotlin-compiler-sources.jar"))
|
||||
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId2, daemonOptions)
|
||||
|
||||
val logFile1 = createTempFile("kotlin-daemon1-test", ".log")
|
||||
val logFile2 = createTempFile("kotlin-daemon2-test", ".log")
|
||||
val daemonJVMOptions1 =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile1.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon1-test") { logFile1 ->
|
||||
withLogFile("kotlin-daemon2-test") { logFile2 ->
|
||||
val daemonJVMOptions1 = makeTestDaemonJvmOptions(logFile1)
|
||||
val daemonJVMOptions2 = makeTestDaemonJvmOptions(logFile2)
|
||||
|
||||
val daemonJVMOptions2 =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile2.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
assertTrue(logFile1.length() == 0L && logFile2.length() == 0L)
|
||||
|
||||
assertTrue(logFile1.length() == 0L && logFile2.length() == 0L)
|
||||
val jar1 = tmpdir.absolutePath + File.separator + "hello1.jar"
|
||||
val res1 = compileOnDaemon(flagFile, compilerId, daemonJVMOptions1, daemonOptions, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar1)
|
||||
assertEquals("first compilation failed:\n${res1.out}", 0, res1.resultCode)
|
||||
|
||||
val jar1 = tmpdir.absolutePath + File.separator + "hello1.jar"
|
||||
val res1 = compileOnDaemon(flagFile, compilerId, daemonJVMOptions1, daemonOptions, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar1)
|
||||
assertEquals("first compilation failed:\n${res1.out}", 0, res1.resultCode)
|
||||
logFile1.assertLogContainsSequence("Starting compilation with args: ")
|
||||
assertEquals("expecting '${logFile2.absolutePath}' to be empty", 0L, logFile2.length())
|
||||
|
||||
logFile1.assertLogContainsSequence("Starting compilation with args: ")
|
||||
assertEquals("expecting '${logFile2.absolutePath}' to be empty", 0L, logFile2.length())
|
||||
val jar2 = tmpdir.absolutePath + File.separator + "hello2.jar"
|
||||
val res2 = compileOnDaemon(flagFile, compilerId2, daemonJVMOptions2, daemonOptions, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar2)
|
||||
assertEquals("second compilation failed:\n${res2.out}", 0, res1.resultCode)
|
||||
|
||||
val jar2 = tmpdir.absolutePath + File.separator + "hello2.jar"
|
||||
val res2 = compileOnDaemon(flagFile, compilerId2, daemonJVMOptions2, daemonOptions, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar2)
|
||||
assertEquals("second compilation failed:\n${res2.out}", 0, res1.resultCode)
|
||||
logFile2.assertLogContainsSequence("Starting compilation with args: ")
|
||||
|
||||
logFile2.assertLogContainsSequence("Starting compilation with args: ")
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId2, daemonOptions)
|
||||
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId2, daemonOptions)
|
||||
Thread.sleep(100)
|
||||
|
||||
Thread.sleep(100)
|
||||
|
||||
logFile1.assertLogContainsSequence("Shutdown started")
|
||||
logFile2.assertLogContainsSequence("Shutdown started")
|
||||
logFile1.assertLogContainsSequence("Shutdown started")
|
||||
logFile2.assertLogContainsSequence("Shutdown started")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,25 +213,23 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
val daemonOptions = DaemonOptions(autoshutdownUnusedSeconds = 1, shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
|
||||
// wait up to 4s (more than 1s unused timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Unused timeout exceeded 1s")) break
|
||||
// wait up to 4s (more than 1s unused timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Unused timeout exceeded 1s")) break
|
||||
Thread.sleep(200)
|
||||
}
|
||||
Thread.sleep(200)
|
||||
}
|
||||
Thread.sleep(200)
|
||||
|
||||
logFile.assertLogContainsSequence("Unused timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
logFile.delete()
|
||||
logFile.assertLogContainsSequence("Unused timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,30 +238,31 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
val daemonOptions = DaemonOptions(autoshutdownIdleSeconds = 1, shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello1.jar"
|
||||
val strm = ByteArrayOutputStream()
|
||||
val code = KotlinCompilerClient.compile(daemon!!, CompileService.NO_SESSION, CompileService.TargetPlatform.JVM, arrayOf("-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar), strm)
|
||||
assertEquals("compilation failed:\n$strm", 0, code)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello1.jar"
|
||||
val strm = ByteArrayOutputStream()
|
||||
val code = KotlinCompilerClient.compile(daemon!!, CompileService.NO_SESSION, CompileService.TargetPlatform.JVM,
|
||||
arrayOf("-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar),
|
||||
PrintingMessageCollector(PrintStream(strm), MessageRenderer.WITHOUT_PATHS, true),
|
||||
reportSeverity = ReportSeverity.DEBUG)
|
||||
assertEquals("compilation failed:\n$strm", 0, code)
|
||||
|
||||
logFile.assertLogContainsSequence("Starting compilation with args: ")
|
||||
logFile.assertLogContainsSequence("Starting compilation with args: ")
|
||||
|
||||
// wait up to 4s (more than 1s idle timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Idle timeout exceeded 1s")) break
|
||||
// wait up to 4s (more than 1s idle timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Idle timeout exceeded 1s")) break
|
||||
Thread.sleep(200)
|
||||
}
|
||||
Thread.sleep(200)
|
||||
logFile.assertLogContainsSequence("Idle timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
}
|
||||
Thread.sleep(200)
|
||||
logFile.assertLogContainsSequence("Idle timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
logFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,35 +271,33 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
val daemonOptions = DaemonOptions(autoshutdownIdleSeconds = 1, shutdownDelayMilliseconds = 1, forceShutdownTimeoutMilliseconds = 60000, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val sessionId = daemon?.leaseCompileSession(null)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val sessionId = daemon?.leaseCompileSession(null)
|
||||
|
||||
val scheduleShutdownRes = daemon?.scheduleShutdown(true)
|
||||
val scheduleShutdownRes = daemon?.scheduleShutdown(true)
|
||||
|
||||
assertTrue("failed to schedule shutdown ($scheduleShutdownRes)", scheduleShutdownRes?.let { it.isGood && it.get() } ?: false )
|
||||
assertTrue("failed to schedule shutdown ($scheduleShutdownRes)", scheduleShutdownRes?.let { it.isGood && it.get() } ?: false)
|
||||
|
||||
Thread.sleep(100) // to allow timer task to run in the daemon
|
||||
Thread.sleep(100) // to allow timer task to run in the daemon
|
||||
|
||||
logFile.assertLogContainsSequence("Some sessions are active, waiting for them to finish")
|
||||
logFile.assertLogContainsSequence("Some sessions are active, waiting for them to finish")
|
||||
|
||||
val res = daemon?.getUsedMemory()
|
||||
val res = daemon?.getUsedMemory()
|
||||
|
||||
assertEquals("Invalid state", CompileService.CallResult.Dying(), res)
|
||||
assertEquals("Invalid state", CompileService.CallResult.Dying(), res)
|
||||
|
||||
daemon?.releaseCompileSession(sessionId!!.get())
|
||||
daemon?.releaseCompileSession(sessionId!!.get())
|
||||
|
||||
Thread.sleep(100) // allow after session timed action to run
|
||||
Thread.sleep(100) // allow after session timed action to run
|
||||
|
||||
logFile.assertLogContainsSequence("All sessions finished, shutting down",
|
||||
"Shutdown started")
|
||||
logFile.delete()
|
||||
logFile.assertLogContainsSequence("All sessions finished, shutting down",
|
||||
"Shutdown started")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,11 +313,11 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
*/
|
||||
fun testDaemonExecutionViaIntermediateProcess() {
|
||||
val clientAliveFile = createTempFile("kotlin-daemon-transitive-run-test", ".run")
|
||||
val runFilesPath = File(tmpdir, getTestName(true)).absolutePath
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = runFilesPath)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
|
||||
val args = listOf(
|
||||
File(File(System.getProperty("java.home"), "bin"), "java").absolutePath,
|
||||
"-Xmx256m",
|
||||
"-D$COMPILE_DAEMON_VERBOSE_REPORT_PROPERTY",
|
||||
"-cp",
|
||||
daemonClientClassPath.joinToString(File.pathSeparator) { it.absolutePath },
|
||||
@@ -354,74 +368,69 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
assertTrue(PARALLEL_THREADS_TO_COMPILE <= LoopbackNetworkInterface.SERVER_SOCKET_BACKLOG_SIZE)
|
||||
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
val daemonJVMOptions = configureDaemonJVMOptions(inheritMemoryLimits = true, inheritAdditionalProperties = false)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
|
||||
val (_, port) = findPortAndCreateRegistry(10, 16384, 65535)
|
||||
val tracer = SynchronizationTracer(CountDownLatch(1), CountDownLatch(PARALLEL_THREADS_TO_COMPILE), port)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile, xmx = -1)
|
||||
|
||||
val resultCodes = arrayOfNulls<Int>(PARALLEL_THREADS_TO_COMPILE)
|
||||
val localEndSignal = CountDownLatch(PARALLEL_THREADS_TO_COMPILE)
|
||||
val outStreams = Array(PARALLEL_THREADS_TO_COMPILE, { ByteArrayOutputStream() })
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
|
||||
fun runCompile(threadNo: Int) =
|
||||
thread {
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.$threadNo.jar"
|
||||
val res = KotlinCompilerClient.compile(
|
||||
daemon!!,
|
||||
CompileService.NO_SESSION,
|
||||
CompileService.TargetPlatform.JVM,
|
||||
arrayOf("-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar),
|
||||
outStreams[threadNo],
|
||||
port = port,
|
||||
operationsTracer = tracer as RemoteOperationsTracer)
|
||||
synchronized(resultCodes) {
|
||||
resultCodes[threadNo] = res
|
||||
val (_, port) = findPortAndCreateRegistry(10, 16384, 65535)
|
||||
val resultCodes = arrayOfNulls<Int>(PARALLEL_THREADS_TO_COMPILE)
|
||||
val localEndSignal = CountDownLatch(PARALLEL_THREADS_TO_COMPILE)
|
||||
val outStreams = Array(PARALLEL_THREADS_TO_COMPILE, { ByteArrayOutputStream() })
|
||||
|
||||
fun runCompile(threadNo: Int) =
|
||||
thread {
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.$threadNo.jar"
|
||||
val res = KotlinCompilerClient.compile(
|
||||
daemon!!,
|
||||
CompileService.NO_SESSION,
|
||||
CompileService.TargetPlatform.JVM,
|
||||
arrayOf("-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar),
|
||||
PrintingMessageCollector(PrintStream(outStreams[threadNo]), MessageRenderer.WITHOUT_PATHS, true),
|
||||
port = port)
|
||||
synchronized(resultCodes) {
|
||||
resultCodes[threadNo] = res
|
||||
}
|
||||
localEndSignal.countDown()
|
||||
}
|
||||
localEndSignal.countDown()
|
||||
}
|
||||
|
||||
(1..PARALLEL_THREADS_TO_COMPILE).forEach { runCompile(it - 1) }
|
||||
(1..PARALLEL_THREADS_TO_COMPILE).forEach { runCompile(it - 1) }
|
||||
|
||||
tracer.startSignal.countDown()
|
||||
val succeeded = tracer.doneSignal.await(PARALLEL_WAIT_TIMEOUT_S, TimeUnit.SECONDS)
|
||||
assertTrue("parallel compilation failed to complete in $PARALLEL_WAIT_TIMEOUT_S s, ${tracer.doneSignal.count} unfinished threads", succeeded)
|
||||
val succeeded = localEndSignal.await(PARALLEL_WAIT_TIMEOUT_S, TimeUnit.SECONDS)
|
||||
assertTrue("parallel compilation failed to complete in $PARALLEL_WAIT_TIMEOUT_S s, ${localEndSignal.count} unfinished threads", succeeded)
|
||||
|
||||
localEndSignal.await(PARALLEL_WAIT_TIMEOUT_S, TimeUnit.SECONDS)
|
||||
(1..PARALLEL_THREADS_TO_COMPILE).forEach {
|
||||
assertEquals("Compilation on thread $it failed:\n${outStreams[it - 1]}", 0, resultCodes[it - 1])
|
||||
(1..PARALLEL_THREADS_TO_COMPILE).forEach {
|
||||
assertEquals("Compilation on thread $it failed:\n${outStreams[it - 1]}", 0, resultCodes[it - 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun testParallelDaemonStart() {
|
||||
private val PARALLEL_THREADS_TO_START = 8
|
||||
|
||||
val PARALLEL_THREADS_TO_START = 8
|
||||
fun testParallelDaemonStart() {
|
||||
|
||||
val doneLatch = CountDownLatch(PARALLEL_THREADS_TO_START)
|
||||
|
||||
val resultCodes = arrayOfNulls<Int>(PARALLEL_THREADS_TO_START)
|
||||
val outStreams = Array(PARALLEL_THREADS_TO_START, { ByteArrayOutputStream() })
|
||||
val logFiles = arrayOfNulls<File>(PARALLEL_THREADS_TO_START)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true), 100)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
fun connectThread(threadNo: Int) = thread(name = "daemonConnect$threadNo") {
|
||||
try {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
withFlagFile(getTestName(true), ".salive") { sessionFlagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 10000, // attempt to avoid immediate shutdown of the non-elected daemons
|
||||
runFilesPath = File(tmpdir, getTestName(true)).absolutePath,
|
||||
verbose = true)
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
logFiles[threadNo] = logFile
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions(DaemonJVMOptions(maxMemory = "2048m"),
|
||||
"D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
val compileServiceSession = KotlinCompilerClient.connectAndLease(compilerId, flagFile, daemonJVMOptions, daemonOptions,
|
||||
DaemonReportingTargets(out = System.err), autostart = true,
|
||||
leaseSession = true, sessionAliveFlagFile = sessionFlagFile)
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
val compileServiceSession =
|
||||
KotlinCompilerClient.connectAndLease(compilerId, flagFile, daemonJVMOptions, daemonOptions,
|
||||
DaemonReportingTargets(out = System.err), autostart = true,
|
||||
leaseSession = true)
|
||||
assertNotNull("failed to connect daemon", compileServiceSession?.compileService)
|
||||
val jar = tmpdir.absolutePath + File.separator + "hello.$threadNo.jar"
|
||||
val res = KotlinCompilerClient.compile(
|
||||
@@ -429,8 +438,9 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
compileServiceSession.sessionId,
|
||||
CompileService.TargetPlatform.JVM,
|
||||
arrayOf(File(getHelloAppBaseDir(), "hello.kt").absolutePath, "-d", jar),
|
||||
outStreams[threadNo])
|
||||
PrintingMessageCollector(PrintStream(outStreams[threadNo]), MessageRenderer.WITHOUT_PATHS, true))
|
||||
resultCodes[threadNo] = res
|
||||
assertEquals("Compilation on thread $threadNo failed", 0, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -457,22 +467,19 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
val electionLogs = (0..(PARALLEL_THREADS_TO_START - 1)).map {
|
||||
val logContents = logFiles[it]?.readLines()
|
||||
assertEquals("Compilation on thread $it failed:\n${outStreams[it]}\n\n------- daemon log: -------\n${logContents?.joinToString("\n")}\n-------", 0, resultCodes[it])
|
||||
logContents?.find { it.contains(LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE) }
|
||||
}
|
||||
|
||||
assertTrue("No daemon elected: \n${electionLogs.joinToString("\n")}",
|
||||
electionLogs.any { it != null && (it.contains("lower prio") || it.contains("equal prio")) })
|
||||
|
||||
logFiles.forEach { it?.delete() }
|
||||
}
|
||||
|
||||
fun testDaemonConnectionProblems() {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val daemonJVMOptions = configureDaemonJVMOptions(inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions()
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
@@ -500,48 +507,46 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
|
||||
fun testDaemonCallbackConnectionProblems() {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
daemon?.registerClient(flagFile.absolutePath)
|
||||
|
||||
val file = File(tmpdir, "largeKotlinFile.kt")
|
||||
file.writeText(generateLargeKotlinFile(10))
|
||||
val jar = File(tmpdir, "largeKotlinFile.jar").absolutePath
|
||||
val file = File(tmpdir, "largeKotlinFile.kt")
|
||||
file.writeText(generateLargeKotlinFile(10))
|
||||
val jar = File(tmpdir, "largeKotlinFile.jar").absolutePath
|
||||
|
||||
var callbackServices: CompilerCallbackServicesFacadeServer? = null
|
||||
callbackServices = CompilerCallbackServicesFacadeServer(compilationCanceledStatus = object : CompilationCanceledStatus {
|
||||
override fun checkCanceled() {
|
||||
thread {
|
||||
Thread.sleep(10)
|
||||
UnicastRemoteObject.unexportObject(callbackServices, true)
|
||||
var callbackServices: CompilerCallbackServicesFacadeServer? = null
|
||||
callbackServices = CompilerCallbackServicesFacadeServer(compilationCanceledStatus = object : CompilationCanceledStatus {
|
||||
override fun checkCanceled() {
|
||||
thread {
|
||||
Thread.sleep(10)
|
||||
UnicastRemoteObject.unexportObject(callbackServices, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, port = SOCKET_ANY_FREE_PORT)
|
||||
val strm = ByteArrayOutputStream()
|
||||
val code = daemon!!.remoteCompile(CompileService.NO_SESSION,
|
||||
CompileService.TargetPlatform.JVM,
|
||||
arrayOf("-include-runtime", file.absolutePath, "-d", jar),
|
||||
callbackServices,
|
||||
RemoteOutputStreamServer(strm, SOCKET_ANY_FREE_PORT),
|
||||
CompileService.OutputFormat.XML,
|
||||
RemoteOutputStreamServer(strm, SOCKET_ANY_FREE_PORT),
|
||||
null).get()
|
||||
}, port = SOCKET_ANY_FREE_PORT)
|
||||
val strm = ByteArrayOutputStream()
|
||||
val code = daemon!!.remoteCompile(CompileService.NO_SESSION,
|
||||
CompileService.TargetPlatform.JVM,
|
||||
arrayOf("-include-runtime", file.absolutePath, "-d", jar),
|
||||
callbackServices,
|
||||
RemoteOutputStreamServer(strm, SOCKET_ANY_FREE_PORT),
|
||||
CompileService.OutputFormat.XML,
|
||||
RemoteOutputStreamServer(strm, SOCKET_ANY_FREE_PORT),
|
||||
null).get()
|
||||
|
||||
TestCase.assertEquals(0, code)
|
||||
TestCase.assertEquals(0, code)
|
||||
|
||||
val compilerOutput = strm.toString()
|
||||
assertTrue("Expecting cancellation message in:\n$compilerOutput", compilerOutput.contains("Compilation was canceled"))
|
||||
logFile.assertLogContainsSequence("error communicating with host, assuming compilation canceled")
|
||||
val compilerOutput = strm.toString()
|
||||
assertTrue("Expecting cancellation message in:\n$compilerOutput", compilerOutput.contains("Compilation was canceled"))
|
||||
logFile.assertLogContainsSequence("error communicating with host, assuming compilation canceled")
|
||||
|
||||
logFile.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,53 +613,53 @@ class CompilerDaemonTest : KotlinIntegrationTestBase() {
|
||||
val daemonOptions = DaemonOptions(autoshutdownIdleSeconds = 1, autoshutdownUnusedSeconds = 1, shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
KotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
|
||||
|
||||
val logFile = createTempFile("kotlin-daemon-test", ".log")
|
||||
val daemonJVMOptions =
|
||||
configureDaemonJVMOptions("D$COMPILE_DAEMON_LOG_PATH_PROPERTY=\"${logFile.loggerCompatiblePath}\"",
|
||||
inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
val daemon = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
|
||||
val replCompiler = KotlinRemoteReplCompilerClient(daemon!!, null, CompileService.TargetPlatform.JVM,
|
||||
emptyArray(),
|
||||
TestMessageCollector(),
|
||||
classpathFromClassloader(),
|
||||
ScriptWithNoParam::class.qualifiedName!!)
|
||||
val replCompiler = KotlinRemoteReplCompilerClient(daemon!!, null, CompileService.TargetPlatform.JVM,
|
||||
emptyArray(),
|
||||
TestMessageCollector(),
|
||||
classpathFromClassloader(),
|
||||
ScriptWithNoParam::class.qualifiedName!!)
|
||||
|
||||
val compilerState = replCompiler.createState()
|
||||
val compilerState = replCompiler.createState()
|
||||
|
||||
// use repl compiler for >> 1s, making sure that idle/unused timeouts are not firing
|
||||
for (attempts in 1..10) {
|
||||
val codeLine1 = ReplCodeLine(attempts, 0, "3 + 5")
|
||||
val res1 = replCompiler.compile(compilerState, codeLine1)
|
||||
val res1c = res1 as? ReplCompileResult.CompiledClasses
|
||||
TestCase.assertNotNull("Unexpected compile result: $res1", res1c)
|
||||
Thread.sleep(200)
|
||||
}
|
||||
|
||||
// wait up to 4s (more than 1s idle timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Idle timeout exceeded 1s")) break
|
||||
Thread.sleep(200)
|
||||
}
|
||||
replCompiler.dispose()
|
||||
|
||||
// use repl compiler for >> 1s, making sure that idle/unused timeouts are not firing
|
||||
for (attempts in 1..10) {
|
||||
val codeLine1 = ReplCodeLine(attempts, 0, "3 + 5")
|
||||
val res1 = replCompiler.compile(compilerState, codeLine1)
|
||||
val res1c = res1 as? ReplCompileResult.CompiledClasses
|
||||
TestCase.assertNotNull("Unexpected compile result: $res1", res1c)
|
||||
Thread.sleep(200)
|
||||
logFile.assertLogContainsSequence("Idle timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
}
|
||||
|
||||
// wait up to 4s (more than 1s idle timeout)
|
||||
for (attempts in 1..20) {
|
||||
if (logFile.isLogContainsSequence("Idle timeout exceeded 1s")) break
|
||||
Thread.sleep(200)
|
||||
}
|
||||
replCompiler.dispose()
|
||||
|
||||
Thread.sleep(200)
|
||||
logFile.assertLogContainsSequence("Idle timeout exceeded 1s",
|
||||
"Shutdown started")
|
||||
logFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun withDaemon(body: (CompileService) -> Unit) {
|
||||
withFlagFile(getTestName(true), ".alive") { flagFile ->
|
||||
val daemonOptions = DaemonOptions(shutdownDelayMilliseconds = 1, runFilesPath = File(tmpdir, getTestName(true)).absolutePath)
|
||||
val daemonJVMOptions = configureDaemonJVMOptions(inheritMemoryLimits = false, inheritAdditionalProperties = false)
|
||||
val daemon: CompileService? = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
val daemonOptions = makeTestDaemonOptions(getTestName(true))
|
||||
withLogFile("kotlin-daemon-test") { logFile ->
|
||||
val daemonJVMOptions = makeTestDaemonJvmOptions(logFile)
|
||||
val daemon: CompileService? = KotlinCompilerClient.connectToCompileService(compilerId, flagFile, daemonJVMOptions, daemonOptions, DaemonReportingTargets(out = System.err), autostart = true)
|
||||
assertNotNull("failed to connect daemon", daemon)
|
||||
|
||||
body(daemon!!)
|
||||
body(daemon!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -727,6 +732,17 @@ internal inline fun withFlagFile(prefix: String, suffix: String? = null, body: (
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun withLogFile(prefix: String, suffix: String = ".log", body: (File) -> Unit) {
|
||||
val logFile = createTempFile(prefix, suffix)
|
||||
try {
|
||||
body(logFile)
|
||||
}
|
||||
catch (e: Exception) {
|
||||
System.err.println("--- log file ${logFile.name}:\n${logFile.readText()}\n---")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
// java.util.Logger used in the daemon silently forgets to log into a file specified in the config on Windows,
|
||||
// if file path is given in windows form (using backslash as a separator); the reason is unknown
|
||||
// this function makes a path with forward slashed, that works on windows too
|
||||
|
||||
Reference in New Issue
Block a user