ENT-3266: Do not attempt to overrwite an existing CorDapp jar in tests (#1906)

There's a bug with the ServiceLoader which leaks a file handle to the app jar on shutdown. This causes an issue if a mock node is restarted in Windows. To avoid the problem completely we no longer overwrite any existing jars, as the jar to be copied will be same anyway.
This commit is contained in:
Shams Asari 2019-03-06 20:27:10 +00:00 committed by GitHub
parent 2f8280d7c6
commit 0038a86481
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 13 deletions

View File

@ -144,7 +144,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
findServiceFlows(this),
findSchedulableFlows(this),
findServices(this),
findPlugins(url),
findWhitelists(url),
findSerializers(this),
findCustomSchemas(this),
findAllFlows(this),
@ -267,7 +267,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
return contractClasses
}
private fun findPlugins(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
private fun findWhitelists(cordappJarPath: RestrictedURL): List<SerializationWhitelist> {
val whitelists = URLClassLoader(arrayOf(cordappJarPath.url)).use {
ServiceLoader.load(SerializationWhitelist::class.java, it).toList()
}
@ -306,6 +306,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
}
}
// TODO Remove this class as rootPackageName is never non-null.
/** @property rootPackageName only this package and subpackages may be extracted from [url], or null to allow all packages. */
private data class RestrictedURL(val url: URL, val rootPackageName: String?) {
val qualifiedNamePrefix: String get() = rootPackageName?.let { "$it." } ?: ""
@ -359,14 +360,14 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
fun getAllStandardClasses(): List<String> {
return scanResult
.getAllStandardClasses()
.allStandardClasses
.names
.filter { it.startsWith(qualifiedNamePrefix) }
}
fun getAllInterfaces(): List<String> {
return scanResult
.getAllInterfaces()
.allInterfaces
.names
.filter { it.startsWith(qualifiedNamePrefix) }
}
@ -400,13 +401,14 @@ abstract class CordappLoaderTemplate : CordappLoader {
logger.error("There are multiple CorDapp JARs on the classpath for flow " +
"${entry.value.first().first.name}: [ ${entry.value.joinToString { it.second.jarPath.toString() }} ].")
entry.value.forEach { (_, cordapp) ->
val zip = ZipInputStream(cordapp.jarPath.openStream())
val ident = BigInteger(64, Random()).toString(36)
logger.error("Contents of: ${cordapp.jarPath} will be prefaced with: ${ident}")
var e = zip.nextEntry
while (e != null) {
logger.error("$ident\t ${e.name}")
e = zip.nextEntry
ZipInputStream(cordapp.jarPath.openStream()).use { zip ->
val ident = BigInteger(64, Random()).toString(36)
logger.error("Contents of: ${cordapp.jarPath} will be prefaced with: $ident")
var e = zip.nextEntry
while (e != null) {
logger.error("$ident\t ${e.name}")
e = zip.nextEntry
}
}
}
throw MultipleCordappsForFlowException("There are multiple CorDapp JARs on the classpath for flow " +

View File

@ -6,8 +6,8 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.writeText
import net.corda.testing.node.TestCordapp
import java.nio.file.FileAlreadyExistsException
import java.nio.file.Path
import java.nio.file.StandardCopyOption.REPLACE_EXISTING
/**
* Extends the public [TestCordapp] API with internal extensions for use within the testing framework and for internal testing of the platform.
@ -36,7 +36,11 @@ abstract class TestCordappInternal : TestCordapp() {
val configDir = (cordappsDir / "config").createDirectories()
jarToCordapp.forEach { jar, cordapp ->
jar.copyToDirectory(cordappsDir, REPLACE_EXISTING)
try {
jar.copyToDirectory(cordappsDir)
} catch (e: FileAlreadyExistsException) {
// Ignore if the node already has the same CorDapp jar. This can happen if the node is being restarted.
}
val configString = ConfigValueFactory.fromMap(cordapp.config).toConfig().root().render()
(configDir / "${jar.fileName.toString().removeSuffix(".jar")}.conf").writeText(configString)
}