diff --git a/libs/membership/membership-impl/build.gradle b/libs/membership/membership-impl/build.gradle index 6965bd5bd8b..094eb05390e 100644 --- a/libs/membership/membership-impl/build.gradle +++ b/libs/membership/membership-impl/build.gradle @@ -26,8 +26,11 @@ dependencies { implementation "net.corda:corda-membership" implementation 'net.corda:corda-serialization' + testImplementation project(':libs:crypto:cipher-suite-impl') testImplementation project(":libs:crypto:crypto-impl") testImplementation project(":testing:layered-property-map-testkit") + testImplementation project(':testing:test-serialization') + testImplementation project(':libs:serialization:serialization-amqp') testImplementation project(":testing:test-utilities") testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlinVersion" diff --git a/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/MemberInfoTest.kt b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/MemberInfoTest.kt index e0e50c97c3c..f5cce2229e7 100644 --- a/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/MemberInfoTest.kt +++ b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/MemberInfoTest.kt @@ -1,6 +1,5 @@ package net.corda.membership.lib.impl -import net.corda.crypto.cipher.suite.CipherSchemeMetadata import net.corda.crypto.impl.converter.PublicKeyConverter import net.corda.data.KeyValuePairList import net.corda.data.crypto.wire.CryptoSignatureSpec @@ -9,28 +8,17 @@ import net.corda.data.membership.SignedData import net.corda.data.membership.SignedMemberInfo import net.corda.layeredpropertymap.testkit.LayeredPropertyMapMocks import net.corda.layeredpropertymap.toAvro -import net.corda.membership.lib.EndpointInfoFactory -import net.corda.membership.lib.MemberInfoExtension.Companion.GROUP_ID import net.corda.membership.lib.MemberInfoExtension.Companion.LEDGER_KEYS -import net.corda.membership.lib.MemberInfoExtension.Companion.LEDGER_KEYS_KEY -import net.corda.membership.lib.MemberInfoExtension.Companion.MEMBER_STATUS_ACTIVE -import net.corda.membership.lib.MemberInfoExtension.Companion.MODIFIED_TIME -import net.corda.membership.lib.MemberInfoExtension.Companion.PARTY_NAME -import net.corda.membership.lib.MemberInfoExtension.Companion.PARTY_SESSION_KEYS -import net.corda.membership.lib.MemberInfoExtension.Companion.PLATFORM_VERSION -import net.corda.membership.lib.MemberInfoExtension.Companion.PROTOCOL_VERSION -import net.corda.membership.lib.MemberInfoExtension.Companion.SERIAL -import net.corda.membership.lib.MemberInfoExtension.Companion.SOFTWARE_VERSION -import net.corda.membership.lib.MemberInfoExtension.Companion.STATUS -import net.corda.membership.lib.MemberInfoExtension.Companion.URL_KEY import net.corda.membership.lib.MemberInfoExtension.Companion.endpoints import net.corda.membership.lib.MemberInfoExtension.Companion.groupId import net.corda.membership.lib.MemberInfoExtension.Companion.modifiedTime import net.corda.membership.lib.MemberInfoExtension.Companion.status import net.corda.membership.lib.impl.converter.EndpointInfoConverter import net.corda.membership.lib.impl.converter.MemberNotaryDetailsConverter +import net.corda.membership.lib.impl.utils.createDummyMemberInfo +import net.corda.membership.lib.impl.utils.keyEncodingService +import net.corda.membership.lib.impl.utils.ledgerKeys import net.corda.membership.lib.toSortedMap -import net.corda.test.util.time.TestClock import net.corda.utilities.parse import net.corda.utilities.parseList import net.corda.v5.base.exceptions.ValueNotFoundException @@ -45,16 +33,8 @@ import org.apache.avro.specific.SpecificDatumWriter import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test -import org.mockito.Mockito -import org.mockito.kotlin.any -import org.mockito.kotlin.doAnswer -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock -import org.mockito.kotlin.whenever import java.io.File import java.nio.ByteBuffer -import java.security.PublicKey -import java.time.Instant import kotlin.test.assertFailsWith import kotlin.test.assertNotNull import kotlin.test.assertNull @@ -63,26 +43,6 @@ import kotlin.test.assertTrue @Suppress("MaxLineLength") class MemberInfoTest { companion object { - private val keyEncodingService = Mockito.mock(CipherSchemeMetadata::class.java) - private const val KEY = "12345" - private val key = Mockito.mock(PublicKey::class.java) - - - private val clock = TestClock(Instant.ofEpochSecond(100)) - private val modifiedTime = clock.instant() - private val endpointInfoFactory: EndpointInfoFactory = mock { - on { create(any(), any()) } doAnswer { invocation -> - mock { - on { this.url } doReturn invocation.getArgument(0) - on { this.protocolVersion } doReturn invocation.getArgument(1) - } - } - } - private val endpoints = listOf( - endpointInfoFactory.create("https://localhost:10000"), - endpointInfoFactory.create("https://google.com", 10) - ) - private val ledgerKeys = listOf(key, key) private val testObjects = listOf( DummyObjectWithNumberAndText(1, "dummytext1"), DummyObjectWithNumberAndText(2, "dummytext2") @@ -98,59 +58,12 @@ class MemberInfoTest { DummyConverter() ) - private const val NULL_KEY = "nullKey" private const val DUMMY_KEY = "dummyKey" private const val INVALID_LIST_KEY = "invalidList" private val MemberInfo.dummy: List get() = memberProvidedContext.parseList(INVALID_LIST_KEY) - @Suppress("SpreadOperator") - private fun createDummyMemberInfo(): MemberInfo = MemberInfoImpl( - memberProvidedContext = LayeredPropertyMapMocks.create( - sortedMapOf( - PARTY_NAME to "O=Alice,L=London,C=GB", - String.format(PARTY_SESSION_KEYS, 0) to KEY, - GROUP_ID to "DEFAULT_MEMBER_GROUP_ID", - *convertPublicKeys().toTypedArray(), - *convertEndpoints().toTypedArray(), - *convertTestObjects().toTypedArray(), - *createInvalidListFormat().toTypedArray(), - SOFTWARE_VERSION to "5.0.0", - PLATFORM_VERSION to "5000", - DUMMY_KEY to "dummyValue", - NULL_KEY to null, - ), - converters - ), - mgmProvidedContext = LayeredPropertyMapMocks.create( - sortedMapOf( - STATUS to MEMBER_STATUS_ACTIVE, - MODIFIED_TIME to modifiedTime.toString(), - DUMMY_KEY to "dummyValue", - SERIAL to "1", - ), - converters - ) - ) - - private fun convertEndpoints(): List> { - val result = mutableListOf>() - for (i in endpoints.indices) { - result.add(Pair(String.format(URL_KEY, i), endpoints[i].url)) - result.add(Pair(String.format(PROTOCOL_VERSION, i), endpoints[i].protocolVersion.toString())) - } - return result - } - - private fun convertPublicKeys(): List> = - ledgerKeys.mapIndexed { i, ledgerKey -> - String.format( - LEDGER_KEYS_KEY, - i - ) to keyEncodingService.encodeAsString(ledgerKey) - } - private fun convertTestObjects(): List> { val result = mutableListOf>() for (i in testObjects.indices) { @@ -182,14 +95,10 @@ class MemberInfoTest { @BeforeAll @JvmStatic fun setUp() { - whenever( - keyEncodingService.decodePublicKey(KEY) - ).thenReturn(key) - whenever( - keyEncodingService.encodeAsString(key) - ).thenReturn(KEY) - - memberInfo = createDummyMemberInfo() + memberInfo = createDummyMemberInfo( + converters = converters, + additionalMemberContext = convertTestObjects() + createInvalidListFormat(), + ) } } diff --git a/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MGMContextSerializerTest.kt b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MGMContextSerializerTest.kt new file mode 100644 index 00000000000..dbb5aad1ff1 --- /dev/null +++ b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MGMContextSerializerTest.kt @@ -0,0 +1,37 @@ +package net.corda.membership.lib.impl.serializer.amqp + +import net.corda.cipher.suite.impl.CipherSchemeMetadataImpl +import net.corda.crypto.impl.converter.PublicKeyConverter +import net.corda.internal.serialization.amqp.helper.TestSerializationService +import net.corda.layeredpropertymap.testkit.LayeredPropertyMapMocks +import net.corda.membership.lib.impl.converter.EndpointInfoConverter +import net.corda.membership.lib.impl.converter.MemberNotaryDetailsConverter +import net.corda.membership.lib.impl.utils.createDummyMgmContext +import net.corda.v5.membership.MGMContext +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test + +class MGMContextSerializerTest { + private companion object { + val cipherSchemeMetadata = CipherSchemeMetadataImpl() + val converters = listOf( + EndpointInfoConverter(), + MemberNotaryDetailsConverter(cipherSchemeMetadata), + PublicKeyConverter(cipherSchemeMetadata), + ) + val layeredPropertyMapFactory = LayeredPropertyMapMocks.createFactory(converters) + val mgmContextSerializer = MGMContextSerializer(layeredPropertyMapFactory) + + val serializationServiceWithWireTx = TestSerializationService.getTestSerializationService({ + it.register(mgmContextSerializer, it) + }, cipherSchemeMetadata) + } + + @Test + fun `Should serialize and then deserialize MGMContext`() { + val mgmContext = createDummyMgmContext(converters) as MGMContext + val serialized = serializationServiceWithWireTx.serialize(mgmContext) + val deserialized = serializationServiceWithWireTx.deserialize(serialized, MGMContext::class.java) + Assertions.assertThat(deserialized).isEqualTo(mgmContext) + } +} diff --git a/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MemberContextSerializerTest.kt b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MemberContextSerializerTest.kt new file mode 100644 index 00000000000..736b051187c --- /dev/null +++ b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/serializer/amqp/MemberContextSerializerTest.kt @@ -0,0 +1,37 @@ +package net.corda.membership.lib.impl.serializer.amqp + +import net.corda.cipher.suite.impl.CipherSchemeMetadataImpl +import net.corda.crypto.impl.converter.PublicKeyConverter +import net.corda.internal.serialization.amqp.helper.TestSerializationService +import net.corda.layeredpropertymap.testkit.LayeredPropertyMapMocks +import net.corda.membership.lib.impl.converter.EndpointInfoConverter +import net.corda.membership.lib.impl.converter.MemberNotaryDetailsConverter +import net.corda.membership.lib.impl.utils.createDummyMemberContext +import net.corda.v5.membership.MemberContext +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class MemberContextSerializerTest { + private companion object { + val cipherSchemeMetadata = CipherSchemeMetadataImpl() + val converters = listOf( + EndpointInfoConverter(), + MemberNotaryDetailsConverter(cipherSchemeMetadata), + PublicKeyConverter(cipherSchemeMetadata), + ) + val layeredPropertyMapFactory = LayeredPropertyMapMocks.createFactory(converters) + val memberContextSerializer = MemberContextSerializer(layeredPropertyMapFactory) + + val serializationServiceWithWireTx = TestSerializationService.getTestSerializationService({ + it.register(memberContextSerializer, it) + }, cipherSchemeMetadata) + } + + @Test + fun `Should serialize and then deserialize MemberContext`() { + val memberContext = createDummyMemberContext(converters) as MemberContext + val serialized = serializationServiceWithWireTx.serialize(memberContext) + val deserialized = serializationServiceWithWireTx.deserialize(serialized, MemberContext::class.java) + assertThat(deserialized).isEqualTo(memberContext) + } +} diff --git a/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/utils/MemberInfoTestUtils.kt b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/utils/MemberInfoTestUtils.kt new file mode 100644 index 00000000000..0c39a7e99e7 --- /dev/null +++ b/libs/membership/membership-impl/src/test/kotlin/net/corda/membership/lib/impl/utils/MemberInfoTestUtils.kt @@ -0,0 +1,104 @@ +package net.corda.membership.lib.impl.utils + +import net.corda.crypto.cipher.suite.CipherSchemeMetadata +import net.corda.layeredpropertymap.CustomPropertyConverter +import net.corda.layeredpropertymap.testkit.LayeredPropertyMapMocks +import net.corda.membership.lib.EndpointInfoFactory +import net.corda.membership.lib.MemberInfoExtension +import net.corda.membership.lib.impl.MGMContextImpl +import net.corda.membership.lib.impl.MemberContextImpl +import net.corda.membership.lib.impl.MemberInfoImpl +import net.corda.test.util.time.TestClock +import net.corda.v5.membership.MemberInfo +import org.mockito.Mockito +import org.mockito.kotlin.any +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import java.security.PublicKey +import java.time.Instant +import java.util.UUID + +private const val KEY = "12345" +private val key: PublicKey = Mockito.mock(PublicKey::class.java) +internal val keyEncodingService: CipherSchemeMetadata = mock { + on { decodePublicKey(KEY) } doReturn key + on { encodeAsString(key) } doReturn KEY +} + +private val clock = TestClock(Instant.ofEpochSecond(100)) +private val modifiedTime = clock.instant() +private val endpointInfoFactory: EndpointInfoFactory = mock { + on { create(any(), any()) } doAnswer { invocation -> + mock { + on { this.url } doReturn invocation.getArgument(0) + on { this.protocolVersion } doReturn invocation.getArgument(1) + } + } +} +private val endpoints = listOf( + endpointInfoFactory.create("https://localhost:10000"), endpointInfoFactory.create("https://google.com", 10) +) +internal val ledgerKeys = listOf(key, key) + +private const val NULL_KEY = "nullKey" +private const val DUMMY_KEY = "dummyKey" + +@Suppress("SpreadOperator") +fun createDummyMemberInfo( + converters: List>, + additionalMemberContext: List> = emptyList(), +): MemberInfo = MemberInfoImpl( + memberProvidedContext = createDummyMemberContext(converters, additionalMemberContext), + mgmProvidedContext = createDummyMgmContext(converters) +) + +@Suppress("SpreadOperator") +fun createDummyMemberContext( + converters: List>, + additionalMemberContext: List> = emptyList(), +) = LayeredPropertyMapMocks.create( + sortedMapOf( + MemberInfoExtension.PARTY_NAME to "O=Alice,L=London,C=GB", + String.format(MemberInfoExtension.PARTY_SESSION_KEYS, 0) to KEY, + MemberInfoExtension.GROUP_ID to UUID(0,1).toString(), + *convertPublicKeys().toTypedArray(), + *convertEndpoints().toTypedArray(), + MemberInfoExtension.SOFTWARE_VERSION to "5.0.0", + MemberInfoExtension.PLATFORM_VERSION to "5000", + DUMMY_KEY to "dummyValue", + NULL_KEY to null, + *additionalMemberContext.toTypedArray(), + ), converters +) + +fun createDummyMgmContext( + converters: List>, +) = LayeredPropertyMapMocks.create( + sortedMapOf( + MemberInfoExtension.STATUS to MemberInfoExtension.MEMBER_STATUS_ACTIVE, + MemberInfoExtension.MODIFIED_TIME to modifiedTime.toString(), + DUMMY_KEY to "dummyValue", + MemberInfoExtension.SERIAL to "1", + ), converters +) + +fun convertEndpoints(): List> { + val result = mutableListOf>() + for (i in endpoints.indices) { + result.add(Pair(String.format(MemberInfoExtension.URL_KEY, i), endpoints[i].url)) + result.add( + Pair( + String.format(MemberInfoExtension.PROTOCOL_VERSION, i), + endpoints[i].protocolVersion.toString() + ) + ) + } + return result +} + +fun convertPublicKeys(): List> = ledgerKeys.mapIndexed { i, ledgerKey -> + String.format( + MemberInfoExtension.LEDGER_KEYS_KEY, i + ) to keyEncodingService.encodeAsString(ledgerKey) +}