diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt index d4596c5ec0..e70b55d8fc 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPSerializer.kt @@ -35,5 +35,5 @@ interface AMQPSerializer { /** * Read the given object from the input. The envelope is provided in case the schema is required. */ - fun readObject(obj: Any, schema: SerializationSchemas, input: DeserializationInput): T + fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): T } \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt new file mode 100644 index 0000000000..f8579fc21e --- /dev/null +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/EnumEvolutionSerializer.kt @@ -0,0 +1,89 @@ +package net.corda.nodeapi.internal.serialization.amqp + +import org.apache.qpid.proton.amqp.Symbol +import org.apache.qpid.proton.codec.Data +import java.io.NotSerializableException +import java.lang.reflect.Type +import java.util.* + +/** + * @property transforms + * + */ +class EnumEvolutionSerializer( + clazz: Type, + factory: SerializerFactory, + private val conversions : Map, + private val ordinals : Map) : AMQPSerializer { + override val type: Type = clazz + override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")!! + + companion object { + fun MutableMap.mapInPlace(f : (String)->String) { + val i = this.iterator() + while(i.hasNext()) { + val curr = (i.next()) + curr.setValue(f(curr.value)) + } + } + + /** + * @param old + * @param new + */ + fun make(old: RestrictedType, + new: AMQPSerializer, + factory: SerializerFactory, + transformsFromBlob: TransformsSchema): AMQPSerializer { + + val wireTransforms = transformsFromBlob.types[old.name] + val localTransforms = TransformsSchema.get(old.name, factory) + val transforms = if (wireTransforms?.size ?: -1 > localTransforms.size) wireTransforms!! else localTransforms + + // if either of these isn't of the cast type then something has gone terribly wrong + // elsewhere in the code + @Suppress("UNCHECKED_CAST") + val defaultRules = transforms[TransformTypes.EnumDefault] as? List + @Suppress("UNCHECKED_CAST") + val renameRules = transforms[TransformTypes.Rename] as? List + + // What values exist on the enum as it exists on the class path + val localVals = new.type.asClass()!!.enumConstants.map { it.toString() } + + var conversions : MutableMap = new.type.asClass()!!.enumConstants.map { it.toString() } + .union(defaultRules?.map { it.new }?.toSet() ?: emptySet()) + .union(renameRules?.map { it.to } ?: emptySet()) + .associateBy({ it }, { it }) + .toMutableMap() + + val rules : MutableMap = mutableMapOf() + rules.putAll(defaultRules?.associateBy({ it.new }, { it.old }) ?: emptyMap()) + rules.putAll(renameRules?.associateBy({ it.to }, { it.from }) ?: emptyMap()) + + while (conversions.filter { it.value !in localVals }.isNotEmpty()) { + conversions.mapInPlace { rules[it] ?: it } + } + + var idx = 0 + return EnumEvolutionSerializer(new.type, factory, conversions, localVals.associateBy( {it}, { idx++ })) + } + } + + override fun readObject(obj: Any, schemas: SerializationSchemas, input: DeserializationInput): Any { + var enumName = (obj as List<*>)[0] as String + + if (enumName !in conversions) { + throw NotSerializableException ("No rule to evolve enum constant $type::$enumName") + } + + return type.asClass()!!.enumConstants[ordinals[conversions[enumName]]!!] + } + + override fun writeClassInfo(output: SerializationOutput) { + throw IllegalAccessException("It should be impossible to write an evolution serializer") + } + + override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) { + throw IllegalAccessException("It should be impossible to write an evolution serializer") + } +} \ No newline at end of file diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt index d310f5a6bb..764f0b5458 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt @@ -50,7 +50,7 @@ open class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) { return serializersByDescriptor.computeIfAbsent(typeNotation.descriptor.name!!) { when (typeNotation) { is CompositeType -> EvolutionSerializer.make(typeNotation, newSerializer as ObjectSerializer, this) - is RestrictedType -> throw NotSerializableException("Enum evolution is not currently supported") + is RestrictedType -> EnumEvolutionSerializer.make(typeNotation, newSerializer, this, transforms) } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt index 5bb6fc05d5..6fd1e4a95f 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TansformTypes.kt @@ -27,14 +27,62 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType Unknown({ UnknownTransform() }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + override fun validate(l : List, constants: Set) { } }, EnumDefault({ a -> EnumDefaultSchemaTransform((a as CordaSerializationTransformEnumDefault).old, a.new) }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + + /** + * Validates a list of constant additions to an enumerated types, to be valid a default (the value + * that should be used when we cannot use the new value) must refer to a constant that exists in the + * enum class as it exists now and it cannot refer to itself. + * + * @param l The list of transforms representing new constants and the mapping from that constant to an + * existing value + * @param constants The list of enum constants on the type the transforms are being applied to + */ + override fun validate(l : List, constants: Set) { + @Suppress("UNCHECKED_CAST") (l as List).forEach { + if (!constants.contains(it.old)) { + throw NotSerializableException( + "Enum extension defaults must be to a valid constant: ${it.new} -> ${it.old}. ${it.old} " + + "doesn't exist in constant set $constants") + } + + if (it.old == it.new) { + throw NotSerializableException("Enum extension ${it.new} cannot default to itself") + } + } + } }, Rename({ a -> RenameSchemaTransform((a as CordaSerializationTransformRename).from, a.to) }) { override fun getDescriptor(): Any = DESCRIPTOR override fun getDescribed(): Any = ordinal + + /** + * Validates a list of rename transforms is valid. Such a list isn't valid if we detect a cyclic chain, + * that is a constant is renamed to something that used to exist in the enum. We do this for both + * the same constant (i.e. C -> D -> C) and multiple constants (C->D, B->C) + * + * @param l The list of transforms representing the renamed constants and the mapping between their new + * and old values + * @param constants The list of enum constants on the type the transforms are being applied to + */ + override fun validate(l : List, constants: Set) { + object : Any() { + val from : MutableSet = mutableSetOf() + val to : MutableSet = mutableSetOf() }.apply { + @Suppress("UNCHECKED_CAST") (l as List).forEach { rename -> + if (rename.to in this.to || rename.from in this.from) { + throw NotSerializableException("Cyclic renames are not allowed (${rename.to})") + } + + this.to.add(rename.from) + this.from.add(rename.to) + } + } + } } // Transform used to test the unknown handler, leave this at as the final constant, uncomment // when regenerating test cases - if Java had a pre-processor this would be much neater @@ -45,6 +93,8 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType //} ; + abstract fun validate(l: List, constants: Set) + companion object : DescribedTypeConstructor { val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_ELEMENT_KEY.amqpDescriptor diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt index 974de134b1..a8409a64c3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/TransformsSchema.kt @@ -148,6 +148,8 @@ class EnumDefaultSchemaTransform(val old: String, val new: String) : Transform() * * @property from the name at time of change of the property * @property to the new name of the property + * + * */ class RenameSchemaTransform(val from: String, val to: String) : Transform() { companion object : DescribedTypeConstructor { @@ -192,6 +194,61 @@ data class TransformsSchema(val types: Map { val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_SCHEMA.amqpDescriptor + /** + * Takes a class name and either returns a cached instance of the TransformSet for it or, on a cache miss, + * instantiates the transform set before inserting into the cache and returning it. + * + * @param name fully qualified class name to lookup transforms for + * @param sf the [SerializerFactory] building this transform set. Needed as each can define it's own + * class loader and this dictates which classes we can and cannot see + */ + fun get(name: String, sf: SerializerFactory) = sf.transformsCache.computeIfAbsent(name) { + val transforms = EnumMap>(TransformTypes::class.java) + try { + val clazz = sf.classloader.loadClass(name) + + supportedTransforms.forEach { transform -> + clazz.getAnnotation(transform.type)?.let { list -> + transform.getAnnotations(list).forEach { annotation -> + val t = transform.enum.build(annotation) + + // we're explicitly rejecting repeated annotations, whilst it's fine and we'd just + // ignore them it feels like a good thing to alert the user to since this is + // more than likely a typo in their code so best make it an actual error + if (transforms.computeIfAbsent(transform.enum) { mutableListOf() } + .filter { t == it } + .isNotEmpty()) { + throw NotSerializableException( + "Repeated unique transformation annotation of type ${t.name}") + } + + transforms[transform.enum]!!.add(t) + } + + transform.enum.validate( + transforms[transform.enum] ?: emptyList(), + clazz.enumConstants.map { it.toString() }.toSet()) + } + } + } catch (_: ClassNotFoundException) { + // if we can't load the class we'll end up caching an empty list which is fine as that + // list, on lookup, won't be included in the schema because it's empty + } + + transforms + } + + private fun getAndAdd( + type: String, + sf: SerializerFactory, + map: MutableMap>>) { + get(type, sf).apply { + if (isNotEmpty()) { + map[type] = this + } + } + } + /** * Prepare a schema for encoding, takes all of the types being transmitted and inspects each * one for any transform annotations. If there are any build up a set that can be @@ -200,48 +257,10 @@ data class TransformsSchema(val types: Map>>() - - schema.types.forEach { type -> - sf.transformsCache.computeIfAbsent(type.name) { - val transforms = EnumMap>(TransformTypes::class.java) - try { - val clazz = sf.classloader.loadClass(type.name) - - supportedTransforms.forEach { transform -> - clazz.getAnnotation(transform.type)?.let { list -> - transform.getAnnotations(list).forEach { annotation -> - val t = transform.enum.build(annotation) - - // we're explicitly rejecting repeated annotations, whilst it's fine and we'd just - // ignore them it feels like a good thing to alert the user to since this is - // more than likely a typo in their code so best make it an actual error - if (transforms.computeIfAbsent(transform.enum) { mutableListOf() } - .filter { t == it }.isNotEmpty()) { - throw NotSerializableException( - "Repeated unique transformation annotation of type ${t.name}") - } - - transforms[transform.enum]!!.add(t) - } - } - } - } catch (_: ClassNotFoundException) { - // if we can't load the class we'll end up caching an empty list which is fine as that - // list, on lookup, won't be included in the schema because it's empty - } - - transforms - }.apply { - if (isNotEmpty()) { - rtn[type.name] = this - } - } - } - - return TransformsSchema(rtn) - } + fun build(schema: Schema, sf: SerializerFactory) = TransformsSchema( + mutableMapOf>>().apply { + schema.types.forEach { type -> getAndAdd(type.name, sf, this) } + }) override fun getTypeClass(): Class<*> = TransformsSchema::class.java @@ -286,6 +305,7 @@ data class TransformsSchema(val types: Map(File(path.toURI()).readBytes())) + + assertEquals (DeserializeNewerSetToUnknown.C, obj.e) + } + + // Version of the class as it was serialised + // + // @CordaSerializationTransformEnumDefaults ( + // CordaSerializationTransformEnumDefault("D", "C"), + // CordaSerializationTransformEnumDefault("E", "D")) + // enum class DeserializeNewerSetToUnknown2 { A, B, C, D, E } + // + // Version of the class as it's used in the test + enum class DeserializeNewerSetToUnknown2 { A, B, C } + + @Test + fun deserialiseNewerSetToUnknown2() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeNewerSetToUnknown2) + + // Uncomment to re-generate test files + // val so = SerializationOutput(sf) + // File(URI("$localPath/$resource.C")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.C)).bytes) + // File(URI("$localPath/$resource.D")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.D)).bytes) + // File(URI("$localPath/$resource.E")).writeBytes(so.serialize(C(DeserializeNewerSetToUnknown2.E)).bytes) + + val path1 = EvolvabilityTests::class.java.getResource("$resource.C") + val path2 = EvolvabilityTests::class.java.getResource("$resource.D") + val path3 = EvolvabilityTests::class.java.getResource("$resource.E") + + // C will just work + val obj1 = DeserializationInput(sf).deserialize(SerializedBytes(File(path1.toURI()).readBytes())) + // D will transform directly to C + val obj2 = DeserializationInput(sf).deserialize(SerializedBytes(File(path2.toURI()).readBytes())) + // E will have to transform from E -> D -> C to work, so this should exercise that part + // of the evolution code + val obj3 = DeserializationInput(sf).deserialize(SerializedBytes(File(path3.toURI()).readBytes())) + + assertEquals (DeserializeNewerSetToUnknown2.C, obj1.e) + assertEquals (DeserializeNewerSetToUnknown2.C, obj2.e) + assertEquals (DeserializeNewerSetToUnknown2.C, obj3.e) + } + + + // Version of the class as it was serialised, evolve rule purposfuly not included to + // test failure conditions + // + // enum class DeserializeNewerWithNoRule { A, B, C, D } + // + // Class as it exists for the test + enum class DeserializeNewerWithNoRule { A, B, C } + + // Lets test to see if they forgot to provide an upgrade rule + @Test + fun deserialiseNewerWithNoRule() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeNewerWithNoRule) + + // Uncomment to re-generate test files + // val so = SerializationOutput(sf) + // File(URI("$localPath/$resource")).writeBytes(so.serialize(C(DeserializeNewerWithNoRule.D)).bytes) + + val path = EvolvabilityTests::class.java.getResource(resource) + Assertions.assertThatThrownBy { - DeserializationInput(sf).deserialize(SerializedBytes( - File(EvolvabilityTests::class.java.getResource(resource).toURI()).readBytes())) + DeserializationInput(sf).deserialize(SerializedBytes(File(path.toURI()).readBytes())) }.isInstanceOf(NotSerializableException::class.java) } + + // Version of class as it was serialized, at some point in the "future" several + // values have been renamed + // + // First Change + // A -> AA + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from ="A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, B, C } + // + // Second Change + // B -> BB + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from = "B", to = "BB"), + // CordaSerializationTransformRename(from = "A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, BB, C } + // + // Third Change + // BB -> XX + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(from = "B", to = "BB"), + // CordaSerializationTransformRename(from = "BB", to = "XX"), + // CordaSerializationTransformRename(from = "A", to = "AA") + // ) + // enum class DeserializeWithRename { AA, XX, C } + // + // Finally, the version we're using to test with + enum class DeserializeWithRename { A, B, C } + + @Test + fun deserializeWithRename() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: DeserializeWithRename) + + // Uncomment to re-generate test files, needs to be done in three stages + val so = SerializationOutput(sf) + // First change + // File(URI("$localPath/$resource.1.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.1.B")).writeBytes(so.serialize(C(DeserializeWithRename.B)).bytes) + // File(URI("$localPath/$resource.1.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + // Second change + // File(URI("$localPath/$resource.2.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.2.BB")).writeBytes(so.serialize(C(DeserializeWithRename.BB)).bytes) + // File(URI("$localPath/$resource.2.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + // Third change + // File(URI("$localPath/$resource.3.AA")).writeBytes(so.serialize(C(DeserializeWithRename.AA)).bytes) + // File(URI("$localPath/$resource.3.XX")).writeBytes(so.serialize(C(DeserializeWithRename.XX)).bytes) + // File(URI("$localPath/$resource.3.C")).writeBytes(so.serialize(C(DeserializeWithRename.C)).bytes) + + // + // Test we can deserialize instances of the class after its first transformation + // + val path1_AA = EvolvabilityTests::class.java.getResource("$resource.1.AA") + val path1_B = EvolvabilityTests::class.java.getResource("$resource.1.B") + val path1_C = EvolvabilityTests::class.java.getResource("$resource.1.C") + + val obj1_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_AA.toURI()).readBytes())) + val obj1_B = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_B.toURI()).readBytes())) + val obj1_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path1_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj1_AA.e) + assertEquals(DeserializeWithRename.B, obj1_B.e) + assertEquals(DeserializeWithRename.C, obj1_C.e) + + // + // Test we can deserialize instances of the class after its second transformation + // + val path2_AA = EvolvabilityTests::class.java.getResource("$resource.2.AA") + val path2_BB = EvolvabilityTests::class.java.getResource("$resource.2.BB") + val path2_C = EvolvabilityTests::class.java.getResource("$resource.2.C") + + val obj2_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_AA.toURI()).readBytes())) + val obj2_BB = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_BB.toURI()).readBytes())) + val obj2_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path2_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj2_AA.e) + assertEquals(DeserializeWithRename.B, obj2_BB.e) + assertEquals(DeserializeWithRename.C, obj2_C.e) + + // + // Test we can deserialize instances of the class after its third transformation + // + val path3_AA = EvolvabilityTests::class.java.getResource("$resource.3.AA") + val path3_XX = EvolvabilityTests::class.java.getResource("$resource.3.XX") + val path3_C = EvolvabilityTests::class.java.getResource("$resource.3.C") + + val obj3_AA = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_AA.toURI()).readBytes())) + val obj3_XX = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_XX.toURI()).readBytes())) + val obj3_C = DeserializationInput(sf).deserialize(SerializedBytes(File(path3_C.toURI()).readBytes())) + + assertEquals(DeserializeWithRename.A, obj3_AA.e) + assertEquals(DeserializeWithRename.B, obj3_XX.e) + assertEquals(DeserializeWithRename.C, obj3_C.e) + } + + // The origional version of the enum, what we'll be eventually deserialising into + // enum class MultiOperations { A, B, C } + // + // First alteration, add D + // @CordaSerializationTransformEnumDefault(old = "C", new = "D") + // enum class MultiOperations { A, B, C, D } + // + // Second, add E + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "C", new = "D"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E") + // ) + // enum class MultiOperations { A, B, C, D, E } + // + // Third, Rename E to BOB + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "C", new = "D"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E") + // ) + // @CordaSerializationTransformRename(to = "BOB", from = "E") + // enum class MultiOperations { A, B, C, D, BOB } + // + // Fourth, Rename C to CAT, ADD F and G + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "F", new = "G"), + // CordaSerializationTransformEnumDefault(old = "BOB", new = "F"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E"), + // CordaSerializationTransformEnumDefault(old = "C", new = "D") + // ) + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(to = "CAT", from = "C"), + // CordaSerializationTransformRename(to = "BOB", from = "E") + // ) + // enum class MultiOperations { A, B, CAT, D, BOB, F, G} + // + // Fifth, Rename F to FLUMP, Rename BOB to BBB, Rename A to APPLE + // @CordaSerializationTransformEnumDefaults( + // CordaSerializationTransformEnumDefault(old = "F", new = "G"), + // CordaSerializationTransformEnumDefault(old = "BOB", new = "F"), + // CordaSerializationTransformEnumDefault(old = "D", new = "E"), + // CordaSerializationTransformEnumDefault(old = "C", new = "D") + // ) + // @CordaSerializationTransformRenames ( + // CordaSerializationTransformRename(to = "APPLE", from = "A"), + // CordaSerializationTransformRename(to = "BBB", from = "BOB"), + // CordaSerializationTransformRename(to = "FLUMP", from = "F"), + // CordaSerializationTransformRename(to = "CAT", from = "C"), + // CordaSerializationTransformRename(to = "BOB", from = "E") + // ) + // enum class MultiOperations { APPLE, B, CAT, D, BBB, FLUMP, G} + // + // Finally, the original version of teh class that we're going to be testing with + enum class MultiOperations { A, B, C } + + @Test + fun multiOperations() { + val resource = "${this.javaClass.simpleName}.${testName()}" + val sf = testDefaultFactory() + + data class C(val e: MultiOperations) + + // Uncomment to re-generate test files, needs to be done in three stages + val so = SerializationOutput(sf) + // First change + // File(URI("$localPath/$resource.1.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.1.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.1.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.1.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // Second change + // File(URI("$localPath/$resource.2.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.2.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.2.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.2.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.2.E")).writeBytes(so.serialize(C(MultiOperations.E)).bytes) + // Third change + // File(URI("$localPath/$resource.3.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.3.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.3.C")).writeBytes(so.serialize(C(MultiOperations.C)).bytes) + // File(URI("$localPath/$resource.3.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.3.BOB")).writeBytes(so.serialize(C(MultiOperations.BOB)).bytes) + // Fourth change + // File(URI("$localPath/$resource.4.A")).writeBytes(so.serialize(C(MultiOperations.A)).bytes) + // File(URI("$localPath/$resource.4.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.4.CAT")).writeBytes(so.serialize(C(MultiOperations.CAT)).bytes) + // File(URI("$localPath/$resource.4.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.4.BOB")).writeBytes(so.serialize(C(MultiOperations.BOB)).bytes) + // File(URI("$localPath/$resource.4.F")).writeBytes(so.serialize(C(MultiOperations.F)).bytes) + // File(URI("$localPath/$resource.4.G")).writeBytes(so.serialize(C(MultiOperations.G)).bytes) + // Fifth change - { APPLE, B, CAT, D, BBB, FLUMP, G} + // File(URI("$localPath/$resource.5.APPLE")).writeBytes(so.serialize(C(MultiOperations.APPLE)).bytes) + // File(URI("$localPath/$resource.5.B")).writeBytes(so.serialize(C(MultiOperations.B)).bytes) + // File(URI("$localPath/$resource.5.CAT")).writeBytes(so.serialize(C(MultiOperations.CAT)).bytes) + // File(URI("$localPath/$resource.5.D")).writeBytes(so.serialize(C(MultiOperations.D)).bytes) + // File(URI("$localPath/$resource.5.BBB")).writeBytes(so.serialize(C(MultiOperations.BBB)).bytes) + // File(URI("$localPath/$resource.5.FLUMP")).writeBytes(so.serialize(C(MultiOperations.FLUMP)).bytes) + // File(URI("$localPath/$resource.5.G")).writeBytes(so.serialize(C(MultiOperations.G)).bytes) + + val stage1Resources = listOf( + Pair("$resource.1.A", MultiOperations.A), + Pair("$resource.1.B", MultiOperations.B), + Pair("$resource.1.C", MultiOperations.C), + Pair("$resource.1.D", MultiOperations.C)) + + val stage2Resources = listOf( + Pair("$resource.2.A", MultiOperations.A), + Pair("$resource.2.B", MultiOperations.B), + Pair("$resource.2.C", MultiOperations.C), + Pair("$resource.2.D", MultiOperations.C), + Pair("$resource.2.E", MultiOperations.C)) + + val stage3Resources = listOf( + Pair("$resource.3.A", MultiOperations.A), + Pair("$resource.3.B", MultiOperations.B), + Pair("$resource.3.C", MultiOperations.C), + Pair("$resource.3.D", MultiOperations.C), + Pair("$resource.3.BOB", MultiOperations.C)) + + val stage4Resources = listOf( + Pair("$resource.4.A", MultiOperations.A), + Pair("$resource.4.B", MultiOperations.B), + Pair("$resource.4.CAT", MultiOperations.C), + Pair("$resource.4.D", MultiOperations.C), + Pair("$resource.4.BOB", MultiOperations.C), + Pair("$resource.4.F", MultiOperations.C), + Pair("$resource.4.G", MultiOperations.C)) + + val stage5Resources = listOf( + Pair("$resource.5.APPLE", MultiOperations.A), + Pair("$resource.5.B", MultiOperations.B), + Pair("$resource.5.CAT", MultiOperations.C), + Pair("$resource.5.D", MultiOperations.C), + Pair("$resource.5.BBB", MultiOperations.C), + Pair("$resource.5.FLUMP", MultiOperations.C), + Pair("$resource.5.G", MultiOperations.C)) + + fun load(l: List>) = l.map { + Pair (DeserializationInput(sf).deserialize(SerializedBytes( + File(EvolvabilityTests::class.java.getResource(it.first).toURI()).readBytes())), it.second) + } + + load (stage1Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage2Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage3Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage4Resources).forEach { assertEquals(it.second, it.first.e) } + load (stage5Resources).forEach { assertEquals(it.second, it.first.e) } + } } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt index 173e7fd87c..10a59e1414 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/EvolvabilityTests.kt @@ -2,6 +2,7 @@ package net.corda.nodeapi.internal.serialization.amqp import net.corda.core.serialization.DeprecatedConstructorForDeserialization import net.corda.core.serialization.SerializedBytes +import net.corda.testing.common.internal.ProjectStructure.projectRootDir import org.junit.Test import java.io.File import java.io.NotSerializableException @@ -18,7 +19,8 @@ import kotlin.test.assertEquals // 5. Comment back out the generation code and uncomment the actual test class EvolvabilityTests { // When regenerating the test files this needs to be set to the file system location of the resource files - var localPath = "file://////corda/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp" + var localPath = projectRootDir.toUri().resolve( + "node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp") @Test fun simpleOrderSwapSameType() { diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C new file mode 100644 index 0000000000..cced4f8de7 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.D new file mode 100644 index 0000000000..998ec49f9a Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.E b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.E new file mode 100644 index 0000000000..cd62f21adb Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerSetToUnknown2.E differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerWithNoRule b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerWithNoRule new file mode 100644 index 0000000000..58cf98b4ad Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserialiseNewerWithNoRule differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.AA b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.AA new file mode 100644 index 0000000000..16b9b723f8 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.AA differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.B new file mode 100644 index 0000000000..fb59df3314 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C new file mode 100644 index 0000000000..33425ddb68 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.1.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA new file mode 100644 index 0000000000..4f75773756 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.AA differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB new file mode 100644 index 0000000000..521bf9ec2f Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.BB differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.C new file mode 100644 index 0000000000..62448e369e Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.2.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.AA b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.AA new file mode 100644 index 0000000000..c597affc7b Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.AA differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C new file mode 100644 index 0000000000..5e90893cb4 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.XX b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.XX new file mode 100644 index 0000000000..86d9a16721 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.deserializeWithRename.3.XX differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A new file mode 100644 index 0000000000..c28d480977 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.A differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B new file mode 100644 index 0000000000..4f5e9ab81c Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C new file mode 100644 index 0000000000..6fd1917beb Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D new file mode 100644 index 0000000000..2ca115091f Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.1.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A new file mode 100644 index 0000000000..434b43c42a Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.A differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B new file mode 100644 index 0000000000..f216584cdf Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.C new file mode 100644 index 0000000000..864da60e34 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D new file mode 100644 index 0000000000..71b890bdef Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E new file mode 100644 index 0000000000..cf15290a05 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.2.E differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A new file mode 100644 index 0000000000..26cbcc8f4e Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.A differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.B new file mode 100644 index 0000000000..8478191ec9 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB new file mode 100644 index 0000000000..87a4636599 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.BOB differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.C b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.C new file mode 100644 index 0000000000..d66d774640 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.C differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.D new file mode 100644 index 0000000000..0bc8084e62 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.3.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.A b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.A new file mode 100644 index 0000000000..40f7c037d2 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.A differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.B new file mode 100644 index 0000000000..5d996bfe14 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB new file mode 100644 index 0000000000..b741fceac9 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.BOB differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.CAT b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.CAT new file mode 100644 index 0000000000..bb229ddc82 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.CAT differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.D new file mode 100644 index 0000000000..becaee5fa6 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F new file mode 100644 index 0000000000..b9bedc2502 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.F differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.G b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.G new file mode 100644 index 0000000000..bd93f918dc Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.4.G differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE new file mode 100644 index 0000000000..95b55e36de Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.APPLE differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B new file mode 100644 index 0000000000..f6aaf7d2ff Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.B differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.BBB b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.BBB new file mode 100644 index 0000000000..cd181d1b7c Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.BBB differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT new file mode 100644 index 0000000000..27d9d766f7 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.CAT differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.D b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.D new file mode 100644 index 0000000000..54420c13fb Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.D differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP new file mode 100644 index 0000000000..86b4ed8e6a Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.FLUMP differ diff --git a/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.G b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.G new file mode 100644 index 0000000000..92ed95c4d8 Binary files /dev/null and b/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp/EnumEvolveTests.multiOperations.5.G differ