CORDA-3680: Add CorDapp custom serialisers to Driver's in-process nodes. (#6098)

* Run serialisation tests with both in-process and out-of-process nodes.

* Add custom serialisers and whitelists to Driver's AMQPServerSerializationScheme.
This commit is contained in:
Chris Rankin 2020-03-27 10:01:30 +00:00 committed by GitHub
parent a5d49ea111
commit f1ebaa761b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 17 deletions

View File

@ -8,7 +8,6 @@ import net.corda.core.serialization.SerializationCustomSerializer
import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.serialization.internal.SerializationEnvironment import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal._rpcClientSerializationEnv import net.corda.core.serialization.internal._rpcClientSerializationEnv
import net.corda.core.serialization.internal.nodeSerializationEnv
import net.corda.serialization.internal.* import net.corda.serialization.internal.*
import net.corda.serialization.internal.amqp.* import net.corda.serialization.internal.amqp.*
import net.corda.serialization.internal.amqp.custom.RxNotificationSerializer import net.corda.serialization.internal.amqp.custom.RxNotificationSerializer
@ -57,7 +56,7 @@ class AMQPClientSerializationScheme(
} }
} }
override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { override fun canDeserializeVersion(magic: CordaSerializationMagic, target: UseCase): Boolean {
return magic == amqpMagic && (target == UseCase.RPCClient || target == UseCase.P2P) return magic == amqpMagic && (target == UseCase.RPCClient || target == UseCase.P2P)
} }

View File

@ -18,13 +18,21 @@ import net.corda.testing.node.internal.cordappWithPackages
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.BeforeClass import org.junit.BeforeClass
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@RunWith(Parameterized::class)
@Suppress("FunctionName") @Suppress("FunctionName")
class ContractWithCustomSerializerTest { class ContractWithCustomSerializerTest(private val runInProcess: Boolean) {
companion object { companion object {
const val CURRANTS = 5000L const val CURRANTS = 5000L
@Parameters
@JvmStatic
fun modes(): List<Array<Boolean>> = listOf(Array(1) { true }, Array(1) { false })
@BeforeClass @BeforeClass
@JvmStatic @JvmStatic
fun checkData() { fun checkData() {
@ -37,7 +45,7 @@ class ContractWithCustomSerializerTest {
val user = User("u", "p", setOf(Permissions.all())) val user = User("u", "p", setOf(Permissions.all()))
driver(DriverParameters( driver(DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)),
cordappsForAllNodes = listOf( cordappsForAllNodes = listOf(
cordappWithPackages("net.corda.flows.serialization.custom").signed(), cordappWithPackages("net.corda.flows.serialization.custom").signed(),

View File

@ -26,10 +26,14 @@ import net.corda.testing.node.internal.cordappWithPackages
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.BeforeClass import org.junit.BeforeClass
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@RunWith(Parameterized::class)
@Suppress("FunctionName") @Suppress("FunctionName")
class ContractWithMissingCustomSerializerTest { class ContractWithMissingCustomSerializerTest(private val runInProcess: Boolean) {
companion object { companion object {
const val BOBBINS = 5000L const val BOBBINS = 5000L
@ -37,15 +41,19 @@ class ContractWithMissingCustomSerializerTest {
val flowCorDapp = cordappWithPackages("net.corda.flows.serialization.missing").signed() val flowCorDapp = cordappWithPackages("net.corda.flows.serialization.missing").signed()
val contractCorDapp = cordappWithPackages("net.corda.contracts.serialization.missing").signed() val contractCorDapp = cordappWithPackages("net.corda.contracts.serialization.missing").signed()
fun driverParameters(cordapps: List<TestCordapp>): DriverParameters { fun driverParameters(cordapps: List<TestCordapp>, runInProcess: Boolean): DriverParameters {
return DriverParameters( return DriverParameters(
portAllocation = incrementalPortAllocation(), portAllocation = incrementalPortAllocation(),
startNodesInProcess = false, startNodesInProcess = runInProcess,
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)),
cordappsForAllNodes = cordapps cordappsForAllNodes = cordapps
) )
} }
@Parameters
@JvmStatic
fun modes(): List<Array<Boolean>> = listOf(Array(1) { true }, Array(1) { false })
@BeforeClass @BeforeClass
@JvmStatic @JvmStatic
fun checkData() { fun checkData() {
@ -62,7 +70,7 @@ class ContractWithMissingCustomSerializerTest {
val flowId = flowCorDapp.jarFile.hash val flowId = flowCorDapp.jarFile.hash
val fixupCorDapp = cordappWithFixups(listOf(setOf(contractId) to setOf(contractId, flowId))).signed() val fixupCorDapp = cordappWithFixups(listOf(setOf(contractId) to setOf(contractId, flowId))).signed()
driver(driverParameters(listOf(flowCorDapp, contractCorDapp, fixupCorDapp))) { driver(driverParameters(listOf(flowCorDapp, contractCorDapp, fixupCorDapp), runInProcess)) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val ex = assertFailsWith<ContractRejection> { val ex = assertFailsWith<ContractRejection> {
CordaRPCClient(hostAndPort = alice.rpcAddress) CordaRPCClient(hostAndPort = alice.rpcAddress)
@ -83,7 +91,7 @@ class ContractWithMissingCustomSerializerTest {
*/ */
@Test(timeout=300_000) @Test(timeout=300_000)
fun `flow with missing custom serializer but without fixup`() { fun `flow with missing custom serializer but without fixup`() {
driver(driverParameters(listOf(flowCorDapp, contractCorDapp))) { driver(driverParameters(listOf(flowCorDapp, contractCorDapp), runInProcess)) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val ex = assertFailsWith<BrokenTransactionException> { val ex = assertFailsWith<BrokenTransactionException> {
CordaRPCClient(hostAndPort = alice.rpcAddress) CordaRPCClient(hostAndPort = alice.rpcAddress)
@ -104,7 +112,7 @@ class ContractWithMissingCustomSerializerTest {
*/ */
@Test(timeout=300_000) @Test(timeout=300_000)
fun `transaction builder flow with missing custom serializer by rpc`() { fun `transaction builder flow with missing custom serializer by rpc`() {
driver(driverParameters(listOf(flowCorDapp, contractCorDapp))) { driver(driverParameters(listOf(flowCorDapp, contractCorDapp), runInProcess)) {
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow()
val ex = assertFailsWith<CordaRuntimeException> { val ex = assertFailsWith<CordaRuntimeException> {
CordaRPCClient(hostAndPort = alice.rpcAddress) CordaRPCClient(hostAndPort = alice.rpcAddress)

View File

@ -18,10 +18,16 @@ class AMQPServerSerializationScheme(
cordappSerializationWhitelists: Set<SerializationWhitelist>, cordappSerializationWhitelists: Set<SerializationWhitelist>,
serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory> serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory>
) : AbstractAMQPSerializationScheme(cordappCustomSerializers, cordappSerializationWhitelists, serializerFactoriesForContexts) { ) : AbstractAMQPSerializationScheme(cordappCustomSerializers, cordappSerializationWhitelists, serializerFactoriesForContexts) {
constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, cordapps.serializationWhitelists, AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>(128).toSynchronised()) constructor(cordapps: List<Cordapp>) : this(cordapps.customSerializers, cordapps.serializationWhitelists)
constructor(cordapps: List<Cordapp>, serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory>) : this(cordapps.customSerializers, cordapps.serializationWhitelists, serializerFactoriesForContexts) constructor(cordapps: List<Cordapp>, serializerFactoriesForContexts: MutableMap<SerializationFactoryCacheKey, SerializerFactory>)
: this(cordapps.customSerializers, cordapps.serializationWhitelists, serializerFactoriesForContexts)
constructor(
cordappCustomSerializers: Set<SerializationCustomSerializer<*,*>>,
cordappSerializationWhitelists: Set<SerializationWhitelist>
) : this(cordappCustomSerializers, cordappSerializationWhitelists, AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>(128).toSynchronised())
constructor() : this(emptySet(), emptySet(), AccessOrderLinkedHashMap<SerializationFactoryCacheKey, SerializerFactory>(128).toSynchronised() ) @Suppress("UNUSED")
constructor() : this(emptySet(), emptySet())
override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory { override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory {
throw UnsupportedOperationException() throw UnsupportedOperationException()

View File

@ -21,16 +21,18 @@ fun createTestSerializationEnv(): SerializationEnvironment {
} }
fun createTestSerializationEnv(classLoader: ClassLoader?): SerializationEnvironment { fun createTestSerializationEnv(classLoader: ClassLoader?): SerializationEnvironment {
val clientSerializationScheme = if (classLoader != null) { val (clientSerializationScheme, serverSerializationScheme) = if (classLoader != null) {
val customSerializers = createInstancesOfClassesImplementing(classLoader, SerializationCustomSerializer::class.java) val customSerializers = createInstancesOfClassesImplementing(classLoader, SerializationCustomSerializer::class.java)
val serializationWhitelists = ServiceLoader.load(SerializationWhitelist::class.java, classLoader).toSet() val serializationWhitelists = ServiceLoader.load(SerializationWhitelist::class.java, classLoader).toSet()
AMQPClientSerializationScheme(customSerializers, serializationWhitelists)
Pair(AMQPClientSerializationScheme(customSerializers, serializationWhitelists),
AMQPServerSerializationScheme(customSerializers, serializationWhitelists))
} else { } else {
AMQPClientSerializationScheme(emptyList()) Pair(AMQPClientSerializationScheme(emptyList()), AMQPServerSerializationScheme(emptyList()))
} }
val factory = SerializationFactoryImpl().apply { val factory = SerializationFactoryImpl().apply {
registerScheme(clientSerializationScheme) registerScheme(clientSerializationScheme)
registerScheme(AMQPServerSerializationScheme(emptyList())) registerScheme(serverSerializationScheme)
} }
return SerializationEnvironment.with( return SerializationEnvironment.with(
factory, factory,