mirror of
https://github.com/corda/corda.git
synced 2025-01-31 00:24:59 +00:00
[ENT-1731]: Record an event of loading and unloading CorDapps. (#818)
This commit is contained in:
parent
32011e05d1
commit
590f626433
8
.idea/compiler.xml
generated
8
.idea/compiler.xml
generated
@ -48,14 +48,14 @@
|
||||
<module name="client_test" target="1.8" />
|
||||
<module name="confidential-identities_main" target="1.8" />
|
||||
<module name="confidential-identities_test" target="1.8" />
|
||||
<module name="corda-project-tools_main" target="1.8" />
|
||||
<module name="corda-project-tools_test" target="1.8" />
|
||||
<module name="contracts-states_integrationTest" target="1.8" />
|
||||
<module name="contracts-states_main" target="1.8" />
|
||||
<module name="contracts-states_test" target="1.8" />
|
||||
<module name="corda-core_integrationTest" target="1.8" />
|
||||
<module name="corda-core_smokeTest" target="1.8" />
|
||||
<module name="corda-finance_integrationTest" target="1.8" />
|
||||
<module name="corda-project-tools_main" target="1.8" />
|
||||
<module name="corda-project-tools_test" target="1.8" />
|
||||
<module name="corda-project_main" target="1.8" />
|
||||
<module name="corda-project_test" target="1.8" />
|
||||
<module name="cordapp-configuration_main" target="1.8" />
|
||||
@ -95,6 +95,8 @@
|
||||
<module name="finance_integrationTest" target="1.8" />
|
||||
<module name="finance_main" target="1.8" />
|
||||
<module name="finance_test" target="1.8" />
|
||||
<module name="flow-hook_main" target="1.8" />
|
||||
<module name="flow-hook_test" target="1.8" />
|
||||
<module name="flows_integrationTest" target="1.8" />
|
||||
<module name="flows_main" target="1.8" />
|
||||
<module name="flows_test" target="1.8" />
|
||||
@ -222,4 +224,4 @@
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_STRING" value="-parameters" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
@ -51,4 +51,21 @@ interface Cordapp {
|
||||
val customSchemas: Set<MappedSchema>
|
||||
val jarPath: URL
|
||||
val cordappClasses: List<String>
|
||||
val info: Info
|
||||
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
@ -29,8 +29,9 @@ data class CordappImpl(
|
||||
override val serializationWhitelists: List<SerializationWhitelist>,
|
||||
override val serializationCustomSerializers: List<SerializationCustomSerializer<*, *>>,
|
||||
override val customSchemas: Set<MappedSchema>,
|
||||
override val jarPath: URL) : Cordapp {
|
||||
override val name: String = jarPath.toPath().fileName.toString().removeSuffix(".jar")
|
||||
override val jarPath: URL,
|
||||
override val info: Cordapp.Info = CordappImpl.Info.UNKNOWN,
|
||||
override val name: String = jarPath.toPath().fileName.toString().removeSuffix(".jar")) : Cordapp {
|
||||
|
||||
/**
|
||||
* An exhaustive list of all classes relevant to the node within this CorDapp
|
||||
@ -38,4 +39,16 @@ data class CordappImpl(
|
||||
* TODO: Also add [SchedulableFlow] as a Cordapp class
|
||||
*/
|
||||
override val cordappClasses = ((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 {
|
||||
companion object {
|
||||
private const val UNKNOWN_VALUE = "Unknown"
|
||||
|
||||
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE)
|
||||
}
|
||||
|
||||
override fun hasUnknownFields(): Boolean {
|
||||
return setOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import org.assertj.core.api.Assertions.assertThat
|
||||
import java.time.Duration
|
||||
|
||||
class ScenarioState {
|
||||
|
||||
companion object {
|
||||
val log = contextLogger()
|
||||
}
|
||||
|
@ -81,6 +81,19 @@ jar {
|
||||
exclude "META-INF/*.MF"
|
||||
exclude "META-INF/LICENSE"
|
||||
exclude "META-INF/NOTICE"
|
||||
|
||||
manifest {
|
||||
attributes(
|
||||
"Manifest-Version": "1.0",
|
||||
"Name": "net/corda/finance",
|
||||
"Specification-Title": description,
|
||||
"Specification-Version": version,
|
||||
"Specification-Vendor": "R3",
|
||||
"Implementation-Title": "$group.$baseName",
|
||||
"Implementation-Version": version,
|
||||
"Implementation-Vendor": "R3"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
publish {
|
||||
|
@ -24,4 +24,9 @@ data class VersionInfo(
|
||||
/** The exact version control commit ID of the node build. */
|
||||
val revision: String,
|
||||
/** The node vendor */
|
||||
val vendor: String)
|
||||
val vendor: String) {
|
||||
|
||||
companion object {
|
||||
val UNKNOWN = VersionInfo(1, "Unknown", "Unknown", "Unknown")
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ import java.util.concurrent.TimeUnit
|
||||
open class EnterpriseNode(configuration: NodeConfiguration,
|
||||
versionInfo: VersionInfo,
|
||||
initialiseSerialization: Boolean = true,
|
||||
cordappLoader: CordappLoader = makeCordappLoader(configuration)
|
||||
cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo)
|
||||
) : Node(configuration, versionInfo, initialiseSerialization, cordappLoader) {
|
||||
companion object {
|
||||
private val logger by lazy { loggerFor<EnterpriseNode>() }
|
||||
|
@ -72,7 +72,7 @@ import kotlin.system.exitProcess
|
||||
open class Node(configuration: NodeConfiguration,
|
||||
versionInfo: VersionInfo,
|
||||
private val initialiseSerialization: Boolean = true,
|
||||
cordappLoader: CordappLoader = makeCordappLoader(configuration)
|
||||
cordappLoader: CordappLoader = makeCordappLoader(configuration, versionInfo)
|
||||
) : AbstractNode(configuration, createClock(configuration), versionInfo, cordappLoader) {
|
||||
companion object {
|
||||
private val staticLog = contextLogger()
|
||||
@ -100,10 +100,10 @@ open class Node(configuration: NodeConfiguration,
|
||||
const val scanPackagesSeparator = ","
|
||||
|
||||
@JvmStatic
|
||||
protected fun makeCordappLoader(configuration: NodeConfiguration): CordappLoader {
|
||||
protected fun makeCordappLoader(configuration: NodeConfiguration, versionInfo: VersionInfo): CordappLoader {
|
||||
return System.getProperty(scanPackagesSystemProperty)?.let { scanPackages ->
|
||||
CordappLoader.createDefaultWithTestPackages(configuration, scanPackages.split(scanPackagesSeparator))
|
||||
} ?: CordappLoader.createDefault(configuration.baseDirectory)
|
||||
CordappLoader.createDefaultWithTestPackages(configuration, scanPackages.split(scanPackagesSeparator), versionInfo)
|
||||
} ?: CordappLoader.createDefault(configuration.baseDirectory, versionInfo)
|
||||
}
|
||||
|
||||
// TODO Wire up maxMessageSize
|
||||
|
@ -12,13 +12,19 @@ package net.corda.node.internal
|
||||
|
||||
import com.jcabi.manifests.Manifests
|
||||
import net.corda.core.crypto.Crypto
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.Emoji
|
||||
import net.corda.core.internal.concurrent.thenMatch
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.randomOrNull
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.*
|
||||
import net.corda.node.CmdLineOptions
|
||||
import net.corda.node.NodeArgsParser
|
||||
import net.corda.node.NodeRegistrationOption
|
||||
import net.corda.node.SerialFilter
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.defaultSerialFilter
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.config.NodeConfigurationImpl
|
||||
import net.corda.node.services.config.shouldStartLocalShell
|
||||
@ -28,8 +34,8 @@ import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
||||
import net.corda.node.utilities.registration.NodeRegistrationHelper
|
||||
import net.corda.nodeapi.internal.addShutdownHook
|
||||
import net.corda.nodeapi.internal.config.UnknownConfigurationKeysException
|
||||
import net.corda.tools.shell.InteractiveShell
|
||||
import net.corda.nodeapi.internal.persistence.oracleJdbcDriverSerialFilter
|
||||
import net.corda.tools.shell.InteractiveShell
|
||||
import org.fusesource.jansi.Ansi
|
||||
import org.fusesource.jansi.AnsiConsole
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler
|
||||
@ -153,7 +159,7 @@ open class NodeStartup(val args: Array<String>) {
|
||||
return
|
||||
}
|
||||
val startedNode = node.start()
|
||||
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name })
|
||||
logLoadedCorDapps(startedNode.services.cordappProvider.cordapps)
|
||||
startedNode.internals.nodeReadyFuture.thenMatch({
|
||||
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
|
||||
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation
|
||||
@ -242,6 +248,17 @@ open class NodeStartup(val args: Array<String>) {
|
||||
)
|
||||
}
|
||||
|
||||
open protected fun logLoadedCorDapps(corDapps: List<Cordapp>) {
|
||||
fun Cordapp.Info.description() = "$shortName version $version by $vendor"
|
||||
|
||||
Node.printBasicNodeInfo("Loaded ${corDapps.size} CorDapp(s)", corDapps.map { it.info }.joinToString(", ", transform = Cordapp.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) {
|
||||
// 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
|
||||
|
@ -14,15 +14,32 @@ import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.flows.*
|
||||
import net.corda.core.internal.*
|
||||
import net.corda.core.flows.ContractUpgradeFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.InitiatedBy
|
||||
import net.corda.core.flows.SchedulableFlow
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.flows.StartableByService
|
||||
import net.corda.core.internal.VisibleForTesting
|
||||
import net.corda.core.internal.copyTo
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.div
|
||||
import net.corda.core.internal.exists
|
||||
import net.corda.core.internal.isRegularFile
|
||||
import net.corda.core.internal.list
|
||||
import net.corda.core.internal.objectOrNewInstance
|
||||
import net.corda.core.internal.outputStream
|
||||
import net.corda.core.internal.toPath
|
||||
import net.corda.core.internal.toTypedArray
|
||||
import net.corda.core.internal.walk
|
||||
import net.corda.core.node.services.CordaService
|
||||
import net.corda.core.schemas.MappedSchema
|
||||
import net.corda.core.serialization.SerializationCustomSerializer
|
||||
import net.corda.core.serialization.SerializationWhitelist
|
||||
import net.corda.core.serialization.SerializeAsToken
|
||||
import net.corda.core.utilities.contextLogger
|
||||
import net.corda.node.VersionInfo
|
||||
import net.corda.node.internal.classloading.requireAnnotation
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.nodeapi.internal.coreContractClasses
|
||||
@ -38,6 +55,7 @@ import java.nio.file.attribute.FileTime
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.jar.JarInputStream
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import kotlin.reflect.KClass
|
||||
@ -48,7 +66,7 @@ import kotlin.streams.toList
|
||||
*
|
||||
* @property cordappJarPaths The classpath of cordapp JARs
|
||||
*/
|
||||
class CordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>) {
|
||||
class CordappLoader private constructor(private val cordappJarPaths: List<RestrictedURL>, versionInfo: VersionInfo) {
|
||||
val cordapps: List<Cordapp> by lazy { loadCordapps() + coreCordapp }
|
||||
val appClassLoader: ClassLoader = URLClassLoader(cordappJarPaths.stream().map { it.url }.toTypedArray(), javaClass.classLoader)
|
||||
|
||||
@ -62,6 +80,22 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
|
||||
val cordappSchemas: Set<MappedSchema> get() = cordapps.flatMap { it.customSchemas }.toSet()
|
||||
|
||||
/** 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(),
|
||||
jarPath = ContractUpgradeFlow.javaClass.protectionDomain.codeSource.location, // Core JAR location
|
||||
info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion)
|
||||
)
|
||||
|
||||
companion object {
|
||||
private val logger = contextLogger()
|
||||
/**
|
||||
@ -75,7 +109,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
* @param baseDir The directory that this node is running in. Will use this to resolve the cordapps directory
|
||||
* for classpath scanning.
|
||||
*/
|
||||
fun createDefault(baseDir: Path) = CordappLoader(getNodeCordappURLs(baseDir))
|
||||
fun createDefault(baseDir: Path, versionInfo: VersionInfo = VersionInfo.UNKNOWN) = CordappLoader(getNodeCordappURLs(baseDir), versionInfo)
|
||||
|
||||
// Cache for CordappLoaders to avoid costly classpath scanning
|
||||
private val cordappLoadersCache = Caffeine.newBuilder().softValues().build<List<RestrictedURL>, CordappLoader>()
|
||||
@ -98,12 +132,12 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
* @param testPackages See [createWithTestPackages]
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun createDefaultWithTestPackages(configuration: NodeConfiguration, testPackages: List<String>): CordappLoader {
|
||||
fun createDefaultWithTestPackages(configuration: NodeConfiguration, testPackages: List<String>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader {
|
||||
if (!configuration.devMode) {
|
||||
logger.warn("Package scanning should only occur in dev mode!")
|
||||
}
|
||||
val urls = getNodeCordappURLs(configuration.baseDirectory) + simplifyScanPackages(testPackages).flatMap(this::getPackageURLs)
|
||||
return cordappLoadersCache.asMap().computeIfAbsent(urls, ::CordappLoader)
|
||||
return cordappLoadersCache.asMap().computeIfAbsent(urls) { values -> CordappLoader(values, versionInfo) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,9 +148,9 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
* CorDapps.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun createWithTestPackages(testPackages: List<String>): CordappLoader {
|
||||
fun createWithTestPackages(testPackages: List<String>, versionInfo: VersionInfo = VersionInfo.UNKNOWN): CordappLoader {
|
||||
val urls = simplifyScanPackages(testPackages).flatMap(this::getPackageURLs)
|
||||
return cordappLoadersCache.asMap().computeIfAbsent(urls, ::CordappLoader)
|
||||
return cordappLoadersCache.asMap().computeIfAbsent(urls) { values -> CordappLoader(values, versionInfo) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -125,7 +159,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
* @param scanJars Uses the JAR URLs provided for classpath scanning and Cordapp detection
|
||||
*/
|
||||
@VisibleForTesting
|
||||
fun createDevMode(scanJars: List<URL>) = CordappLoader(scanJars.map { RestrictedURL(it, null) })
|
||||
fun createDevMode(scanJars: List<URL>, versionInfo: VersionInfo = VersionInfo.UNKNOWN) = CordappLoader(scanJars.map { RestrictedURL(it, null) }, versionInfo)
|
||||
|
||||
private fun getPackageURLs(scanPackage: String): List<RestrictedURL> {
|
||||
val resource = scanPackage.replace('.', '/')
|
||||
@ -148,20 +182,24 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
return generatedCordapps.computeIfAbsent(url) {
|
||||
// TODO Using the driver in out-of-process mode causes each node to have their own copy of the same dev CorDapps
|
||||
val cordappDir = (Paths.get("build") / "tmp" / "generated-test-cordapps").createDirectories()
|
||||
val cordappJar = cordappDir / "$scanPackage-${UUID.randomUUID()}.jar"
|
||||
val uuid = UUID.randomUUID()
|
||||
val cordappJar = cordappDir / "$scanPackage-$uuid.jar"
|
||||
logger.info("Generating a test-only CorDapp of classes discovered for package $scanPackage in $url: $cordappJar")
|
||||
JarOutputStream(cordappJar.outputStream()).use { jos ->
|
||||
val scanDir = url.toPath()
|
||||
scanDir.walk { it.forEach {
|
||||
val entryPath = "$resource/${scanDir.relativize(it).toString().replace('\\', '/')}"
|
||||
val time = FileTime.from(Instant.EPOCH)
|
||||
val entry = ZipEntry(entryPath).setCreationTime(time).setLastAccessTime(time).setLastModifiedTime(time)
|
||||
jos.putNextEntry(entry)
|
||||
if (it.isRegularFile()) {
|
||||
it.copyTo(jos)
|
||||
val manifest = createTestManifest(resource, scanPackage, uuid)
|
||||
val scanDir = url.toPath()
|
||||
JarOutputStream(cordappJar.outputStream(), manifest).use { jos ->
|
||||
scanDir.walk {
|
||||
it.forEach {
|
||||
val entryPath = "$resource/${scanDir.relativize(it).toString().replace('\\', '/')}"
|
||||
val time = FileTime.from(Instant.EPOCH)
|
||||
val entry = ZipEntry(entryPath).setCreationTime(time).setLastAccessTime(time).setLastModifiedTime(time)
|
||||
jos.putNextEntry(entry)
|
||||
if (it.isRegularFile()) {
|
||||
it.copyTo(jos)
|
||||
}
|
||||
jos.closeEntry()
|
||||
}
|
||||
jos.closeEntry()
|
||||
} }
|
||||
}
|
||||
}
|
||||
cordappJar
|
||||
}
|
||||
@ -183,25 +221,13 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
ContractUpgradeFlow.Initiate::class.java,
|
||||
ContractUpgradeFlow.Authorise::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(),
|
||||
jarPath = ContractUpgradeFlow.javaClass.protectionDomain.codeSource.location // Core JAR location
|
||||
)
|
||||
}
|
||||
|
||||
private fun loadCordapps(): List<Cordapp> {
|
||||
return cordappJarPaths.map {
|
||||
val url = it.url
|
||||
val name = url.toPath().fileName.toString().removeSuffix(".jar")
|
||||
val info = url.openStream().let(::JarInputStream).use { it.manifest }.toCordappInfo(name)
|
||||
val scanResult = scanCordapp(it)
|
||||
CordappImpl(findContractClassNames(scanResult),
|
||||
findInitiatedFlows(scanResult),
|
||||
@ -212,7 +238,9 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
findPlugins(it),
|
||||
findSerializers(scanResult),
|
||||
findCustomSchemas(scanResult),
|
||||
it.url)
|
||||
url,
|
||||
info,
|
||||
name)
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,7 +331,7 @@ class CordappLoader private constructor(private val cordappJarPaths: List<Restri
|
||||
|
||||
/** @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 + '.' } ?: ""
|
||||
val qualifiedNamePrefix: String get() = rootPackageName?.let { "$it." } ?: ""
|
||||
}
|
||||
|
||||
private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) {
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* R3 Proprietary and Confidential
|
||||
*
|
||||
* Copyright (c) 2018 R3 Limited. All rights reserved.
|
||||
*
|
||||
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
|
||||
*
|
||||
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
|
||||
*/
|
||||
|
||||
package net.corda.node.internal.cordapp
|
||||
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.cordapp.CordappImpl
|
||||
import java.util.*
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.Manifest
|
||||
|
||||
internal fun createTestManifest(name: String, title: String, jarUUID: UUID): Manifest {
|
||||
val manifest = Manifest()
|
||||
val version = "test-$jarUUID"
|
||||
val vendor = "R3"
|
||||
|
||||
// Mandatory manifest attribute. If not present, all other entries are silently skipped.
|
||||
manifest.mainAttributes[Attributes.Name.MANIFEST_VERSION] = "1.0"
|
||||
|
||||
manifest["Name"] = name
|
||||
|
||||
manifest["Specification-Title"] = title
|
||||
manifest["Specification-Version"] = version
|
||||
manifest["Specification-Vendor"] = vendor
|
||||
|
||||
manifest["Implementation-Title"] = title
|
||||
manifest["Implementation-Version"] = version
|
||||
manifest["Implementation-Vendor"] = vendor
|
||||
|
||||
return manifest
|
||||
}
|
||||
|
||||
internal operator fun Manifest.set(key: String, value: String) {
|
||||
mainAttributes.putValue(key, value)
|
||||
}
|
||||
|
||||
internal fun Manifest?.toCordappInfo(defaultShortName: String): Cordapp.Info {
|
||||
var unknown = CordappImpl.Info.UNKNOWN
|
||||
(this?.mainAttributes?.getValue("Name") ?: defaultShortName).let { shortName ->
|
||||
unknown = unknown.copy(shortName = shortName)
|
||||
}
|
||||
this?.mainAttributes?.getValue("Implementation-Vendor")?.let { vendor ->
|
||||
unknown = unknown.copy(vendor = vendor)
|
||||
}
|
||||
this?.mainAttributes?.getValue("Implementation-Version")?.let { version ->
|
||||
unknown = unknown.copy(version = version)
|
||||
}
|
||||
return unknown
|
||||
}
|
@ -64,7 +64,7 @@ class NodeTest {
|
||||
fun `generateAndSaveNodeInfo works`() {
|
||||
val nodeAddress = NetworkHostAndPort("0.1.2.3", 456)
|
||||
val nodeName = CordaX500Name("Manx Blockchain Corp", "Douglas", "IM")
|
||||
val platformVersion = 789
|
||||
val info = VersionInfo(789, "3.0", "SNAPSHOT", "R3")
|
||||
val dataSourceProperties = makeTestDataSourceProperties()
|
||||
val databaseConfig = DatabaseConfig()
|
||||
val configuration = rigorousMock<AbstractNodeConfiguration>().also {
|
||||
@ -79,10 +79,8 @@ class NodeTest {
|
||||
doReturn("tsp").whenever(it).trustStorePassword
|
||||
doReturn("ksp").whenever(it).keyStorePassword
|
||||
}
|
||||
configureDatabase(dataSourceProperties, databaseConfig, rigorousMock()).use { database ->
|
||||
val node = Node(configuration, rigorousMock<VersionInfo>().also {
|
||||
doReturn(platformVersion).whenever(it).platformVersion
|
||||
}, initialiseSerialization = false)
|
||||
configureDatabase(dataSourceProperties, databaseConfig, rigorousMock()).use { _ ->
|
||||
val node = Node(configuration, info, initialiseSerialization = false)
|
||||
assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial)
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class CordappLoaderTest {
|
||||
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
|
||||
val loader = CordappLoader.createDefault(Paths.get("."))
|
||||
assertThat(loader.cordapps).containsOnly(CordappLoader.coreCordapp)
|
||||
assertThat(loader.cordapps).containsOnly(loader.coreCordapp)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -62,7 +62,7 @@ class CordappLoaderTest {
|
||||
val actual = loader.cordapps.toTypedArray()
|
||||
assertThat(actual).hasSize(2)
|
||||
|
||||
val actualCordapp = actual.single { it != CordappLoader.coreCordapp }
|
||||
val actualCordapp = actual.single { it != loader.coreCordapp }
|
||||
assertThat(actualCordapp.contractClassNames).isEqualTo(listOf(isolatedContractId))
|
||||
assertThat(actualCordapp.initiatedFlows.single().name).isEqualTo("net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Acceptor")
|
||||
assertThat(actualCordapp.rpcFlows).isEmpty()
|
||||
|
@ -41,7 +41,7 @@ class AttachmentDemoTest : IntegrationTest() {
|
||||
@Test
|
||||
fun `attachment demo using a 10MB zip file`() {
|
||||
val numOfExpectedBytes = 10_000_000
|
||||
driver(DriverParameters(isDebug = true, portAllocation = PortAllocation.Incremental(20000))) {
|
||||
driver(DriverParameters(isDebug = true, portAllocation = PortAllocation.Incremental(20000), startNodesInProcess = true)) {
|
||||
val demoUser = listOf(User("demo", "demo", setOf(
|
||||
startFlow<AttachmentDemoFlow>(),
|
||||
invokeRpc(CordaRPCOps::attachmentExists),
|
||||
|
Loading…
x
Reference in New Issue
Block a user