Scripting: fix loadDependencies property use with cached scripts
#KT-50902 fixed
This commit is contained in:
+62
-11
@@ -13,12 +13,14 @@ import org.junit.Assert
|
|||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.net.URLClassLoader
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import kotlin.script.experimental.api.*
|
import kotlin.script.experimental.api.*
|
||||||
import kotlin.script.experimental.host.toScriptSource
|
import kotlin.script.experimental.host.toScriptSource
|
||||||
import kotlin.script.experimental.host.with
|
import kotlin.script.experimental.host.with
|
||||||
import kotlin.script.experimental.jvm.*
|
import kotlin.script.experimental.jvm.*
|
||||||
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
|
||||||
|
import kotlin.script.experimental.jvm.loadDependencies
|
||||||
import kotlin.script.experimental.jvm.util.KotlinJars
|
import kotlin.script.experimental.jvm.util.KotlinJars
|
||||||
import kotlin.script.experimental.jvm.util.classpathFromClass
|
import kotlin.script.experimental.jvm.util.classpathFromClass
|
||||||
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
|
||||||
@@ -130,17 +132,7 @@ class CachingTest : TestCase() {
|
|||||||
fun ignoredTestLocalDependencyWithJarCacheInvalidation() {
|
fun ignoredTestLocalDependencyWithJarCacheInvalidation() {
|
||||||
withTempDir("scriptingTestDepDir") { depDir ->
|
withTempDir("scriptingTestDepDir") { depDir ->
|
||||||
val standardJars = KotlinJars.kotlinScriptStandardJars
|
val standardJars = KotlinJars.kotlinScriptStandardJars
|
||||||
val outJar = File(depDir, "dependency.jar")
|
val outJar = makeDependenciesJar(depDir, standardJars)
|
||||||
val inKt = File(depDir, "Dependency.kt").apply { writeText("class Dependency(val v: Int)") }
|
|
||||||
val outStream = ByteArrayOutputStream()
|
|
||||||
val compileExitCode = K2JVMCompiler().exec(
|
|
||||||
PrintStream(outStream),
|
|
||||||
"-d", outJar.path, "-no-stdlib", "-cp", standardJars.joinToString(File.pathSeparator), inKt.path
|
|
||||||
)
|
|
||||||
assertTrue(
|
|
||||||
"Compilation Failed:\n$outStream",
|
|
||||||
outStream.size() == 0 && compileExitCode == ExitCode.OK && outJar.exists()
|
|
||||||
)
|
|
||||||
|
|
||||||
withTempDir("scriptingTestJarChacheWithDep") { cacheDir ->
|
withTempDir("scriptingTestJarChacheWithDep") { cacheDir ->
|
||||||
val cache = TestCompiledScriptJarsCache(cacheDir)
|
val cache = TestCompiledScriptJarsCache(cacheDir)
|
||||||
@@ -188,6 +180,65 @@ class CachingTest : TestCase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLocalDependencyWithExternalLoadAndCache() {
|
||||||
|
withTempDir("scriptingTestDepDir") { depDir ->
|
||||||
|
val standardJars = KotlinJars.kotlinScriptStandardJars
|
||||||
|
val outJar = makeDependenciesJar(depDir, standardJars)
|
||||||
|
|
||||||
|
withTempDir("scriptingTestJarChacheWithExtLoadedDep") { cacheDir ->
|
||||||
|
val cache = TestCompiledScriptJarsCache(cacheDir)
|
||||||
|
Assert.assertTrue(cache.baseDir.listFiles()!!.isEmpty())
|
||||||
|
|
||||||
|
val hostConfiguration = defaultJvmScriptingHostConfiguration.with {
|
||||||
|
jvm {
|
||||||
|
baseClassLoader(URLClassLoader((standardJars + outJar).map { it.toURI().toURL() }.toTypedArray(), null))
|
||||||
|
compilationCache(cache)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val host = BasicJvmScriptingHost(compiler = JvmScriptCompiler(hostConfiguration), evaluator = BasicJvmScriptEvaluator())
|
||||||
|
|
||||||
|
val scriptCompilationConfiguration = ScriptCompilationConfiguration {
|
||||||
|
updateClasspath(standardJars + outJar)
|
||||||
|
this.hostConfiguration.update { hostConfiguration }
|
||||||
|
}
|
||||||
|
val scriptEvaluationConfiguration = ScriptEvaluationConfiguration {
|
||||||
|
jvm {
|
||||||
|
loadDependencies(false)
|
||||||
|
}
|
||||||
|
this.hostConfiguration.update { hostConfiguration }
|
||||||
|
}
|
||||||
|
|
||||||
|
val script = "Dependency(42).v".toScriptSource()
|
||||||
|
|
||||||
|
// Without the patch that fixes loadDependencies usage in kotlin.script.experimental.jvmhost.KJvmCompiledScriptLazilyLoadedFromClasspath.getClass
|
||||||
|
// AND with hostConfiguration removed from scriptEvaluationConfiguration (essentially creating a misconfigured evaluator)
|
||||||
|
// the first evaluation fails because it cannot find the class for dependency, but the second mistakingly succeed, because dependency is taken from the cache
|
||||||
|
// (see #KT-50902 for details)
|
||||||
|
val res0 = host.eval(script, scriptCompilationConfiguration, scriptEvaluationConfiguration).valueOrThrow().returnValue
|
||||||
|
assertEquals(42, (res0 as? ResultValue.Value)?.value)
|
||||||
|
|
||||||
|
val res1 = host.eval(script, scriptCompilationConfiguration, scriptEvaluationConfiguration).valueOrThrow().returnValue
|
||||||
|
assertEquals(42, (res1 as? ResultValue.Value)?.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeDependenciesJar(depDir: File, standardJars: List<File>): File {
|
||||||
|
val outJar = File(depDir, "dependency.jar")
|
||||||
|
val inKt = File(depDir, "Dependency.kt").apply { writeText("class Dependency(val v: Int)") }
|
||||||
|
val outStream = ByteArrayOutputStream()
|
||||||
|
val compileExitCode = K2JVMCompiler().exec(
|
||||||
|
PrintStream(outStream),
|
||||||
|
"-d", outJar.path, "-no-stdlib", "-cp", standardJars.joinToString(File.pathSeparator), inKt.path
|
||||||
|
)
|
||||||
|
assertTrue(
|
||||||
|
"Compilation Failed:\n$outStream",
|
||||||
|
outStream.size() == 0 && compileExitCode == ExitCode.OK && outJar.exists()
|
||||||
|
)
|
||||||
|
return outJar
|
||||||
|
}
|
||||||
|
|
||||||
private fun checkWithCache(
|
private fun checkWithCache(
|
||||||
cache: ScriptingCacheWithCounters, script: SourceCode, expectedOutput: List<String>, checkDirectEval: Boolean = true,
|
cache: ScriptingCacheWithCounters, script: SourceCode, expectedOutput: List<String>, checkDirectEval: Boolean = true,
|
||||||
compilationConfiguration: ScriptCompilationConfiguration.Builder.() -> Unit = {},
|
compilationConfiguration: ScriptCompilationConfiguration.Builder.() -> Unit = {},
|
||||||
|
|||||||
+3
-1
@@ -20,6 +20,7 @@ import kotlin.script.experimental.jvm.JvmDependency
|
|||||||
import kotlin.script.experimental.jvm.baseClassLoader
|
import kotlin.script.experimental.jvm.baseClassLoader
|
||||||
import kotlin.script.experimental.jvm.impl.*
|
import kotlin.script.experimental.jvm.impl.*
|
||||||
import kotlin.script.experimental.jvm.jvm
|
import kotlin.script.experimental.jvm.jvm
|
||||||
|
import kotlin.script.experimental.jvm.loadDependencies
|
||||||
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrNull
|
import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrNull
|
||||||
|
|
||||||
// TODO: generate execution code (main)
|
// TODO: generate execution code (main)
|
||||||
@@ -145,8 +146,9 @@ private class KJvmCompiledScriptLazilyLoadedFromClasspath(
|
|||||||
if (loadedScript == null) {
|
if (loadedScript == null) {
|
||||||
val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration()
|
val actualEvaluationConfiguration = scriptEvaluationConfiguration ?: ScriptEvaluationConfiguration()
|
||||||
val baseClassLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]
|
val baseClassLoader = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.baseClassLoader]
|
||||||
|
val loadDependencies = actualEvaluationConfiguration[ScriptEvaluationConfiguration.jvm.loadDependencies]!!
|
||||||
val classLoader = URLClassLoader(
|
val classLoader = URLClassLoader(
|
||||||
classPath.map { it.toURI().toURL() }.toTypedArray(),
|
classPath.let { if (loadDependencies) it else it.take(1) }.map { it.toURI().toURL() }.toTypedArray(),
|
||||||
baseClassLoader
|
baseClassLoader
|
||||||
)
|
)
|
||||||
loadedScript = createScriptFromClassLoader(scriptClassFQName, classLoader)
|
loadedScript = createScriptFromClassLoader(scriptClassFQName, classLoader)
|
||||||
|
|||||||
Reference in New Issue
Block a user