Syncing Cordapp info code from ENT so that ENT-1731 is fully ported (#3914)

Also, Cordapp.Info has been made internal as it's not used in the public API
This commit is contained in:
Shams Asari
2018-09-10 10:43:00 +01:00
committed by GitHub
parent 4183d55650
commit 83e66d542d
15 changed files with 113 additions and 93 deletions

View File

@ -48,20 +48,4 @@ interface Cordapp {
val jarPath: URL val jarPath: URL
val cordappClasses: List<String> val cordappClasses: List<String>
val jarHash: SecureHash.SHA256 val jarHash: SecureHash.SHA256
}
/**
* CorDapp's information, including vendor and version.
*
* @property shortName Cordapp's shortName
* @property vendor Cordapp's vendor
* @property version Cordapp's version
*/
@DoNotImplement
interface Info {
val shortName: String
val vendor: String
val version: String
fun hasUnknownFields(): Boolean
}
}

View File

@ -24,25 +24,28 @@ data class CordappImpl(
override val customSchemas: Set<MappedSchema>, override val customSchemas: Set<MappedSchema>,
override val allFlows: List<Class<out FlowLogic<*>>>, override val allFlows: List<Class<out FlowLogic<*>>>,
override val jarPath: URL, override val jarPath: URL,
val info: Info,
override val jarHash: SecureHash.SHA256) : Cordapp { override val jarHash: SecureHash.SHA256) : Cordapp {
override val name: String = jarPath.toPath().fileName.toString().removeSuffix(".jar") override val name: String = jarName(jarPath)
companion object {
fun jarName(url: URL): String = url.toPath().fileName.toString().removeSuffix(".jar")
}
/** /**
* An exhaustive list of all classes relevant to the node within this CorDapp * An exhaustive list of all classes relevant to the node within this CorDapp
* *
* TODO: Also add [SchedulableFlow] as a Cordapp class * TODO: Also add [SchedulableFlow] as a Cordapp class
*/ */
override val cordappClasses = ((rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass }).map { it.name } + contractClassNames) override val cordappClasses: List<String> = (rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass }).map { it.name } + contractClassNames
data class Info(override val shortName: String, override val vendor: String, override val version: String): Cordapp.Info { // TODO Why a seperate Info class and not just have the fields directly in CordappImpl?
data class Info(val shortName: String, val vendor: String, val version: String) {
companion object { companion object {
private const val UNKNOWN_VALUE = "Unknown" private const val UNKNOWN_VALUE = "Unknown"
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE) val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE)
} }
override fun hasUnknownFields(): Boolean { fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
return setOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
}
} }
} }

View File

@ -71,11 +71,22 @@ jar {
exclude "META-INF/*.MF" exclude "META-INF/*.MF"
exclude "META-INF/LICENSE" exclude "META-INF/LICENSE"
exclude "META-INF/NOTICE" exclude "META-INF/NOTICE"
manifest {
attributes(
"Manifest-Version": "1.0",
"Specification-Title": description,
"Specification-Version": version,
"Specification-Vendor": "Corda Open Source",
"Implementation-Title": "$group.$baseName",
)
}
} }
cordapp { cordapp {
info { info {
vendor "R3" name "net/corda/finance"
vendor "Corda Open Source"
} }
} }

View File

@ -14,4 +14,9 @@ data class VersionInfo(
/** The exact version control commit ID of the node build. */ /** The exact version control commit ID of the node build. */
val revision: String, val revision: String,
/** The node vendor */ /** The node vendor */
val vendor: String) val vendor: String) {
companion object {
val UNKNOWN = VersionInfo(1, "Unknown", "Unknown", "Unknown")
}
}

View File

@ -2,6 +2,7 @@ package net.corda.node.cordapp
import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.Cordapp
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.MappedSchema
/** /**
@ -12,7 +13,7 @@ interface CordappLoader {
/** /**
* Returns all [Cordapp]s found. * Returns all [Cordapp]s found.
*/ */
val cordapps: List<Cordapp> val cordapps: List<CordappImpl>
/** /**
* Returns a [ClassLoader] containing all types from all [Cordapp]s. * Returns a [ClassLoader] containing all types from all [Cordapp]s.

View File

@ -88,7 +88,7 @@ class NodeWithInfo(val node: Node, val info: NodeInfo) {
open class Node(configuration: NodeConfiguration, open class Node(configuration: NodeConfiguration,
versionInfo: VersionInfo, versionInfo: VersionInfo,
private val initialiseSerialization: Boolean = true, private val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration) cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo)
) : AbstractNode<NodeInfo>( ) : AbstractNode<NodeInfo>(
configuration, configuration,
createClock(configuration), createClock(configuration),
@ -130,9 +130,11 @@ open class Node(configuration: NodeConfiguration,
} }
private val sameVmNodeCounter = AtomicInteger() private val sameVmNodeCounter = AtomicInteger()
private fun makeCordappLoader(configuration: NodeConfiguration): CordappLoader {
return JarScanningCordappLoader.fromDirectories(configuration.cordappDirectories) private fun makeCordappLoader(configuration: NodeConfiguration, versionInfo: VersionInfo): CordappLoader {
return JarScanningCordappLoader.fromDirectories(configuration.cordappDirectories, versionInfo)
} }
// TODO: make this configurable. // TODO: make this configurable.
const val MAX_RPC_MESSAGE_SIZE = 10485760 const val MAX_RPC_MESSAGE_SIZE = 10485760
} }

View File

@ -10,6 +10,7 @@ import net.corda.cliutils.ExitCodes
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.internal.* import net.corda.core.internal.*
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.internal.errors.AddressBindingException import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.utilities.Try import net.corda.core.utilities.Try
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
@ -325,7 +326,8 @@ open class NodeStartup: CordaCliWrapper("corda", "Runs a Corda Node") {
} }
val nodeInfo = node.start() val nodeInfo = node.start()
Node.printBasicNodeInfo("Loaded CorDapps", node.services.cordappProvider.cordapps.joinToString { it.name }) logLoadedCorDapps(node.services.cordappProvider.cordapps)
node.nodeReadyFuture.thenMatch({ node.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = nodeInfo.legalIdentitiesAndCerts.first().name.organisation val name = nodeInfo.legalIdentitiesAndCerts.first().name.organisation
@ -407,6 +409,17 @@ open class NodeStartup: CordaCliWrapper("corda", "Runs a Corda Node") {
) )
} }
open protected fun logLoadedCorDapps(corDapps: List<CordappImpl>) {
fun CordappImpl.Info.description() = "$shortName version $version by $vendor"
Node.printBasicNodeInfo("Loaded ${corDapps.size} CorDapp(s)", corDapps.map { it.info }.joinToString(", ", transform = CordappImpl.Info::description))
corDapps.map { it.info }.filter { it.hasUnknownFields() }.let { malformed ->
if (malformed.isNotEmpty()) {
logger.warn("Found ${malformed.size} CorDapp(s) with unknown information. They will be unable to run on Corda in the future.")
}
}
}
private fun enforceSingleNodeIsRunning(baseDirectory: Path) { private fun enforceSingleNodeIsRunning(baseDirectory: Path) {
// Write out our process ID (which may or may not resemble a UNIX process id - to us it's just a string) to a // Write out our process ID (which may or may not resemble a UNIX process id - to us it's just a string) to a
// file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already // file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already

View File

@ -8,6 +8,7 @@ import net.corda.core.cordapp.CordappContext
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
import net.corda.core.internal.cordapp.CordappImpl
import net.corda.core.internal.createCordappContext import net.corda.core.internal.createCordappContext
import net.corda.core.node.services.AttachmentId import net.corda.core.node.services.AttachmentId
import net.corda.core.node.services.AttachmentStorage import net.corda.core.node.services.AttachmentStorage
@ -34,7 +35,7 @@ open class CordappProviderImpl(private val cordappLoader: CordappLoader,
/** /**
* Current known CorDapps loaded on this node * Current known CorDapps loaded on this node
*/ */
override val cordapps get() = cordappLoader.cordapps override val cordapps: List<CordappImpl> get() = cordappLoader.cordapps
fun start(whitelistedContractImplementations: Map<String, List<AttachmentId>>) { fun start(whitelistedContractImplementations: Map<String, List<AttachmentId>>) {
cordappAttachments.putAll(loadContractsIntoAttachmentStore()) cordappAttachments.putAll(loadContractsIntoAttachmentStore())

View File

@ -3,8 +3,9 @@ package net.corda.node.internal.cordapp
import net.corda.core.cordapp.Cordapp import net.corda.core.cordapp.Cordapp
import net.corda.core.cordapp.CordappProvider import net.corda.core.cordapp.CordappProvider
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.internal.cordapp.CordappImpl
interface CordappProviderInternal : CordappProvider { interface CordappProviderInternal : CordappProvider {
val cordapps: List<Cordapp> val cordapps: List<CordappImpl>
fun getCordappForFlow(flowLogic: FlowLogic<*>): Cordapp? fun getCordappForFlow(flowLogic: FlowLogic<*>): Cordapp?
} }

View File

@ -14,6 +14,7 @@ import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.SerializeAsToken import net.corda.core.serialization.SerializeAsToken
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.node.VersionInfo
import net.corda.node.cordapp.CordappLoader import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.classloading.requireAnnotation import net.corda.node.internal.classloading.requireAnnotation
import net.corda.nodeapi.internal.coreContractClasses import net.corda.nodeapi.internal.coreContractClasses
@ -24,6 +25,7 @@ import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
import java.nio.file.Path import java.nio.file.Path
import java.util.* import java.util.*
import java.util.jar.JarInputStream
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.streams.toList import kotlin.streams.toList
@ -32,9 +34,10 @@ import kotlin.streams.toList
* *
* @property cordappJarPaths The classpath of cordapp JARs * @property cordappJarPaths The classpath of cordapp JARs
*/ */
class JarScanningCordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>) : CordappLoaderTemplate() { class JarScanningCordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>,
versionInfo: VersionInfo = VersionInfo.UNKNOWN) : CordappLoaderTemplate() {
override val cordapps: List<Cordapp> by lazy { loadCordapps() + coreCordapp } override val cordapps: List<CordappImpl> by lazy { loadCordapps() + coreCordapp }
override val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader) override val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
@ -54,10 +57,9 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
* *
* @param corDappDirectories Directories used to scan for CorDapp JARs. * @param corDappDirectories Directories used to scan for CorDapp JARs.
*/ */
fun fromDirectories(corDappDirectories: Iterable<Path>): CordappLoader { fun fromDirectories(corDappDirectories: Iterable<Path>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): JarScanningCordappLoader {
logger.info("Looking for CorDapps in ${corDappDirectories.distinct().joinToString(", ", "[", "]")}") logger.info("Looking for CorDapps in ${corDappDirectories.distinct().joinToString(", ", "[", "]")}")
return JarScanningCordappLoader(corDappDirectories.distinct().flatMap(this::jarUrlsInDirectory).map { it.restricted() }) return JarScanningCordappLoader(corDappDirectories.distinct().flatMap(this::jarUrlsInDirectory).map { it.restricted() }, versionInfo)
} }
/** /**
@ -65,7 +67,9 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
* *
* @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection. * @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection.
*/ */
fun fromJarUrls(scanJars: List<URL>) = JarScanningCordappLoader(scanJars.map { it.restricted() }) fun fromJarUrls(scanJars: List<URL>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): JarScanningCordappLoader {
return JarScanningCordappLoader(scanJars.map { it.restricted() }, versionInfo)
}
private fun URL.restricted(rootPackageName: String? = null) = RestrictedURL(this, rootPackageName) private fun URL.restricted(rootPackageName: String? = null) = RestrictedURL(this, rootPackageName)
@ -86,31 +90,30 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
ContractUpgradeFlow.Initiate::class.java, ContractUpgradeFlow.Initiate::class.java,
ContractUpgradeFlow.Authorise::class.java, ContractUpgradeFlow.Authorise::class.java,
ContractUpgradeFlow.Deauthorise::class.java) ContractUpgradeFlow.Deauthorise::class.java)
/** A Cordapp representing the core package which is not scanned automatically. */
@VisibleForTesting
internal val coreCordapp = CordappImpl(
contractClassNames = listOf(),
initiatedFlows = listOf(),
rpcFlows = coreRPCFlows,
serviceFlows = listOf(),
schedulableFlows = listOf(),
services = listOf(),
serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(),
customSchemas = setOf(),
allFlows = listOf(),
jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
jarHash = SecureHash.allOnesHash
)
} }
private fun loadCordapps(): List<Cordapp> { /** A Cordapp representing the core package which is not scanned automatically. */
return cordappJarPaths.map { scanCordapp(it).toCordapp(it) } @VisibleForTesting
} internal val coreCordapp = CordappImpl(
contractClassNames = listOf(),
initiatedFlows = listOf(),
rpcFlows = coreRPCFlows,
serviceFlows = listOf(),
schedulableFlows = listOf(),
services = listOf(),
serializationWhitelists = listOf(),
serializationCustomSerializers = listOf(),
customSchemas = setOf(),
info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion),
allFlows = listOf(),
jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
jarHash = SecureHash.allOnesHash
)
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): Cordapp { private fun loadCordapps(): List<CordappImpl> = cordappJarPaths.map { scanCordapp(it).toCordapp(it) }
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
val info = url.url.openStream().let(::JarInputStream).use { it.manifest }.toCordappInfo(CordappImpl.jarName(url.url))
return CordappImpl( return CordappImpl(
findContractClassNames(this), findContractClassNames(this),
findInitiatedFlows(this), findInitiatedFlows(this),
@ -123,6 +126,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
findCustomSchemas(this), findCustomSchemas(this),
findAllFlows(this), findAllFlows(this),
url.url, url.url,
info,
getJarHash(url.url) getJarHash(url.url)
) )
} }
@ -268,24 +272,23 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
class MultipleCordappsForFlowException(message: String) : Exception(message) class MultipleCordappsForFlowException(message: String) : Exception(message)
abstract class CordappLoaderTemplate : CordappLoader { abstract class CordappLoaderTemplate : CordappLoader {
override val flowCordappMap: Map<Class<out FlowLogic<*>>, Cordapp> by lazy { override val flowCordappMap: Map<Class<out FlowLogic<*>>, Cordapp> by lazy {
cordapps.flatMap { corDapp -> corDapp.allFlows.map { flow -> flow to corDapp } } cordapps.flatMap { corDapp -> corDapp.allFlows.map { flow -> flow to corDapp } }
.groupBy { it.first } .groupBy { it.first }
.mapValues { .mapValues { entry ->
if(it.value.size > 1) { throw MultipleCordappsForFlowException("There are multiple CorDapp JARs on the classpath for flow ${it.value.first().first.name}: [ ${it.value.joinToString { it.second.name }} ].") } if (entry.value.size > 1) {
it.value.single().second throw MultipleCordappsForFlowException("There are multiple CorDapp JARs on the classpath for flow " +
"${entry.value.first().first.name}: [ ${entry.value.joinToString { it.second.name }} ].")
}
entry.value.single().second
} }
} }
override val cordappSchemas: Set<MappedSchema> by lazy { override val cordappSchemas: Set<MappedSchema> by lazy {
cordapps.flatMap { it.customSchemas }.toSet() cordapps.flatMap { it.customSchemas }.toSet()
} }
override val appClassLoader: ClassLoader by lazy { override val appClassLoader: ClassLoader by lazy {
URLClassLoader(cordapps.stream().map { it.jarPath }.toTypedArray(), javaClass.classLoader) URLClassLoader(cordapps.stream().map { it.jarPath }.toTypedArray(), javaClass.classLoader)
} }
} }

View File

@ -1,13 +1,10 @@
package net.corda.node.internal.cordapp package net.corda.node.internal.cordapp
import net.corda.core.cordapp.Cordapp
import net.corda.core.internal.cordapp.CordappImpl import net.corda.core.internal.cordapp.CordappImpl
import java.util.*
import java.util.jar.Attributes import java.util.jar.Attributes
import java.util.jar.Manifest import java.util.jar.Manifest
fun createTestManifest(name: String, title: String, version: String, vendor: String): Manifest { fun createTestManifest(name: String, title: String, version: String, vendor: String): Manifest {
val manifest = Manifest() val manifest = Manifest()
// Mandatory manifest attribute. If not present, all other entries are silently skipped. // Mandatory manifest attribute. If not present, all other entries are silently skipped.
@ -27,21 +24,19 @@ fun createTestManifest(name: String, title: String, version: String, vendor: Str
} }
operator fun Manifest.set(key: String, value: String) { operator fun Manifest.set(key: String, value: String) {
mainAttributes.putValue(key, value) mainAttributes.putValue(key, value)
} }
internal fun Manifest?.toCordappInfo(defaultShortName: String): Cordapp.Info { fun Manifest?.toCordappInfo(defaultShortName: String): CordappImpl.Info {
var info = CordappImpl.Info.UNKNOWN
var unknown = CordappImpl.Info.UNKNOWN
(this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName -> (this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName ->
unknown = unknown.copy(shortName = shortName) info = info.copy(shortName = shortName)
} }
this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor -> this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor ->
unknown = unknown.copy(vendor = vendor) info = info.copy(vendor = vendor)
} }
this?.mainAttributes?.getValue("Implementation-Version")?.let { version -> this?.mainAttributes?.getValue("Implementation-Version")?.let { version ->
unknown = unknown.copy(version = version) info = info.copy(version = version)
} }
return unknown return info
} }

View File

@ -58,12 +58,9 @@ class NodeTest {
@Test @Test
fun `generateAndSaveNodeInfo works`() { fun `generateAndSaveNodeInfo works`() {
val configuration = createConfig(ALICE_NAME) val configuration = createConfig(ALICE_NAME)
val platformVersion = 789 val info = VersionInfo(789, "3.0", "SNAPSHOT", "R3")
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use {
val versionInfo = rigorousMock<VersionInfo>().also { val node = Node(configuration, info, initialiseSerialization = false)
doReturn(platformVersion).whenever(it).platformVersion
}
val node = Node(configuration, versionInfo, initialiseSerialization = false)
assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial) assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial)
} }
} }
@ -87,9 +84,8 @@ class NodeTest {
// Save some NodeInfo // Save some NodeInfo
session.save(persistentNodeInfo) session.save(persistentNodeInfo)
} }
val node = Node(configuration, rigorousMock<VersionInfo>().also { val versionInfo = VersionInfo(10, "3.0", "SNAPSHOT", "R3")
doReturn(10).whenever(it).platformVersion val node = Node(configuration, versionInfo, initialiseSerialization = false)
}, initialiseSerialization = false)
assertThat(getAllInfos(it)).isNotEmpty assertThat(getAllInfos(it)).isNotEmpty
node.clearNetworkMapCache() node.clearNetworkMapCache()
assertThat(getAllInfos(it)).isEmpty() assertThat(getAllInfos(it)).isEmpty()
@ -97,7 +93,7 @@ class NodeTest {
} }
@Test @Test
fun `Node can start with multiple keypairs for it's identity`() { fun `Node can start with multiple keypairs for its identity`() {
val configuration = createConfig(ALICE_NAME) val configuration = createConfig(ALICE_NAME)
val (nodeInfo1, _) = createNodeInfoAndSigned(ALICE_NAME) val (nodeInfo1, _) = createNodeInfoAndSigned(ALICE_NAME)
val (nodeInfo2, _) = createNodeInfoAndSigned(ALICE_NAME) val (nodeInfo2, _) = createNodeInfoAndSigned(ALICE_NAME)
@ -135,6 +131,8 @@ class NodeTest {
val node = Node(configuration, rigorousMock<VersionInfo>().also { val node = Node(configuration, rigorousMock<VersionInfo>().also {
doReturn(10).whenever(it).platformVersion doReturn(10).whenever(it).platformVersion
doReturn("test-vendor").whenever(it).vendor
doReturn("1.0").whenever(it).releaseVersion
}, initialiseSerialization = false) }, initialiseSerialization = false)
//this throws an exception with old behaviour //this throws an exception with old behaviour

View File

@ -46,7 +46,7 @@ class JarScanningCordappLoaderTest {
fun `test that classes that aren't in cordapps aren't loaded`() { fun `test that classes that aren't in cordapps aren't loaded`() {
// Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp // Basedir will not be a corda node directory so the dummy flow shouldn't be recognised as a part of a cordapp
val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get("."))) val loader = JarScanningCordappLoader.fromDirectories(listOf(Paths.get(".")))
assertThat(loader.cordapps).containsOnly(JarScanningCordappLoader.coreCordapp) assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
} }
@Test @Test
@ -57,7 +57,7 @@ class JarScanningCordappLoaderTest {
val actual = loader.cordapps.toTypedArray() val actual = loader.cordapps.toTypedArray()
assertThat(actual).hasSize(2) assertThat(actual).hasSize(2)
val actualCordapp = actual.single { it != JarScanningCordappLoader.coreCordapp } val actualCordapp = actual.single { it != loader.coreCordapp }
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId)) assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor") assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
assertThat(actualCordapp.rpcFlows).isEmpty() assertThat(actualCordapp.rpcFlows).isEmpty()
@ -91,7 +91,7 @@ class JarScanningCordappLoaderTest {
@Test @Test
fun `sub-packages are ignored`() { fun `sub-packages are ignored`() {
val loader = cordappLoaderForPackages(listOf("net.corda", testScanPackage)) val loader = cordappLoaderForPackages(listOf("net.corda.core", testScanPackage))
val cordapps = loader.cordapps.filter { LoaderTestFlow::class.java in it.initiatedFlows } val cordapps = loader.cordapps.filter { LoaderTestFlow::class.java in it.initiatedFlows }
assertThat(cordapps).hasSize(1) assertThat(cordapps).hasSize(1)
} }

View File

@ -17,7 +17,7 @@ class AttachmentDemoTest {
@Test @Test
fun `attachment demo using a 10MB zip file`() { fun `attachment demo using a 10MB zip file`() {
val numOfExpectedBytes = 10_000_000 val numOfExpectedBytes = 10_000_000
driver(DriverParameters(portAllocation = PortAllocation.Incremental(20000))) { driver(DriverParameters(portAllocation = PortAllocation.Incremental(20000), startNodesInProcess = true)) {
val demoUser = listOf(User("demo", "demo", setOf(all()))) val demoUser = listOf(User("demo", "demo", setOf(all())))
val (nodeA, nodeB) = listOf( val (nodeA, nodeB) = listOf(
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"),

View File

@ -33,6 +33,7 @@ class MockCordappProvider(
serializationCustomSerializers = emptyList(), serializationCustomSerializers = emptyList(),
customSchemas = emptySet(), customSchemas = emptySet(),
jarPath = Paths.get("").toUri().toURL(), jarPath = Paths.get("").toUri().toURL(),
info = CordappImpl.Info.UNKNOWN,
allFlows = emptyList(), allFlows = emptyList(),
jarHash = SecureHash.allOnesHash) jarHash = SecureHash.allOnesHash)
if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) }) { if (cordappRegistry.none { it.first.contractClassNames.contains(contractClassName) }) {
@ -40,7 +41,9 @@ class MockCordappProvider(
} }
} }
override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? = cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second ?: super.getContractAttachmentID(contractClassName) override fun getContractAttachmentID(contractClassName: ContractClassName): AttachmentId? {
return cordappRegistry.find { it.first.contractClassNames.contains(contractClassName) }?.second ?: super.getContractAttachmentID(contractClassName)
}
private fun findOrImportAttachment(contractClassNames: List<ContractClassName>, data: ByteArray, attachments: MockAttachmentStorage): AttachmentId { private fun findOrImportAttachment(contractClassNames: List<ContractClassName>, data: ByteArray, attachments: MockAttachmentStorage): AttachmentId {
val existingAttachment = attachments.files.filter { val existingAttachment = attachments.files.filter {