Tests: compute runtime classpath for JVM box tests manually

Taking just the `jvmClasspathRoots` is not correct because it also
contains stuff needed for resolve to work correctly, such as JDK (full
or mock), stdlib (full or mock), reflect. JDK is obviously not needed in
the classpath, and stdlib/reflect are available via the parent class
loader, which is specifically reused across all tests to make them run
faster.

Also, don't try to create class loader for Java-only modules in
`JvmBoxRunner.processModule`. This happens, for example, for all tests
which were moved from `boxAgainstJava`.
This commit is contained in:
Alexander Udalov
2021-02-05 19:02:23 +01:00
parent df42868874
commit aaecb87d1b
2 changed files with 34 additions and 10 deletions
@@ -23,6 +23,11 @@ data class TestModule(
val directives: RegisteredDirectives,
val languageVersionSettings: LanguageVersionSettings
) {
override fun equals(other: Any?): Boolean =
other is TestModule && name == other.name
override fun hashCode(): Int = name.hashCode()
override fun toString(): String {
return buildString {
appendLine("Module: $name")
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.test.backend.handlers
import junit.framework.TestCase
import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberDeclarationsToGenerate
import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil.getFileClassInfoNoResolve
@@ -15,11 +14,14 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.clientserver.TestProxy
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.model.BinaryArtifacts
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator.Companion.TEST_CONFIGURATION_KIND_KEY
import org.jetbrains.kotlin.test.services.dependencyProvider
import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import java.io.File
import java.lang.reflect.Method
@@ -40,7 +42,7 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe
}
override fun processModule(module: TestModule, info: BinaryArtifacts.Jvm) {
val ktFiles = info.classFileFactory.inputFiles
val ktFiles = info.classFileFactory.inputFiles.ifEmpty { return }
val reportProblems = module.targetBackend !in module.directives[CodegenTestDirectives.IGNORE_BACKEND]
val classLoader = createAndVerifyClassLoader(module, info.classFileFactory, reportProblems)
try {
@@ -162,21 +164,38 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe
return classLoader
}
@OptIn(ExperimentalStdlibApi::class)
private fun createClassLoader(module: TestModule, classFileFactory: ClassFileFactory): GeneratedClassLoader {
val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
val urls = buildList {
addAll(configuration.jvmClasspathRoots)
testServices.compiledClassesManager.getCompiledJavaDirForModule(module)?.let {
add(it)
}
}.map { it.toURI().toURL() }
val parentClassLoader = if (configuration[TEST_CONFIGURATION_KIND_KEY]?.withReflection == true) {
ForTestCompileRuntime.runtimeAndReflectJarClassLoader()
} else {
ForTestCompileRuntime.runtimeJarClassLoader()
}
return GeneratedClassLoader(classFileFactory, parentClassLoader, *urls.toTypedArray())
val classpath = computeRuntimeClasspath(module)
return GeneratedClassLoader(classFileFactory, parentClassLoader, *classpath.map { it.toURI().toURL() }.toTypedArray())
}
private fun computeRuntimeClasspath(rootModule: TestModule): List<File> {
val visited = mutableSetOf<TestModule>()
val result = mutableListOf<File>()
fun computeClasspath(module: TestModule, isRoot: Boolean) {
if (!visited.add(module)) return
if (!isRoot) {
result.add(testServices.compiledClassesManager.getCompiledKotlinDirForModule(module))
}
result.addIfNotNull(testServices.compiledClassesManager.getCompiledJavaDirForModule(module))
for (dependency in module.dependencies + module.friends) {
if (dependency.kind == DependencyKind.Binary) {
computeClasspath(testServices.dependencyProvider.getTestModule(dependency.moduleName), false)
}
}
}
computeClasspath(rootModule, true)
return result
}
private fun KtFile.getFacadeFqName(): String? {