Remove experimental implementation of Kotlin Compiler Daemon

#KT-50846 Fixed
This commit is contained in:
Andrey Uskov
2022-01-26 23:34:30 +04:00
committed by teamcity
parent 94f690a10e
commit c9e0100214
72 changed files with 0 additions and 7812 deletions
@@ -15,7 +15,6 @@ dependencies {
testCompileOnly(project(":kotlin-test:kotlin-test-jvm"))
testCompileOnly(project(":kotlin-test:kotlin-test-junit"))
testApi(project(":kotlin-daemon-client"))
testApi(project(":kotlin-daemon-client-new"))
testCompileOnly(project(":kotlin-daemon"))
testApi(projectTests(":compiler:tests-common"))
testApi(commonDependency("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
@@ -1,336 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.experimental.integration
import com.intellij.openapi.application.ApplicationManager
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSourceLocation
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.daemon.captureOut
import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets
import org.jetbrains.kotlin.daemon.client.KotlinCompilerDaemonClient
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.ReportSeverity
import org.jetbrains.kotlin.daemon.loggerCompatiblePath
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.test.IgnoreAll
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.resetApplicationToNull
import org.jetbrains.kotlin.test.util.KtTestUtil
import org.junit.Assert
import org.junit.runner.RunWith
import java.io.File
import java.net.URLClassLoader
import java.nio.file.Path
import java.util.logging.LogManager
import java.util.logging.Logger
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createTempFile
private val logFiles = arrayListOf<String>()
// TODO: remove ignore annotation from tests.
@OptIn(ExperimentalPathApi::class)
@RunWith(IgnoreAll::class)
class CompilerApiTest : KotlinIntegrationTestBase() {
val kotlinCompilerClient = KotlinCompilerDaemonClient
.instantiate(DaemonProtocolVariant.SOCKETS) // TODO(SOCKETS)
private val compilerLibDir = getCompilerLib()
private fun createNewLogFile(): Path {
println("creating logFile")
val newLogFile = createTempFile("kotlin-daemon-experimental-test.", ".log")
println("logFile created (${newLogFile.loggerCompatiblePath})")
logFiles.add(newLogFile.loggerCompatiblePath)
return newLogFile
}
private val currentLogFile: Path by lazy {
val newLogFile = createNewLogFile()
val cfg: String =
"handlers = java.util.logging.FileHandler\n" +
"java.util.logging.FileHandler.level = ALL\n" +
"java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter\n" +
"java.util.logging.FileHandler.encoding = UTF-8\n" +
"java.util.logging.FileHandler.limit = 0\n" + // if file is provided - disabled, else - 1Mb
"java.util.logging.FileHandler.count = 1\n" +
"java.util.logging.FileHandler.append = true\n" +
"java.util.logging.FileHandler.pattern = ${newLogFile.loggerCompatiblePath}\n" +
"java.util.logging.SimpleFormatter.format = %1\$tF %1\$tT.%1\$tL [%3\$s] %4\$s: %5\$s%n\n"
LogManager.getLogManager().readConfiguration(cfg.byteInputStream())
newLogFile
}
private val externalLogFile: Path by lazy { createNewLogFile() }
private val log by lazy {
currentLogFile
Logger.getLogger("test")
}
val compilerClassPath = listOf(
File(compilerLibDir, "kotlin-compiler.jar"),
File(compilerLibDir, "kotlin-daemon.jar")
)
val scriptRuntimeClassPath = listOf(
File(compilerLibDir, "kotlin-runtime.jar"),
File(compilerLibDir, "kotlin-script-runtime.jar")
)
val compilerId by lazy(LazyThreadSafetyMode.NONE) { CompilerId.makeCompilerId(compilerClassPath) }
private fun compileLocally(
messageCollector: TestMessageCollector,
vararg args: String
): Pair<Int, Collection<OutputMessageUtil.Output>> {
val application = ApplicationManager.getApplication()
try {
val code = K2JVMCompiler().exec(messageCollector,
Services.EMPTY,
K2JVMCompilerArguments().apply { K2JVMCompiler().parseArguments(args, this) }).code
val outputs = messageCollector.messages.filter { it.severity == CompilerMessageSeverity.OUTPUT }.mapNotNull {
OutputMessageUtil.parseOutputMessage(it.message)?.let { outs ->
outs.outputFile?.let { OutputMessageUtil.Output(outs.sourceFiles, it) }
}
}
return code to outputs
} finally {
resetApplicationToNull(application)
}
}
private fun compileOnDaemon(
clientAliveFile: File,
compilerId: CompilerId,
daemonJVMOptions: DaemonJVMOptions,
daemonOptions: DaemonOptions,
messageCollector: MessageCollector,
vararg args: String
): Pair<Int, Collection<OutputMessageUtil.Output>> = runBlocking {
log.info("kotlinCompilerClient.connectToCompileService() call")
val daemon = kotlinCompilerClient.connectToCompileService(
compilerId,
clientAliveFile,
daemonJVMOptions,
daemonOptions,
DaemonReportingTargets(messageCollector = messageCollector),
autostart = true
)
log.info("kotlinCompilerClient.connectToCompileService() called! (daemon = $daemon)")
assertNotNull("failed to connect daemon", daemon)
log.info("runBlocking { ")
log.info("register client...")
daemon?.registerClient(clientAliveFile.absolutePath)
log.info(" client registered")
log.info("} ^ runBlocking")
val outputs = arrayListOf<OutputMessageUtil.Output>()
val code = kotlinCompilerClient.compile(
daemon!!,
CompileService.NO_SESSION,
CompileService.TargetPlatform.JVM,
args,
messageCollector,
{ outFile, srcFiles -> outputs.add(OutputMessageUtil.Output(srcFiles, outFile)) },
reportSeverity = ReportSeverity.DEBUG
)
code to outputs
}
private fun getHelloAppBaseDir(): String = KtTestUtil.getTestDataPathBase() + "/integration/smoke/helloApp"
private fun getSimpleScriptBaseDir(): String = KtTestUtil.getTestDataPathBase() + "/integration/smoke/simpleScript"
private fun run(baseDir: String, logName: String, vararg args: String): Int = runJava(baseDir, logName, *args)
private fun runScriptWithArgs(
testDataDir: String,
logName: String?,
scriptClassName: String,
classpath: List<File>,
vararg arguments: String
) {
val cl = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray())
val scriptClass = cl.loadClass(scriptClassName)
val scriptOut = captureOut { scriptClass.constructors.first().newInstance(arguments) }
if (logName != null) {
val expectedFile = File(testDataDir, logName + ".expected")
val normalizedContent = normalizeOutput(File(testDataDir), "OUT:\n$scriptOut\nReturn code: 0")
KotlinTestUtils.assertEqualsToFile(expectedFile, normalizedContent)
}
}
fun ignore_testHelloAppLocal() {
val messageCollector = TestMessageCollector()
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
val (code, outputs) = compileLocally(
messageCollector, "-include-runtime", File(getHelloAppBaseDir(), "hello.kt").absolutePath,
"-d", jar, "-Xreport-output-files"
)
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(jar, outputs.first().outputFile?.absolutePath)
run(getHelloAppBaseDir(), "hello.run", "-cp", jar, "Hello.HelloKt")
}
private fun terminate(@Suppress("UNUSED_PARAMETER") daemonOptions: DaemonOptions) {
println("\n\nkillall -9 Console && open ${logFiles.joinToString(" ")}\n\n")
log.info("in finally")
// runBlocking {
// log.info("in runBlocking")
// delay(1000L)
// kotlinCompilerClient.shutdownCompileService(compilerId, daemonOptions)
// }
// currentLogFile.delete()
// externalLogFile.delete()
}
fun ignore_testHelloApp() {
withFlagFile(getTestName(true), ".alive") { flagFile ->
log.info("sarting test...")
log.info("assigning daemonOptions")
val daemonOptions = DaemonOptions(
runFilesPath = File(tmpdir, getTestName(true)).absolutePath,
verbose = true,
reportPerf = true
)
log.info("daemonOptions assigned")
log.info("creating daemonJVMOptions")
val daemonJVMOptions = configureDaemonJVMOptions(
"D${CompilerSystemProperties.COMPILE_DAEMON_LOG_PATH_PROPERTY.property}=\"${externalLogFile.loggerCompatiblePath}\"",
inheritMemoryLimits = false,
inheritOtherJvmOptions = false,
inheritAdditionalProperties = false
)
log.info("daemonJVMOptions created")
log.info("creating jar")
val jar = tmpdir.absolutePath + File.separator + "hello.jar"
log.info("jar created")
try {
log.info("compileOnDaemon call")
val (code, outputs) = compileOnDaemon(
flagFile,
compilerId,
daemonJVMOptions,
daemonOptions,
TestMessageCollector(),
"-include-runtime",
File(getHelloAppBaseDir(), "hello.kt").absolutePath,
"-d",
jar,
"-Xreport-output-files"
)
log.info("compileOnDaemon called")
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(jar, outputs.first().outputFile?.absolutePath)
run(getHelloAppBaseDir(), "hello.run", "-cp", jar, "Hello.HelloKt")
} finally {
terminate(daemonOptions)
}
println("test passed")
}
}
fun ignore_testSimpleScriptLocal() {
val messageCollector = TestMessageCollector()
val (code, outputs) = compileLocally(
messageCollector,
File(getSimpleScriptBaseDir(), "script.kts").absolutePath,
"-d",
tmpdir.absolutePath,
"-Xreport-output-files"
)
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(File(tmpdir, "Script.class").absolutePath, outputs.first().outputFile?.absolutePath)
runScriptWithArgs(getSimpleScriptBaseDir(), "script", "Script", scriptRuntimeClassPath + tmpdir, "hi", "there")
}
fun ignore_testSimpleScript() {
withFlagFile(getTestName(true), ".alive") { flagFile ->
val daemonOptions = DaemonOptions(
runFilesPath = File(tmpdir, getTestName(true)).absolutePath,
verbose = true,
reportPerf = true
)
val daemonJVMOptions = configureDaemonJVMOptions(
"D${CompilerSystemProperties.COMPILE_DAEMON_LOG_PATH_PROPERTY.property}=\"${externalLogFile.loggerCompatiblePath}\"",
inheritMemoryLimits = false, inheritOtherJvmOptions = false, inheritAdditionalProperties = false
)
try {
val (code, outputs) = compileOnDaemon(
flagFile,
compilerId,
daemonJVMOptions,
daemonOptions,
TestMessageCollector(),
File(getSimpleScriptBaseDir(), "script.kts").absolutePath,
"-Xreport-output-files",
"-d",
tmpdir.absolutePath
)
Assert.assertEquals(0, code)
Assert.assertTrue(outputs.isNotEmpty())
Assert.assertEquals(File(tmpdir, "Script.class").absolutePath, outputs.first().outputFile?.absolutePath)
runScriptWithArgs(getSimpleScriptBaseDir(), "script", "Script", scriptRuntimeClassPath + tmpdir, "hi", "there")
} finally {
terminate(daemonOptions)
}
}
}
}
class TestMessageCollector : MessageCollector {
data class Message(val severity: CompilerMessageSeverity, val message: String, val location: CompilerMessageSourceLocation?)
val messages = arrayListOf<Message>()
override fun clear() {
messages.clear()
}
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
messages.add(Message(severity, message, location))
}
override fun hasErrors(): Boolean =
messages.any { it.severity == CompilerMessageSeverity.EXCEPTION || it.severity == CompilerMessageSeverity.ERROR }
override fun toString(): String {
return messages.joinToString("\n") { "${it.severity}: ${it.message}${it.location?.let { " at $it" } ?: ""}" }
}
}
fun TestMessageCollector.assertHasMessage(msg: String, desiredSeverity: CompilerMessageSeverity? = null) {
assert(messages.any { it.message.contains(msg) && (desiredSeverity == null || it.severity == desiredSeverity) }) {
"Expecting message \"$msg\" with severity ${desiredSeverity?.toString() ?: "Any"}, actual:\n" +
messages.joinToString("\n") { it.severity.toString() + ": " + it.message }
}
}
@@ -1,100 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.experimental.unit
import io.ktor.network.sockets.aSocket
import io.ktor.util.*
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.daemon.common.experimental.CompilerServicesFacadeBaseClientSideImpl
import org.jetbrains.kotlin.daemon.common.experimental.LoopbackNetworkInterfaceKtor.selectorMgr
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.DefaultClient
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.ServerBase
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.openIO
import org.jetbrains.kotlin.daemon.common.experimental.socketInfrastructure.runWithTimeout
import org.jetbrains.kotlin.daemon.common.toRMI
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.test.IgnoreAll
import org.junit.runner.RunWith
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.net.InetSocketAddress
import java.util.logging.Logger
import kotlin.io.path.*
@OptIn(KtorExperimentalAPI::class)
class TestServer(val serverPort: Int = 6999) {
private val serverSocket = aSocket(selectorMgr).tcp().bind(InetSocketAddress(serverPort))
private val log = Logger.getLogger("TestServer")
@OptIn(DelicateCoroutinesApi::class)
fun awaitClient() = GlobalScope.async {
log.info("accepting clientSocket...")
val client = serverSocket.accept()
log.info("client accepted! (${client.remoteAddress})")
client.openIO(log)
true
}
}
val testServer = TestServer()
@RunWith(IgnoreAll::class)
@Suppress("UNCHECKED_CAST")
@OptIn(ExperimentalPathApi::class)
class ClientSerializationTest : KotlinIntegrationTestBase() {
val file = createTempFile()
val log = Logger.getLogger("ClientSerializationTest")
private inline fun <reified T> abstractSerializationTest(initClient: () -> T, vararg additionalTests: (T, T) -> Unit) {
val client = initClient()
log.info("created")
file.outputStream().use {
ObjectOutputStream(it).use {
it.writeObject(client)
}
}
log.info("printed")
var client2: T?
var connected = false
runBlocking {
val clientAwait = testServer.awaitClient()
client2 = file.inputStream().use {
ObjectInputStream(it).use {
it.readObject() as T
}
}
connected = runWithTimeout { clientAwait.await() } ?: false
}
assert(connected)
log.info("read")
assert(client2 != null)
additionalTests.forEach { it(client, client2!!) }
log.info("test passed")
}
fun ignore_testDefaultClient() = abstractSerializationTest(
{ DefaultClient<ServerBase>(testServer.serverPort) },
{ client, client2 -> assert(client.serverPort == client2.serverPort) },
{ _, client2 ->
client2.log.info("abacaba (2)")
log.info("test passed")
}
)
fun ignore_testCompilerServicesFacadeBaseClientSide() = abstractSerializationTest(
{ CompilerServicesFacadeBaseClientSideImpl(testServer.serverPort) },
{ client, client2 -> assert(client.serverPort == client2.serverPort) }
)
fun ignore_testRMIWrapper() = abstractSerializationTest({ CompilerServicesFacadeBaseClientSideImpl(testServer.serverPort).toRMI() })
}
@@ -1,396 +0,0 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.daemon.experimental.unit
import kotlinx.coroutines.*
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
import org.jetbrains.kotlin.daemon.CompileServiceImpl
import org.jetbrains.kotlin.daemon.CompilerSelector
import org.jetbrains.kotlin.daemon.client.KotlinCompilerDaemonClient
import org.jetbrains.kotlin.daemon.client.experimental.BasicCompilerServicesWithResultsFacadeServerServerSide
import org.jetbrains.kotlin.daemon.common.*
import org.jetbrains.kotlin.daemon.common.experimental.DaemonWithMetadataAsync
import org.jetbrains.kotlin.daemon.common.experimental.findCallbackServerSocket
import org.jetbrains.kotlin.daemon.common.experimental.findPortForSocket
import org.jetbrains.kotlin.daemon.common.experimental.walkDaemonsAsync
import org.jetbrains.kotlin.daemon.experimental.CompileServiceServerSideImpl
import org.jetbrains.kotlin.daemon.loggerCompatiblePath
import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase
import org.jetbrains.kotlin.test.IgnoreAll
import org.jetbrains.kotlin.test.util.KtTestUtil
import org.junit.runner.RunWith
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import java.io.PrintStream
import java.nio.file.Path
import java.util.*
import java.util.logging.LogManager
import java.util.logging.Logger
import kotlin.concurrent.schedule
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createTempFile
import kotlin.io.path.deleteIfExists
@OptIn(ExperimentalPathApi::class)
@RunWith(IgnoreAll::class)
class ConnectionsTest : KotlinIntegrationTestBase() {
val kotlinCompilerClient = KotlinCompilerDaemonClient.instantiate(DaemonProtocolVariant.SOCKETS)
private val logFile = createTempFile("/Users/jetbrains/Documents/kotlin/my_fork/kotlin", ".txt")
private val cfg = "handlers = java.util.logging.FileHandler\n" +
"java.util.logging.FileHandler.level = ALL\n" +
"java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter\n" +
"java.util.logging.FileHandler.encoding = UTF-8\n" +
"java.util.logging.FileHandler.limit = 0\n" + // if file is provided - disabled, else - 1Mb
"java.util.logging.FileHandler.count = 1\n" +
"java.util.logging.FileHandler.append = true\n" +
"java.util.logging.FileHandler.pattern = ${logFile.loggerCompatiblePath}\n" +
"java.util.logging.SimpleFormatter.format = %1\$tF %1\$tT.%1\$tL [%3\$s] %4\$s: %5\$s%n\n"
init {
LogManager.getLogManager().readConfiguration(cfg.byteInputStream())
}
val log by lazy { Logger.getLogger("ConnectionsTest") }
private val daemonJVMOptions by lazy {
configureDaemonJVMOptions(
inheritMemoryLimits = true,
inheritOtherJvmOptions = true,
inheritAdditionalProperties = true
)
}
private val compilerId by lazy { CompilerId() }
private val daemonOptions by lazy { DaemonOptions() }
private val port
get() = findPortForSocket(
COMPILE_DAEMON_FIND_PORT_ATTEMPTS,
COMPILE_DAEMON_PORTS_RANGE_START,
COMPILE_DAEMON_PORTS_RANGE_END
)
private val timer by lazy { Timer(true) }
private val runFile by lazy {
val runFileDir = File(daemonOptions.runFilesPathOrDefault)
runFileDir.mkdirs()
File(
runFileDir,
makeRunFilenameString(
timestamp = "%tFT%<tH-%<tM-%<tS.%<tLZ".format(Calendar.getInstance(TimeZone.getTimeZone("Z"))),
digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(),
port = port.toString()
)
)
}
private val onShutdown: () -> Unit = {
if (daemonOptions.forceShutdownTimeoutMilliseconds != COMPILE_DAEMON_TIMEOUT_INFINITE_MS) {
// running a watcher thread that ensures that if the daemon is not exited normally (may be due to RMI leftovers), it's forced to exit
timer.schedule(daemonOptions.forceShutdownTimeoutMilliseconds) {
cancel()
org.jetbrains.kotlin.daemon.KotlinCompileDaemon.log.info("force JVM shutdown")
System.exit(0)
}
} else {
timer.cancel()
}
}
private fun getNewDaemonsOrAsyncWrappers() = runBlocking {
walkDaemonsAsync(
File(daemonOptions.runFilesPathOrDefault),
compilerId,
runFile,
filter = { _, _ -> true },
report = { _, msg -> log.info(msg) },
useRMI = true,
useSockets = true
).toList()
}
private fun getOldDaemonsOrRMIWrappers() = runBlocking {
walkDaemons(
File(daemonOptions.runFilesPathOrDefault),
compilerId,
runFile,
filter = { _, _ -> true },
report = { _, msg -> log.info(msg) }
).toList()
}
companion object {
}
private fun runNewServer(): Deferred<Unit> =
port.let { serverPort ->
CompileServiceServerSideImpl(
serverPort,
compilerId,
daemonOptions,
daemonJVMOptions,
serverPort.port,
timer,
onShutdown
).let {
log.info("service created")
it.startDaemonElections()
it.configurePeriodicActivities()
it.runServer()
}
}
private fun runOldServer() {
val (registry, serverPort) = findPortAndCreateRegistry(
COMPILE_DAEMON_FIND_PORT_ATTEMPTS,
COMPILE_DAEMON_PORTS_RANGE_START,
COMPILE_DAEMON_PORTS_RANGE_END
)
val compilerSelector = object : CompilerSelector {
private val jvm by lazy { K2JVMCompiler() }
private val js by lazy { K2JSCompiler() }
private val metadata by lazy { K2MetadataCompiler() }
override fun get(targetPlatform: CompileService.TargetPlatform): CLICompiler<*> = when (targetPlatform) {
CompileService.TargetPlatform.JVM -> jvm
CompileService.TargetPlatform.JS -> js
CompileService.TargetPlatform.METADATA -> metadata
}
}
log.info("old server run: (port= $serverPort, reg= $registry)")
CompileServiceImpl(
registry = registry,
compiler = compilerSelector,
compilerId = compilerId,
daemonOptions = daemonOptions,
daemonJVMOptions = daemonJVMOptions,
port = serverPort,
timer = timer,
onShutdown = onShutdown
).let {
it.startDaemonElections()
it.configurePeriodicActivities()
}
}
val comparator = compareByDescending<DaemonWithMetadataAsync, DaemonJVMOptions>(
DaemonJVMOptionsMemoryComparator(),
{ it.jvmOptions }
)
.thenBy {
when (it.daemon) {
is CompileServiceAsyncWrapper -> 0
else -> 1
}
}
.thenBy(FileAgeComparator()) { it.runFile }
.thenBy { it.daemon.serverPort }
private fun <DaemonWithMeta, Daemon> expectDaemon(
getDaemons: () -> List<DaemonWithMeta>,
chooseDaemon: (List<DaemonWithMeta>) -> Daemon,
getInfo: (Daemon) -> CompileService.CallResult<String>,
registerClient: (Daemon) -> Unit,
port: (Daemon) -> Int,
expectedDaemonCount: Int?,
extraAction: (Daemon) -> Unit = {}
) {
val daemons = getDaemons()
log.info("daemons (${daemons.size}) : ${daemons.map { (it ?: 0)::class.java.name }.toList()}\n\n")
expectedDaemonCount?.let {
log.info("expected $it daemons, found ${daemons.size}")
assertTrue(
"daemons.size : ${daemons.size}, but expected : $expectedDaemonCount",
daemons.size == it
)
}
val daemon = chooseDaemon(daemons)
log.info("chosen : $daemon (port = ${port(daemon)})")
val info = getInfo(daemon)
log.info("info : $info")
assertTrue("bad info", info.isGood)
registerClient(daemon)
extraAction(daemon)
}
private enum class ServerType(val instancesNumber: Int?) {
OLD(1), NEW(2), ANY(null)
}
private fun expectNewDaemon(serverType: ServerType, extraAction: (CompileServiceAsync) -> Unit = {}) = expectDaemon(
getDaemons = ::getNewDaemonsOrAsyncWrappers,
chooseDaemon = { daemons -> daemons.maxWithOrNull(comparator)!!.daemon },
getInfo = { d -> runBlocking { d.getDaemonInfo() } },
registerClient = { d -> runBlocking { d.registerClient(generateClient()) } },
port = { d -> d.serverPort },
expectedDaemonCount = serverType.instancesNumber,
extraAction = extraAction
)
private fun expectOldDaemon(shouldCheckNumber: Boolean = true, extraAction: (CompileService) -> Unit = {}) = expectDaemon(
::getOldDaemonsOrRMIWrappers,
{ daemons -> daemons[0].daemon },
{ d -> d.getDaemonInfo() },
{ d -> d.registerClient(generateClient()) },
{ _ -> -1 },
1.takeIf { shouldCheckNumber },
extraAction
)
private val clientFiles = mutableListOf<Path>()
private fun generateClient(): String {
val file = createTempFile(getTestName(true), ".alive")
clientFiles.add(file)
return file.toAbsolutePath().toString()
}
private fun deleteClients() {
clientFiles.forEach { it.deleteIfExists() }
}
private fun endTest() {
deleteClients()
}
fun ignore_testConnectionMechanism_OldClient_OldServer() {
runOldServer()
expectOldDaemon()
endTest()
}
fun ignore_testConnectionMechanism_NewClient_NewServer() {
runNewServer()
expectNewDaemon(ServerType.NEW)
endTest()
}
fun ignore_testConnectionMechanism_OldClient_NewServer() {
runNewServer()
expectOldDaemon()
endTest()
}
fun ignore_testConnectionMechanism_NewClient_OldServer() {
runOldServer()
expectNewDaemon(ServerType.OLD)
endTest()
}
fun ignore_testConnections_OldDaemon_DifferentClients() {
runOldServer()
(0..20).forEach {
expectNewDaemon(ServerType.OLD)
expectOldDaemon()
}
endTest()
}
fun ignore_testConnections_NewDaemon_DifferentClients() {
runNewServer()
(0..4).forEach {
expectNewDaemon(ServerType.NEW)
expectOldDaemon()
}
endTest()
}
fun ignore_testConnections_MultipleDaemons_MultipleClients() {
(0..3).forEach {
runNewServer()
runOldServer()
}
(0..4).forEach {
expectNewDaemon(ServerType.ANY)
expectOldDaemon(shouldCheckNumber = false)
}
endTest()
}
fun ignore_testShutdown() {
runNewServer()
expectNewDaemon(ServerType.NEW) { daemon ->
runBlocking {
daemon.shutdown()
delay(1000L)
val mem: Long = try {
daemon.getUsedMemory().get()
} catch (e: IOException) {
-100500L
}
assertTrue(mem == -100500L)
}
}
}
fun ignore_testCompile() {
runNewServer()
expectNewDaemon(ServerType.NEW) { daemon ->
runBlocking {
assertTrue("daemon is wrapper", daemon !is CompileServiceAsyncWrapper)
val outStream = ByteArrayOutputStream()
val msgCollector = PrintingMessageCollector(PrintStream(outStream), MessageRenderer.WITHOUT_PATHS, true)
val codes = (0 until 10).toMutableList()
val services = BasicCompilerServicesWithResultsFacadeServerServerSide(
msgCollector,
{ _, _ -> },
findCallbackServerSocket()
)
services.runServer()
val servicesClient = services.clientSide
val compResultsClient = kotlinCompilerClient.createCompResults().clientSide
val threadCount = 10
@OptIn(ObsoleteCoroutinesApi::class)
fun runThread(i: Int) =
async(newSingleThreadContext("thread_$i")) {
val jar = tmpdir.absolutePath + File.separator + "hello.$i.jar"
val code =
daemon.compile(
CompileService.NO_SESSION,
arrayOf(
"-include-runtime",
File(KtTestUtil.getTestDataPathBase() + "/integration/smoke/helloApp", "hello.kt").absolutePath,
"-d",
jar
),
CompilationOptions(
CompilerMode.NON_INCREMENTAL_COMPILER,
CompileService.TargetPlatform.JVM,
arrayOf(
ReportCategory.COMPILER_MESSAGE.code,
ReportCategory.DAEMON_MESSAGE.code,
ReportCategory.EXCEPTION.code,
ReportCategory.OUTPUT_MESSAGE.code
),
ReportSeverity.INFO.code,
emptyArray()
),
servicesClient,
compResultsClient
).get()
codes[i] = code
}
(0 until threadCount).map(::runThread).map { it.await() }
assertTrue("not-null code", codes.all { it == 0 })
}
}
}
}