Various cleanups to AMQP and Kryo serialisation:

* PartyAndCertificate serialiser has been converted to deal with just CertPath
* Removed X500Name serialiser as we no longer use the BC implementation and have our own CordaX500Name
* Converted X509 cert serialiser to use Java certs and not BC X509 cert holder
* Added to test to AMQP serialisation to make sure c'tor is invoked on deserialisation
This commit is contained in:
Shams Asari
2017-11-20 11:57:58 +00:00
parent 288eb5fcc4
commit f7e51a9ae1
12 changed files with 166 additions and 169 deletions

View File

@ -21,13 +21,14 @@ import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.time.Instant
import java.util.Collections
import kotlin.test.*
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class KryoTests {
@Rule
@ -36,9 +37,6 @@ class KryoTests {
private lateinit var factory: SerializationFactory
private lateinit var context: SerializationContext
@get:Rule
val expectedEx: ExpectedException = ExpectedException.none()
@Before
fun setup() {
factory = SerializationFactoryImpl().apply { registerScheme(KryoServerSerializationScheme()) }
@ -51,7 +49,7 @@ class KryoTests {
}
@Test
fun ok() {
fun `simple data class`() {
val birthday = Instant.parse("1984-04-17T00:30:00.00Z")
val mike = Person("mike", birthday)
val bits = mike.serialize(factory, context)
@ -59,7 +57,7 @@ class KryoTests {
}
@Test
fun nullables() {
fun `null values`() {
val bob = Person("bob", null)
val bits = bob.serialize(factory, context)
assertThat(bits.deserialize(factory, context)).isEqualTo(Person("bob", null))
@ -202,13 +200,6 @@ class KryoTests {
assertEquals(expected, actual)
}
@Test
fun `all-zero PrivacySalt not allowed`() {
expectedEx.expect(IllegalArgumentException::class.java)
expectedEx.expectMessage("Privacy salt should not be all zeros.")
PrivacySalt(ByteArray(32))
}
@CordaSerializable
private object TestSingleton

View File

@ -2,16 +2,16 @@ package net.corda.nodeapi.internal.serialization
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.util.DefaultClassResolver
import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.node.services.statemachine.SessionData
import net.corda.nodeapi.internal.serialization.kryo.KryoHeaderV0_1
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.amqpSpecific
import net.corda.testing.kryoSpecific
import net.corda.testing.SerializationEnvironmentRule
import org.assertj.core.api.Assertions
import org.bouncycastle.asn1.x500.X500Name
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Assert.assertArrayEquals
import org.junit.Rule
import org.junit.Test
@ -53,7 +53,7 @@ class MapsSerializationTest {
fun `check throws for forbidden declared type`() = amqpSpecific("Such exceptions are not expected in Kryo mode.") {
val payload = HashMap<String, String>(smallMap)
val wrongPayloadType = WrongPayloadType(payload)
Assertions.assertThatThrownBy { wrongPayloadType.serialize() }
assertThatThrownBy { wrongPayloadType.serialize() }
.isInstanceOf(IllegalArgumentException::class.java).hasMessageContaining(
"Map type class java.util.HashMap is unstable under iteration. Suggested fix: use java.util.LinkedHashMap instead.")
}
@ -62,27 +62,29 @@ class MapsSerializationTest {
data class MyKey(val keyContent: Double)
@CordaSerializable
data class MyValue(val valueContent: X500Name)
data class MyValue(val valueContent: CordaX500Name)
@Test
fun `check map serialization works with custom types`() {
val myMap = mapOf(
MyKey(1.0) to MyValue(X500Name("CN=one")),
MyKey(10.0) to MyValue(X500Name("CN=ten")))
MyKey(1.0) to MyValue(CordaX500Name("OOO", "LLL", "CC")),
MyKey(10.0) to MyValue(CordaX500Name("OO", "LL", "CC")))
assertEqualAfterRoundTripSerialization(myMap)
}
@Test
fun `check empty map serialises as Java emptyMap`() = kryoSpecific("Specifically checks Kryo serialization") {
val nameID = 0
val serializedForm = emptyMap<Int, Int>().serialize()
val output = ByteArrayOutputStream().apply {
write(KryoHeaderV0_1.bytes)
write(DefaultClassResolver.NAME + 2)
write(nameID)
write(javaEmptyMapClass.name.toAscii())
write(Kryo.NOT_NULL.toInt())
fun `check empty map serialises as Java emptyMap`() {
kryoSpecific("Specifically checks Kryo serialization") {
val nameID = 0
val serializedForm = emptyMap<Int, Int>().serialize()
val output = ByteArrayOutputStream().apply {
write(KryoHeaderV0_1.bytes)
write(DefaultClassResolver.NAME + 2)
write(nameID)
write(javaEmptyMapClass.name.toAscii())
write(Kryo.NOT_NULL.toInt())
}
assertArrayEquals(output.toByteArray(), serializedForm.bytes)
}
assertArrayEquals(output.toByteArray(), serializedForm.bytes)
}
}

View File

@ -1,17 +1,20 @@
@file:Suppress("unused", "MemberVisibilityCanPrivate")
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.client.rpc.RPCException
import net.corda.core.CordaRuntimeException
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.secureRandomBytes
import net.corda.core.flows.FlowException
import net.corda.core.identity.AbstractParty
import net.corda.core.internal.toX509CertHolder
import net.corda.core.internal.AbstractAttachment
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.serialization.SerializationFactory
import net.corda.core.transactions.LedgerTransaction
import net.corda.client.rpc.RPCException
import net.corda.core.contracts.*
import net.corda.core.internal.AbstractAttachment
import net.corda.core.serialization.MissingAttachmentsException
import net.corda.core.utilities.OpaqueBytes
import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.EmptyWhitelist
import net.corda.nodeapi.internal.serialization.GeneratedAttachment
@ -25,10 +28,8 @@ import org.apache.activemq.artemis.api.core.SimpleString
import org.apache.qpid.proton.amqp.*
import org.apache.qpid.proton.codec.DecoderImpl
import org.apache.qpid.proton.codec.EncoderImpl
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertNotSame
import org.junit.Assert.assertSame
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.Assertions.*
import org.junit.Assert.*
import org.junit.Ignore
import org.junit.Test
import java.io.ByteArrayInputStream
@ -39,10 +40,7 @@ import java.nio.ByteBuffer
import java.time.*
import java.time.temporal.ChronoUnit
import java.util.*
import kotlin.reflect.full.declaredFunctions
import kotlin.reflect.full.declaredMemberFunctions
import kotlin.reflect.full.superclasses
import kotlin.reflect.jvm.javaMethod
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@ -79,7 +77,6 @@ class SerializationOutputTests {
}
data class Woo(val fred: Int) {
@Suppress("unused")
val bob = "Bob"
}
@ -89,7 +86,6 @@ class SerializationOutputTests {
@CordaSerializable
data class AnnotatedWoo(val fred: Int) {
@Suppress("unused")
val bob = "Bob"
}
@ -151,6 +147,13 @@ class SerializationOutputTests {
data class PolymorphicProperty(val foo: FooInterface?)
@CordaSerializable
class NonZeroByte(val value: Byte) {
init {
require(value.toInt() != 0) { "Zero not allowed" }
}
}
private inline fun <reified T : Any> serdes(obj: T,
factory: SerializerFactory = SerializerFactory(
AllWhitelist, ClassLoader.getSystemClassLoader()),
@ -406,6 +409,32 @@ class SerializationOutputTests {
serdes(obj)
}
@Test
fun `class constructor is invoked on deserialisation`() {
val ser = SerializationOutput(SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()))
val des = DeserializationInput(ser.serializerFactory)
val serialisedOne = ser.serialize(NonZeroByte(1)).bytes
val serialisedTwo = ser.serialize(NonZeroByte(2)).bytes
// Find the index that holds the value byte
val valueIndex = serialisedOne.zip(serialisedTwo).mapIndexedNotNull { index, (oneByte, twoByte) ->
if (oneByte.toInt() == 1 && twoByte.toInt() == 2) index else null
}.single()
val copy = serialisedTwo.clone()
// Double check
copy[valueIndex] = 0x03
assertThat(des.deserialize(OpaqueBytes(copy), NonZeroByte::class.java).value).isEqualTo(3)
// Now use the forbidden value
copy[valueIndex] = 0x00
assertThatExceptionOfType(NotSerializableException::class.java).isThrownBy {
des.deserialize(OpaqueBytes(copy), NonZeroByte::class.java)
}.withMessageContaining("Zero not allowed")
}
@Test
fun `test custom serializers on public key`() {
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
@ -762,26 +791,32 @@ class SerializationOutputTests {
}
@Test
fun `test certificate holder serialize`() {
fun `test privacy salt serialize`() {
serdes(PrivacySalt())
serdes(PrivacySalt(secureRandomBytes(32)))
}
@Test
fun `test X509 certificate serialize`() {
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateHolderSerializer)
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateSerializer)
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateHolderSerializer)
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateSerializer)
val obj = BOB_IDENTITY.certificate.toX509CertHolder()
val obj = BOB_IDENTITY.certificate
serdes(obj, factory, factory2)
}
@Test
fun `test party and certificate serialize`() {
fun `test cert path serialize`() {
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.PartyAndCertificateSerializer(factory))
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.CertPathSerializer(factory))
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.PartyAndCertificateSerializer(factory2))
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.CertPathSerializer(factory2))
val obj = BOB_IDENTITY
val obj = BOB_IDENTITY.certPath
serdes(obj, factory, factory2)
}