mirror of
https://github.com/corda/corda.git
synced 2025-01-18 10:46:38 +00:00
Fixing stuff
This commit is contained in:
parent
f3f06976d0
commit
107fcf82e3
build.gradle
client/rpc/src/integration-test/java/net/corda/client/rpc
confidential-identities/src/test/kotlin/net/corda/confidential
core/src/main/kotlin/net/corda/core/node/services
docs/source
finance/src/test/kotlin/net/corda/finance/contracts
network-management/src
integration-test/kotlin/com/r3/corda/networkmanage
main/kotlin/com/r3/corda/networkmanage
test/kotlin/com/r3/corda/networkmanage
node-api/src
main/kotlin/net/corda/nodeapi/internal/network
test/kotlin/net/corda/nodeapi/internal/serialization
node
build.gradle
src
integration-test/kotlin/net/corda/node
services
utilities/registration
main
kotlin/net/corda/node
internal
services
resources
test
java/net/corda/node/services/vault
kotlin/net/corda/node/services
perftestcordapp/src/test/kotlin/com/r3/corda/enterprise/perftestcordapp/contracts
settings.gradletesting/node-driver/src/main/kotlin/net/corda/testing/node
tools/jmeter
verify-enclave/src
integration-test/kotlin/com/r3/enclaves/verify
test/kotlin/com/r3/enclaves/txverify
27
build.gradle
27
build.gradle
@ -162,33 +162,6 @@ allprojects {
|
|||||||
tasks.withType(Test) {
|
tasks.withType(Test) {
|
||||||
// Prevent the project from creating temporary files outside of the build directory.
|
// Prevent the project from creating temporary files outside of the build directory.
|
||||||
systemProperties['java.io.tmpdir'] = buildDir
|
systemProperties['java.io.tmpdir'] = buildDir
|
||||||
|
|
||||||
// Ensures that "net.corda.testing.amqp.enable" is passed correctly from Gradle command line
|
|
||||||
// down to JVM executing unit test. It looks like we are running unit tests in the forked mode
|
|
||||||
// and all the "-D" parameters passed to Gradle not making it to unit test level
|
|
||||||
// TODO: Remove once we fully switched to AMQP
|
|
||||||
final AMQP_ENABLE_PROP_NAME = "net.corda.testing.amqp.enable"
|
|
||||||
systemProperty(AMQP_ENABLE_PROP_NAME, System.getProperty(AMQP_ENABLE_PROP_NAME))
|
|
||||||
|
|
||||||
// relational database provider to be used by node
|
|
||||||
final DATABASE_PROVIDER = "databaseProvider"
|
|
||||||
final DATASOURCE_URL = "dataSourceProperties.dataSource.url"
|
|
||||||
final DATASOURCE_CLASSNAME = "dataSourceProperties.dataSourceClassName"
|
|
||||||
final DATASOURCE_USER = "dataSourceProperties.dataSource.user"
|
|
||||||
final DATASOURCE_PASSWORD = "dataSourceProperties.dataSource.password"
|
|
||||||
|
|
||||||
// integration testing database configuration (to be used in conjunction with a DATABASE_PROVIDER)
|
|
||||||
final TEST_DB_ADMIN_USER = "test.db.admin.user"
|
|
||||||
final TEST_DB_ADMIN_PASSWORD = "test.db.admin.password"
|
|
||||||
final TEST_DB_SCRIPT_DIR = "test.db.script.dir"
|
|
||||||
|
|
||||||
[DATABASE_PROVIDER,DATASOURCE_URL, DATASOURCE_CLASSNAME, DATASOURCE_USER, DATASOURCE_PASSWORD,
|
|
||||||
TEST_DB_ADMIN_USER, TEST_DB_ADMIN_PASSWORD, TEST_DB_SCRIPT_DIR].forEach {
|
|
||||||
def property = System.getProperty(it)
|
|
||||||
if (property != null) {
|
|
||||||
systemProperty(it, property)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'com.r3.corda.enterprise'
|
group 'com.r3.corda.enterprise'
|
||||||
|
@ -63,8 +63,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws ExecutionException, InterruptedException {
|
||||||
super.setUp();
|
|
||||||
node = startNode(ALICE_NAME, 1, singletonList(rpcUser));
|
node = startNode(ALICE_NAME, 1, singletonList(rpcUser));
|
||||||
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
|
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,11 @@ import net.corda.testing.node.MockNetwork
|
|||||||
import net.corda.testing.node.startFlow
|
import net.corda.testing.node.startFlow
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
import kotlin.test.assertNull
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
@Ignore
|
|
||||||
class IdentitySyncFlowTests {
|
class IdentitySyncFlowTests {
|
||||||
private lateinit var mockNet: MockNetwork
|
private lateinit var mockNet: MockNetwork
|
||||||
|
|
||||||
|
@ -6,11 +6,9 @@ import net.corda.testing.*
|
|||||||
import net.corda.testing.node.MockNetwork
|
import net.corda.testing.node.MockNetwork
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import net.corda.testing.node.startFlow
|
import net.corda.testing.node.startFlow
|
||||||
import org.junit.Ignore
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
@Ignore
|
|
||||||
class SwapIdentitiesFlowTests {
|
class SwapIdentitiesFlowTests {
|
||||||
private lateinit var mockNet: MockNetwork
|
private lateinit var mockNet: MockNetwork
|
||||||
|
|
||||||
|
@ -16,13 +16,21 @@ import java.security.PublicKey
|
|||||||
abstract class NotaryService : SingletonSerializeAsToken() {
|
abstract class NotaryService : SingletonSerializeAsToken() {
|
||||||
companion object {
|
companion object {
|
||||||
const val ID_PREFIX = "corda.notary."
|
const val ID_PREFIX = "corda.notary."
|
||||||
fun constructId(validating: Boolean, raft: Boolean = false, bft: Boolean = false, custom: Boolean = false): String {
|
@JvmOverloads
|
||||||
require(Booleans.countTrue(raft, bft, custom) <= 1) { "At most one of raft, bft or custom may be true" }
|
fun constructId(
|
||||||
|
validating: Boolean,
|
||||||
|
raft: Boolean = false,
|
||||||
|
bft: Boolean = false,
|
||||||
|
custom: Boolean = false,
|
||||||
|
mysql: Boolean = false
|
||||||
|
): String {
|
||||||
|
require(Booleans.countTrue(raft, bft, custom, mysql) <= 1) { "At most one of raft, bft, mysql or custom may be true" }
|
||||||
return StringBuffer(ID_PREFIX).apply {
|
return StringBuffer(ID_PREFIX).apply {
|
||||||
append(if (validating) "validating" else "simple")
|
append(if (validating) "validating" else "simple")
|
||||||
if (raft) append(".raft")
|
if (raft) append(".raft")
|
||||||
if (bft) append(".bft")
|
if (bft) append(".bft")
|
||||||
if (custom) append(".custom")
|
if (custom) append(".custom")
|
||||||
|
if (mysql) append(".mysql")
|
||||||
}.toString()
|
}.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ from the previous milestone release.
|
|||||||
|
|
||||||
UNRELEASED
|
UNRELEASED
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* The network map service concept has been re-designed. More information can be found in :doc:`network-map`.
|
* The network map service concept has been re-designed. More information can be found in :doc:`network-map`.
|
||||||
|
|
||||||
* The previous design was never intended to be final but was rather a quick implementation in the earliest days of the
|
* The previous design was never intended to be final but was rather a quick implementation in the earliest days of the
|
||||||
|
@ -15,7 +15,9 @@ import net.corda.core.utilities.days
|
|||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.finance.DOLLARS
|
import net.corda.finance.DOLLARS
|
||||||
import net.corda.finance.`issued by`
|
import net.corda.finance.`issued by`
|
||||||
import net.corda.finance.contracts.asset.*
|
import net.corda.finance.contracts.asset.CASH
|
||||||
|
import net.corda.finance.contracts.asset.Cash
|
||||||
|
import net.corda.finance.contracts.asset.STATE
|
||||||
import net.corda.node.services.api.IdentityServiceInternal
|
import net.corda.node.services.api.IdentityServiceInternal
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.dsl.EnforceVerifyOrFail
|
import net.corda.testing.dsl.EnforceVerifyOrFail
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
package net.corda.finance.contracts.asset
|
package net.corda.finance.contracts.asset
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.*
|
import com.nhaarman.mockito_kotlin.argThat
|
||||||
|
import com.nhaarman.mockito_kotlin.doNothing
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.*
|
import net.corda.core.identity.AbstractParty
|
||||||
|
import net.corda.core.identity.AnonymousParty
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.services.VaultService
|
import net.corda.core.node.services.VaultService
|
||||||
import net.corda.core.node.services.queryBy
|
import net.corda.core.node.services.queryBy
|
||||||
@ -20,10 +26,10 @@ import net.corda.node.services.vault.NodeVaultService
|
|||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.contracts.DummyState
|
import net.corda.testing.contracts.DummyState
|
||||||
import net.corda.testing.internal.LogHelper
|
|
||||||
import net.corda.testing.dsl.EnforceVerifyOrFail
|
import net.corda.testing.dsl.EnforceVerifyOrFail
|
||||||
import net.corda.testing.dsl.TransactionDSL
|
import net.corda.testing.dsl.TransactionDSL
|
||||||
import net.corda.testing.dsl.TransactionDSLInterpreter
|
import net.corda.testing.dsl.TransactionDSLInterpreter
|
||||||
|
import net.corda.testing.internal.LogHelper
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.internal.vault.VaultFiller
|
import net.corda.testing.internal.vault.VaultFiller
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
||||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||||
@ -8,22 +9,29 @@ import com.r3.corda.networkmanage.doorman.signer.LocalSigner
|
|||||||
import net.corda.core.crypto.Crypto
|
import net.corda.core.crypto.Crypto
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.SignedData
|
import net.corda.core.crypto.SignedData
|
||||||
|
import net.corda.core.crypto.sign
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.PartyAndCertificate
|
import net.corda.core.identity.PartyAndCertificate
|
||||||
import net.corda.core.internal.cert
|
import net.corda.core.internal.cert
|
||||||
|
import net.corda.core.internal.createDirectories
|
||||||
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.node.NodeInfo
|
import net.corda.core.node.NodeInfo
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.minutes
|
import net.corda.core.utilities.minutes
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.services.network.NetworkMapClient
|
import net.corda.node.services.network.NetworkMapClient
|
||||||
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
||||||
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
||||||
|
import net.corda.nodeapi.internal.SignedNodeInfo
|
||||||
import net.corda.nodeapi.internal.crypto.*
|
import net.corda.nodeapi.internal.crypto.*
|
||||||
import net.corda.testing.ALICE_NAME
|
import net.corda.testing.ALICE_NAME
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import net.corda.testing.internal.rigorousMock
|
||||||
import org.bouncycastle.cert.X509CertificateHolder
|
import org.bouncycastle.cert.X509CertificateHolder
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TemporaryFolder
|
import org.junit.rules.TemporaryFolder
|
||||||
@ -48,16 +56,11 @@ class DoormanIntegrationTest {
|
|||||||
|
|
||||||
//Start doorman server
|
//Start doorman server
|
||||||
val doorman = startDoorman(intermediateCertAndKey, rootCertAndKey.certificate)
|
val doorman = startDoorman(intermediateCertAndKey, rootCertAndKey.certificate)
|
||||||
|
val doormanHostAndPort = doorman.hostAndPort
|
||||||
// Start Corda network registration.
|
// Start Corda network registration.
|
||||||
val config = testNodeConfiguration(
|
val config = createConfig().also {
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||||
myLegalName = ALICE_NAME).also {
|
|
||||||
val doormanHostAndPort = doorman.hostAndPort
|
|
||||||
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
|
|
||||||
whenever(it.emailAddress).thenReturn("iTest@R3.com")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.trustStoreFile.parent.createDirectories()
|
config.trustStoreFile.parent.createDirectories()
|
||||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
||||||
@ -94,6 +97,7 @@ class DoormanIntegrationTest {
|
|||||||
doorman.close()
|
doorman.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
fun `nodeInfo is published to the network map`() {
|
fun `nodeInfo is published to the network map`() {
|
||||||
// Given
|
// Given
|
||||||
@ -105,13 +109,9 @@ class DoormanIntegrationTest {
|
|||||||
val doormanHostAndPort = doorman.hostAndPort
|
val doormanHostAndPort = doorman.hostAndPort
|
||||||
|
|
||||||
// Start Corda network registration.
|
// Start Corda network registration.
|
||||||
val config = testNodeConfiguration(
|
val config = createConfig().also {
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||||
myLegalName = ALICE_NAME).also {
|
|
||||||
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
|
|
||||||
whenever(it.emailAddress).thenReturn("iTest@R3.com")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.trustStoreFile.parent.createDirectories()
|
config.trustStoreFile.parent.createDirectories()
|
||||||
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||||
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCertAndKey.certificate.cert)
|
||||||
@ -128,7 +128,8 @@ class DoormanIntegrationTest {
|
|||||||
val nodeInfoBytes = nodeInfo.serialize()
|
val nodeInfoBytes = nodeInfo.serialize()
|
||||||
|
|
||||||
// When
|
// When
|
||||||
networkMapClient.publish(SignedData(nodeInfoBytes, keyPair.sign(nodeInfoBytes)))
|
val signedNodeInfo = SignedNodeInfo(nodeInfoBytes, listOf(keyPair.sign(nodeInfoBytes)))
|
||||||
|
networkMapClient.publish(signedNodeInfo)
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
val networkMapNodeInfo = networkMapClient.getNodeInfo(nodeInfoBytes.hash)
|
val networkMapNodeInfo = networkMapClient.getNodeInfo(nodeInfoBytes.hash)
|
||||||
@ -137,8 +138,24 @@ class DoormanIntegrationTest {
|
|||||||
|
|
||||||
doorman.close()
|
doorman.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createConfig(): NodeConfiguration {
|
||||||
|
return rigorousMock<NodeConfiguration>().also {
|
||||||
|
doReturn(tempFolder.root.toPath()).whenever(it).baseDirectory
|
||||||
|
doReturn(ALICE_NAME).whenever(it).myLegalName
|
||||||
|
doReturn(it.baseDirectory / "certificates").whenever(it).certificatesDirectory
|
||||||
|
doReturn(it.certificatesDirectory / "truststore.jks").whenever(it).trustStoreFile
|
||||||
|
doReturn(it.certificatesDirectory / "nodekeystore.jks").whenever(it).nodeKeystore
|
||||||
|
doReturn(it.certificatesDirectory / "sslkeystore.jks").whenever(it).sslKeystore
|
||||||
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
// doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||||
|
doReturn("iTest@R3.com").whenever(it).emailAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun createDoormanIntermediateCertificateAndKeyPair(rootCertificateAndKeyPair: CertificateAndKeyPair): CertificateAndKeyPair {
|
fun createDoormanIntermediateCertificateAndKeyPair(rootCertificateAndKeyPair: CertificateAndKeyPair): CertificateAndKeyPair {
|
||||||
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
val intermediateCAKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
|
||||||
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCertificateAndKeyPair.certificate, rootCertificateAndKeyPair.keyPair,
|
val intermediateCACert = X509Utilities.createCertificate(CertificateType.INTERMEDIATE_CA, rootCertificateAndKeyPair.certificate, rootCertificateAndKeyPair.keyPair,
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package com.r3.corda.networkmanage.hsm
|
package com.r3.corda.networkmanage.hsm
|
||||||
|
|
||||||
import com.nhaarman.mockito_kotlin.any
|
import com.nhaarman.mockito_kotlin.*
|
||||||
import com.nhaarman.mockito_kotlin.mock
|
|
||||||
import com.nhaarman.mockito_kotlin.verify
|
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
|
||||||
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
import com.r3.corda.networkmanage.common.persistence.configureDatabase
|
||||||
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
import com.r3.corda.networkmanage.common.utils.buildCertPath
|
||||||
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
import com.r3.corda.networkmanage.common.utils.toX509Certificate
|
||||||
@ -17,9 +14,11 @@ import net.corda.core.crypto.Crypto
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.cert
|
import net.corda.core.internal.cert
|
||||||
import net.corda.core.internal.createDirectories
|
import net.corda.core.internal.createDirectories
|
||||||
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.internal.uncheckedCast
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
|
import net.corda.node.services.config.NodeConfiguration
|
||||||
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
|
||||||
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
import net.corda.node.utilities.registration.NetworkRegistrationHelper
|
||||||
import net.corda.nodeapi.internal.crypto.*
|
import net.corda.nodeapi.internal.crypto.*
|
||||||
@ -28,7 +27,7 @@ import net.corda.testing.ALICE_NAME
|
|||||||
import net.corda.testing.BOB_NAME
|
import net.corda.testing.BOB_NAME
|
||||||
import net.corda.testing.CHARLIE_NAME
|
import net.corda.testing.CHARLIE_NAME
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.node.testNodeConfiguration
|
import net.corda.testing.internal.rigorousMock
|
||||||
import org.bouncycastle.cert.X509CertificateHolder
|
import org.bouncycastle.cert.X509CertificateHolder
|
||||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||||
import org.h2.tools.Server
|
import org.h2.tools.Server
|
||||||
@ -101,14 +100,12 @@ class SigningServiceIntegrationTest {
|
|||||||
|
|
||||||
NetworkManagementServer().use { server ->
|
NetworkManagementServer().use { server ->
|
||||||
server.start(NetworkHostAndPort(HOST, 0), database, networkMapServiceParameter = null, doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null), updateNetworkParameters = null)
|
server.start(NetworkHostAndPort(HOST, 0), database, networkMapServiceParameter = null, doormanServiceParameter = DoormanConfig(approveAll = true, approveInterval = 2.seconds.toMillis(), jiraConfig = null), updateNetworkParameters = null)
|
||||||
|
val doormanHostAndPort = server.hostAndPort
|
||||||
// Start Corda network registration.
|
// Start Corda network registration.
|
||||||
val config = testNodeConfiguration(
|
val config = createConfig().also {
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
doReturn(ALICE_NAME).whenever(it).myLegalName
|
||||||
myLegalName = ALICE_NAME).also {
|
doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||||
val doormanHostAndPort = server.hostAndPort
|
|
||||||
whenever(it.compatibilityZoneURL).thenReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val signingServiceStorage = DBSignedCertificateRequestStorage(configureDatabase(makeTestDataSourceProperties()))
|
val signingServiceStorage = DBSignedCertificateRequestStorage(configureDatabase(makeTestDataSourceProperties()))
|
||||||
|
|
||||||
val hsmSigner = givenSignerSigningAllRequests(signingServiceStorage)
|
val hsmSigner = givenSignerSigningAllRequests(signingServiceStorage)
|
||||||
@ -149,6 +146,7 @@ class SigningServiceIntegrationTest {
|
|||||||
* The split is done due to the limited console support while executing tests and inability to capture user's input there.
|
* The split is done due to the limited console support while executing tests and inability to capture user's input there.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
fun `DEMO - Create CSR and poll`() {
|
fun `DEMO - Create CSR and poll`() {
|
||||||
//Start doorman server
|
//Start doorman server
|
||||||
@ -162,23 +160,41 @@ class SigningServiceIntegrationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start Corda network registration.
|
// Start Corda network registration.
|
||||||
(1..3).map {
|
(1..3).map { num ->
|
||||||
thread(start = true) {
|
thread(start = true) {
|
||||||
val config = testNodeConfiguration(
|
// Start Corda network registration.
|
||||||
baseDirectory = tempFolder.root.toPath(),
|
val config = createConfig().also {
|
||||||
myLegalName = when (it) {
|
doReturn(when (num) {
|
||||||
1 -> ALICE_NAME
|
1 -> ALICE_NAME
|
||||||
2 -> BOB_NAME
|
2 -> BOB_NAME
|
||||||
3 -> CHARLIE_NAME
|
3 -> CHARLIE_NAME
|
||||||
else -> throw IllegalArgumentException("Unrecognised option")
|
else -> throw IllegalArgumentException("Unrecognised option")
|
||||||
}).also {
|
}).whenever(it).myLegalName
|
||||||
whenever(it.compatibilityZoneURL).thenReturn(URL("http://$HOST:${server.hostAndPort.port}"))
|
doReturn(URL("http://$HOST:${server.hostAndPort.port}")).whenever(it).compatibilityZoneURL
|
||||||
|
}
|
||||||
|
config.trustStoreFile.parent.createDirectories()
|
||||||
|
loadOrCreateKeyStore(config.trustStoreFile, config.trustStorePassword).also {
|
||||||
|
it.addOrReplaceCertificate(X509Utilities.CORDA_ROOT_CA, rootCACert.cert)
|
||||||
|
it.save(config.trustStoreFile, config.trustStorePassword)
|
||||||
}
|
}
|
||||||
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
NetworkRegistrationHelper(config, HTTPNetworkRegistrationService(config.compatibilityZoneURL!!)).buildKeystore()
|
||||||
}
|
}
|
||||||
}.map { it.join() }
|
}.map { it.join() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createConfig(): NodeConfiguration {
|
||||||
|
return rigorousMock<NodeConfiguration>().also {
|
||||||
|
doReturn(tempFolder.root.toPath()).whenever(it).baseDirectory
|
||||||
|
doReturn(it.baseDirectory / "certificates").whenever(it).certificatesDirectory
|
||||||
|
doReturn(it.certificatesDirectory / "truststore.jks").whenever(it).trustStoreFile
|
||||||
|
doReturn(it.certificatesDirectory / "nodekeystore.jks").whenever(it).nodeKeystore
|
||||||
|
doReturn(it.certificatesDirectory / "sslkeystore.jks").whenever(it).sslKeystore
|
||||||
|
doReturn("trustpass").whenever(it).trustStorePassword
|
||||||
|
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||||
|
doReturn("iTest@R3.com").whenever(it).emailAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeTestDataSourceProperties(): Properties {
|
private fun makeTestDataSourceProperties(): Properties {
|
||||||
|
@ -15,7 +15,7 @@ class NetworkMapSigner(private val networkMapStorage: NetworkMapStorage, private
|
|||||||
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
|
val nodeInfoHashes = networkMapStorage.getNodeInfoHashes(CertificateStatus.VALID)
|
||||||
val networkParameters = networkMapStorage.getLatestNetworkParameters()
|
val networkParameters = networkMapStorage.getLatestNetworkParameters()
|
||||||
val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash)
|
val networkMap = NetworkMap(nodeInfoHashes, networkParameters.serialize().hash)
|
||||||
if (networkMap != currentSignedNetworkMap?.verified()) {
|
if (networkMap != currentSignedNetworkMap?.verified(null)) {
|
||||||
val digitalSignature = signer.sign(networkMap.serialize().bytes)
|
val digitalSignature = signer.sign(networkMap.serialize().bytes)
|
||||||
val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature)
|
val signedHashedNetworkMap = SignedNetworkMap(networkMap.serialize(), digitalSignature)
|
||||||
networkMapStorage.saveNetworkMap(signedHashedNetworkMap)
|
networkMapStorage.saveNetworkMap(signedHashedNetworkMap)
|
||||||
|
@ -5,6 +5,7 @@ import com.typesafe.config.ConfigParseOptions
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.exists
|
import net.corda.core.internal.exists
|
||||||
|
import net.corda.core.utilities.days
|
||||||
import net.corda.core.utilities.parsePublicKeyBase58
|
import net.corda.core.utilities.parsePublicKeyBase58
|
||||||
import net.corda.nodeapi.internal.config.parseAs
|
import net.corda.nodeapi.internal.config.parseAs
|
||||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
|
@ -17,7 +17,6 @@ class NetworkParametersConfigurationTest {
|
|||||||
fun `reads an existing file`() {
|
fun `reads an existing file`() {
|
||||||
val networkParameters = parseNetworkParametersFrom(validOverrideNetworkConfigPath)
|
val networkParameters = parseNetworkParametersFrom(validOverrideNetworkConfigPath)
|
||||||
assertThat(networkParameters.minimumPlatformVersion).isEqualTo(1)
|
assertThat(networkParameters.minimumPlatformVersion).isEqualTo(1)
|
||||||
assertThat(networkParameters.eventHorizon).isEqualTo(100.days)
|
|
||||||
val notaries = networkParameters.notaries
|
val notaries = networkParameters.notaries
|
||||||
assertThat(notaries).hasSize(2)
|
assertThat(notaries).hasSize(2)
|
||||||
assertThat(notaries[0].validating).isTrue()
|
assertThat(notaries[0].validating).isTrue()
|
||||||
|
@ -7,8 +7,8 @@ import com.r3.corda.networkmanage.common.persistence.CertificateStatus
|
|||||||
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
import com.r3.corda.networkmanage.common.persistence.RequestStatus
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.internal.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import net.corda.nodeapi.internal.NotaryInfo
|
import net.corda.nodeapi.internal.network.NotaryInfo
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -62,7 +62,6 @@ abstract class TestBase {
|
|||||||
return NetworkParameters(
|
return NetworkParameters(
|
||||||
minimumPlatformVersion = minimumPlatformVersion,
|
minimumPlatformVersion = minimumPlatformVersion,
|
||||||
notaries = notaries,
|
notaries = notaries,
|
||||||
eventHorizon = eventHorizon,
|
|
||||||
maxMessageSize = maxMessageSize,
|
maxMessageSize = maxMessageSize,
|
||||||
maxTransactionSize = maxTransactionSize,
|
maxTransactionSize = maxTransactionSize,
|
||||||
modifiedTime = modifiedTime,
|
modifiedTime = modifiedTime,
|
||||||
|
@ -81,7 +81,7 @@ class DBNetworkMapStorageTest : TestBase() {
|
|||||||
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
val persistedSignedNetworkMap = networkMapStorage.getCurrentNetworkMap()
|
||||||
|
|
||||||
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
assertEquals(signedNetworkMap.signature, persistedSignedNetworkMap?.signature)
|
||||||
assertEquals(signedNetworkMap.verified(), persistedSignedNetworkMap?.verified())
|
assertEquals(signedNetworkMap.verified(rootCACert.cert), persistedSignedNetworkMap?.verified(rootCACert.cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -11,10 +11,10 @@ import net.corda.core.crypto.sign
|
|||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.internal.cert
|
import net.corda.core.internal.cert
|
||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.nodeapi.internal.NetworkMap
|
|
||||||
import net.corda.nodeapi.internal.SignedNetworkMap
|
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -58,7 +58,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
argumentCaptor<SignedNetworkMap>().apply {
|
argumentCaptor<SignedNetworkMap>().apply {
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
verify(networkMapStorage).saveNetworkMap(capture())
|
||||||
val networkMap = firstValue.verified()
|
val networkMap = firstValue.verified(rootCACert.cert)
|
||||||
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
||||||
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
assertEquals(signedNodeInfoHashes.size, networkMap.nodeInfoHashes.size)
|
||||||
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
assertTrue(networkMap.nodeInfoHashes.containsAll(signedNodeInfoHashes))
|
||||||
@ -104,7 +104,7 @@ class NetworkMapSignerTest : TestBase() {
|
|||||||
verify(networkMapStorage).getLatestNetworkParameters()
|
verify(networkMapStorage).getLatestNetworkParameters()
|
||||||
argumentCaptor<SignedNetworkMap>().apply {
|
argumentCaptor<SignedNetworkMap>().apply {
|
||||||
verify(networkMapStorage).saveNetworkMap(capture())
|
verify(networkMapStorage).saveNetworkMap(capture())
|
||||||
val networkMap = firstValue.verified()
|
val networkMap = firstValue.verified(rootCACert.cert)
|
||||||
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
assertEquals(networkMapParameters.serialize().hash, networkMap.networkParameterHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@ import net.corda.core.serialization.deserialize
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.core.utilities.NetworkHostAndPort
|
import net.corda.core.utilities.NetworkHostAndPort
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.internal.NetworkMap
|
|
||||||
import net.corda.nodeapi.internal.SignedNetworkMap
|
|
||||||
import net.corda.nodeapi.internal.crypto.CertificateType
|
import net.corda.nodeapi.internal.crypto.CertificateType
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities
|
import net.corda.nodeapi.internal.crypto.X509Utilities
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkMap
|
||||||
|
import net.corda.nodeapi.internal.network.SignedNetworkMap
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import org.bouncycastle.asn1.x500.X500Name
|
import org.bouncycastle.asn1.x500.X500Name
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@ -82,7 +82,7 @@ class NodeInfoWebServiceTest {
|
|||||||
val conn = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}").openConnection() as HttpURLConnection
|
val conn = URL("http://${it.hostAndPort}/${NodeInfoWebService.NETWORK_MAP_PATH}").openConnection() as HttpURLConnection
|
||||||
val signedNetworkMap = conn.inputStream.readBytes().deserialize<SignedNetworkMap>()
|
val signedNetworkMap = conn.inputStream.readBytes().deserialize<SignedNetworkMap>()
|
||||||
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
verify(networkMapStorage, times(1)).getCurrentNetworkMap()
|
||||||
assertEquals(signedNetworkMap.verified(), networkMap)
|
assertEquals(signedNetworkMap.verified(rootCACert.cert), networkMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +68,12 @@ class SignedNetworkMap(val raw: SerializedBytes<NetworkMap>, val signature: Digi
|
|||||||
* @throws SignatureException if the signature is invalid.
|
* @throws SignatureException if the signature is invalid.
|
||||||
*/
|
*/
|
||||||
@Throws(SignatureException::class, CertPathValidatorException::class)
|
@Throws(SignatureException::class, CertPathValidatorException::class)
|
||||||
fun verified(trustedRoot: X509Certificate): NetworkMap {
|
fun verified(trustedRoot: X509Certificate?): NetworkMap {
|
||||||
signature.by.publicKey.verify(raw.bytes, signature)
|
signature.by.publicKey.verify(raw.bytes, signature)
|
||||||
// Assume network map cert is under the default trust root.
|
// Assume network map cert is under the default trust root.
|
||||||
X509Utilities.validateCertificateChain(trustedRoot, signature.by, trustedRoot)
|
if (trustedRoot != null) {
|
||||||
|
X509Utilities.validateCertificateChain(trustedRoot, signature.by, trustedRoot)
|
||||||
|
}
|
||||||
return raw.deserialize()
|
return raw.deserialize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ import net.corda.core.serialization.deserialize
|
|||||||
import net.corda.core.serialization.serialize
|
import net.corda.core.serialization.serialize
|
||||||
import net.corda.node.services.statemachine.DataSessionMessage
|
import net.corda.node.services.statemachine.DataSessionMessage
|
||||||
import net.corda.nodeapi.internal.serialization.kryo.KryoHeaderV0_1
|
import net.corda.nodeapi.internal.serialization.kryo.KryoHeaderV0_1
|
||||||
import net.corda.testing.internal.kryoSpecific
|
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.internal.kryoSpecific
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.Assert.assertArrayEquals
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
@ -127,6 +127,8 @@ dependencies {
|
|||||||
compile "org.postgresql:postgresql:$postgresql_version"
|
compile "org.postgresql:postgresql:$postgresql_version"
|
||||||
//For Azure SQL and SQL Server support in persistence
|
//For Azure SQL and SQL Server support in persistence
|
||||||
compile 'com.microsoft.sqlserver:mssql-jdbc:6.2.1.jre8'
|
compile 'com.microsoft.sqlserver:mssql-jdbc:6.2.1.jre8'
|
||||||
|
// For the MySQLUniquenessProvider
|
||||||
|
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
|
||||||
|
|
||||||
// SQL connection pooling library
|
// SQL connection pooling library
|
||||||
compile "com.zaxxer:HikariCP:2.5.1"
|
compile "com.zaxxer:HikariCP:2.5.1"
|
||||||
|
@ -24,9 +24,9 @@ import net.corda.testing.*
|
|||||||
import net.corda.testing.driver.DriverDSL
|
import net.corda.testing.driver.DriverDSL
|
||||||
import net.corda.testing.driver.NodeHandle
|
import net.corda.testing.driver.NodeHandle
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.internal.withoutTestSerialization
|
import net.corda.testing.internal.withoutTestSerialization
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import net.corda.testing.internal.rigorousMock
|
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.ClassRule
|
import org.junit.ClassRule
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
@ -25,11 +25,9 @@ import net.corda.node.services.config.NotaryConfig
|
|||||||
import net.corda.node.services.transactions.minClusterSize
|
import net.corda.node.services.transactions.minClusterSize
|
||||||
import net.corda.node.services.transactions.minCorrectReplicas
|
import net.corda.node.services.transactions.minCorrectReplicas
|
||||||
import net.corda.nodeapi.internal.ServiceIdentityGenerator
|
import net.corda.nodeapi.internal.ServiceIdentityGenerator
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkParametersCopier
|
||||||
import net.corda.nodeapi.internal.network.NotaryInfo
|
import net.corda.nodeapi.internal.network.NotaryInfo
|
||||||
import net.corda.testing.chooseIdentity
|
import net.corda.testing.chooseIdentity
|
||||||
import net.corda.nodeapi.internal.network.NetworkParametersCopier
|
|
||||||
import net.corda.testing.IntegrationTest
|
|
||||||
import net.corda.testing.IntegrationTestSchemas
|
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
import net.corda.testing.contracts.DummyContract
|
import net.corda.testing.contracts.DummyContract
|
||||||
import net.corda.testing.dummyCommand
|
import net.corda.testing.dummyCommand
|
||||||
@ -39,19 +37,12 @@ import net.corda.testing.node.MockNodeParameters
|
|||||||
import net.corda.testing.node.startFlow
|
import net.corda.testing.node.startFlow
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.ClassRule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class BFTNotaryServiceTests : IntegrationTest() {
|
class BFTNotaryServiceTests {
|
||||||
companion object {
|
|
||||||
@ClassRule @JvmField
|
|
||||||
val databaseSchemas = IntegrationTestSchemas("node_0", "node_1", "node_2", "node_3", "node_4", "node_5",
|
|
||||||
"node_6", "node_7", "node_8", "node_9")
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var mockNet: MockNetwork
|
private lateinit var mockNet: MockNetwork
|
||||||
private lateinit var notary: Party
|
private lateinit var notary: Party
|
||||||
private lateinit var node: StartedNode<MockNode>
|
private lateinit var node: StartedNode<MockNode>
|
||||||
|
@ -0,0 +1,154 @@
|
|||||||
|
package net.corda.node.services
|
||||||
|
|
||||||
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
|
import net.corda.core.contracts.StateAndRef
|
||||||
|
import net.corda.core.contracts.StateRef
|
||||||
|
import net.corda.core.crypto.TransactionSignature
|
||||||
|
import net.corda.core.flows.NotaryError
|
||||||
|
import net.corda.core.flows.NotaryException
|
||||||
|
import net.corda.core.flows.NotaryFlow
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
|
import net.corda.core.utilities.getOrThrow
|
||||||
|
import net.corda.node.internal.StartedNode
|
||||||
|
import net.corda.node.services.config.NotaryConfig
|
||||||
|
import net.corda.nodeapi.internal.ServiceIdentityGenerator
|
||||||
|
import net.corda.nodeapi.internal.network.NetworkParametersCopier
|
||||||
|
import net.corda.nodeapi.internal.network.NotaryInfo
|
||||||
|
import net.corda.testing.*
|
||||||
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
|
import net.corda.testing.contracts.DummyContract
|
||||||
|
import net.corda.testing.node.MockNetwork
|
||||||
|
import net.corda.testing.node.MockNodeParameters
|
||||||
|
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||||
|
import net.corda.testing.node.startFlow
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.ClassRule
|
||||||
|
import org.junit.Test
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
|
class MySQLNotaryServiceTests : IntegrationTest() {
|
||||||
|
companion object {
|
||||||
|
val notaryName = CordaX500Name("MySQL Notary Service", "Zurich", "CH")
|
||||||
|
@ClassRule
|
||||||
|
@JvmField
|
||||||
|
val databaseSchemas = IntegrationTestSchemas("node_0", DUMMY_NOTARY_NAME.toDatabaseSchemaName())
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var mockNet: MockNetwork
|
||||||
|
private lateinit var node: StartedNode<MockNetwork.MockNode>
|
||||||
|
private lateinit var notaryParty: Party
|
||||||
|
private lateinit var notaryNode: StartedNode<MockNetwork.MockNode>
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun before() {
|
||||||
|
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
|
||||||
|
notaryParty = ServiceIdentityGenerator.generateToDisk(
|
||||||
|
listOf(mockNet.baseDirectory(mockNet.nextNodeId)),
|
||||||
|
notaryName,
|
||||||
|
"identity"
|
||||||
|
)
|
||||||
|
val networkParameters = NetworkParametersCopier(testNetworkParameters(listOf(NotaryInfo(notaryParty, false))))
|
||||||
|
val notaryNodeUnstarted = createNotaryNode()
|
||||||
|
val nodeUnstarted = mockNet.createUnstartedNode()
|
||||||
|
|
||||||
|
val startedNodes = listOf(notaryNodeUnstarted, nodeUnstarted).map { n ->
|
||||||
|
networkParameters.install(mockNet.baseDirectory(n.id))
|
||||||
|
n.start()
|
||||||
|
}
|
||||||
|
notaryNode = startedNodes.first()
|
||||||
|
node = startedNodes.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun stopNodes() {
|
||||||
|
mockNet.stopNodes()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `detect double spend`() {
|
||||||
|
val inputState = issueState(node, notaryParty)
|
||||||
|
|
||||||
|
val firstTxBuilder = TransactionBuilder(notaryParty)
|
||||||
|
.addInputState(inputState)
|
||||||
|
.addCommand(dummyCommand(node.services.myInfo.chooseIdentity().owningKey))
|
||||||
|
val firstSpendTx = node.services.signInitialTransaction(firstTxBuilder)
|
||||||
|
|
||||||
|
val firstSpend = node.services.startFlow(NotaryFlow.Client(firstSpendTx))
|
||||||
|
mockNet.runNetwork()
|
||||||
|
|
||||||
|
firstSpend.resultFuture.getOrThrow()
|
||||||
|
|
||||||
|
val secondSpendBuilder = TransactionBuilder(notaryParty).withItems(inputState).run {
|
||||||
|
val dummyState = DummyContract.SingleOwnerState(0, node.info.chooseIdentity())
|
||||||
|
addOutputState(dummyState, DummyContract.PROGRAM_ID)
|
||||||
|
addCommand(dummyCommand(node.services.myInfo.chooseIdentity().owningKey))
|
||||||
|
this
|
||||||
|
}
|
||||||
|
val secondSpendTx = node.services.signInitialTransaction(secondSpendBuilder)
|
||||||
|
val secondSpend = node.services.startFlow(NotaryFlow.Client(secondSpendTx))
|
||||||
|
|
||||||
|
mockNet.runNetwork()
|
||||||
|
|
||||||
|
val ex = assertFailsWith(NotaryException::class) { secondSpend.resultFuture.getOrThrow() }
|
||||||
|
val error = ex.error as NotaryError.Conflict
|
||||||
|
assertEquals(error.txId, secondSpendTx.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `notarisations are idempotent`() {
|
||||||
|
val inputState = issueState(node, notaryParty)
|
||||||
|
|
||||||
|
val txBuilder = TransactionBuilder(notaryParty)
|
||||||
|
.addInputState(inputState)
|
||||||
|
.addCommand(dummyCommand(node.services.myInfo.chooseIdentity().owningKey))
|
||||||
|
val spendTx = node.services.signInitialTransaction(txBuilder)
|
||||||
|
|
||||||
|
val notarise = node.services.startFlow(NotaryFlow.Client(spendTx))
|
||||||
|
mockNet.runNetwork()
|
||||||
|
val signature = notarise.resultFuture.get().single()
|
||||||
|
|
||||||
|
val notariseRetry = node.services.startFlow(NotaryFlow.Client(spendTx))
|
||||||
|
mockNet.runNetwork()
|
||||||
|
val signatureRetry = notariseRetry.resultFuture.get().single()
|
||||||
|
|
||||||
|
fun checkSignature(signature: TransactionSignature) {
|
||||||
|
signature.verify(spendTx.id)
|
||||||
|
assertEquals(notaryParty.owningKey, signature.by)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkSignature(signature)
|
||||||
|
checkSignature(signatureRetry)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createNotaryNode(): MockNetwork.MockNode {
|
||||||
|
val dataStoreProperties = makeTestDataSourceProperties().apply {
|
||||||
|
setProperty("autoCommit", "false")
|
||||||
|
}
|
||||||
|
return mockNet.createUnstartedNode(
|
||||||
|
MockNodeParameters(
|
||||||
|
legalName = notaryName,
|
||||||
|
entropyRoot = BigInteger.valueOf(60L),
|
||||||
|
configOverrides = {
|
||||||
|
val notaryConfig = NotaryConfig(validating = false, mysql = dataStoreProperties)
|
||||||
|
doReturn(notaryConfig).whenever(it).notary
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun issueState(node: StartedNode<*>, notary: Party): StateAndRef<*> {
|
||||||
|
return node.database.transaction {
|
||||||
|
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.chooseIdentity().ref(0))
|
||||||
|
val stx = node.services.signInitialTransaction(builder)
|
||||||
|
node.services.recordTransactions(stx)
|
||||||
|
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,24 +11,21 @@ import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
|||||||
import net.corda.nodeapi.internal.network.NetworkParameters
|
import net.corda.nodeapi.internal.network.NetworkParameters
|
||||||
import net.corda.testing.ALICE_NAME
|
import net.corda.testing.ALICE_NAME
|
||||||
import net.corda.testing.BOB_NAME
|
import net.corda.testing.BOB_NAME
|
||||||
import net.corda.testing.*
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.node.internal.CompatibilityZoneParams
|
|
||||||
import net.corda.testing.driver.NodeHandle
|
import net.corda.testing.driver.NodeHandle
|
||||||
import net.corda.testing.driver.PortAllocation
|
import net.corda.testing.driver.PortAllocation
|
||||||
|
import net.corda.testing.node.internal.CompatibilityZoneParams
|
||||||
import net.corda.testing.node.internal.internalDriver
|
import net.corda.testing.node.internal.internalDriver
|
||||||
import net.corda.testing.node.internal.network.NetworkMapServer
|
import net.corda.testing.node.internal.network.NetworkMapServer
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.*
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class NetworkMapTest : IntegrationTest() {
|
class NetworkMapTest {
|
||||||
companion object {
|
|
||||||
@ClassRule
|
|
||||||
@JvmField
|
|
||||||
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), BOB_NAME.toDatabaseSchemaName(),
|
|
||||||
DUMMY_NOTARY_NAME.toDatabaseSchemaName())
|
|
||||||
}
|
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule(true)
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
@ -15,10 +15,9 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_CLIENT_CA
|
|||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_INTERMEDIATE_CA
|
||||||
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
import net.corda.nodeapi.internal.crypto.X509Utilities.CORDA_ROOT_CA
|
||||||
import net.corda.testing.IntegrationTest
|
import net.corda.testing.IntegrationTest
|
||||||
import net.corda.testing.IntegrationTestSchemas
|
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.node.internal.CompatibilityZoneParams
|
|
||||||
import net.corda.testing.driver.PortAllocation
|
import net.corda.testing.driver.PortAllocation
|
||||||
|
import net.corda.testing.node.internal.CompatibilityZoneParams
|
||||||
import net.corda.testing.node.internal.internalDriver
|
import net.corda.testing.node.internal.internalDriver
|
||||||
import net.corda.testing.node.internal.network.NetworkMapServer
|
import net.corda.testing.node.internal.network.NetworkMapServer
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
@ -27,7 +26,6 @@ import org.bouncycastle.pkcs.PKCS10CertificationRequest
|
|||||||
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.ClassRule
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@ -42,11 +40,7 @@ import javax.ws.rs.*
|
|||||||
import javax.ws.rs.core.MediaType
|
import javax.ws.rs.core.MediaType
|
||||||
import javax.ws.rs.core.Response
|
import javax.ws.rs.core.Response
|
||||||
|
|
||||||
class NodeRegistrationTest : IntegrationTest() {
|
class NodeRegistrationTest {
|
||||||
companion object {
|
|
||||||
@ClassRule @JvmField
|
|
||||||
val databaseSchemas = IntegrationTestSchemas("Alice")
|
|
||||||
}
|
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule(true)
|
val testSerialization = SerializationEnvironmentRule(true)
|
||||||
|
@ -697,14 +697,19 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
|||||||
private fun makeCoreNotaryService(notaryConfig: NotaryConfig, database: CordaPersistence): NotaryService {
|
private fun makeCoreNotaryService(notaryConfig: NotaryConfig, database: CordaPersistence): NotaryService {
|
||||||
val notaryKey = myNotaryIdentity?.owningKey ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service")
|
val notaryKey = myNotaryIdentity?.owningKey ?: throw IllegalArgumentException("No notary identity initialized when creating a notary service")
|
||||||
return notaryConfig.run {
|
return notaryConfig.run {
|
||||||
if (raft != null) {
|
when {
|
||||||
val uniquenessProvider = RaftUniquenessProvider(configuration, database, services.monitoringService.metrics, raft)
|
raft != null -> {
|
||||||
(if (validating) ::RaftValidatingNotaryService else ::RaftNonValidatingNotaryService)(services, notaryKey, uniquenessProvider)
|
val uniquenessProvider = RaftUniquenessProvider(configuration, database, services.monitoringService.metrics, raft)
|
||||||
} else if (bftSMaRt != null) {
|
(if (validating) ::RaftValidatingNotaryService else ::RaftNonValidatingNotaryService)(services, notaryKey, uniquenessProvider)
|
||||||
if (validating) throw IllegalArgumentException("Validating BFTSMaRt notary not supported")
|
}
|
||||||
BFTNonValidatingNotaryService(services, notaryKey, bftSMaRt, makeBFTCluster(notaryKey, bftSMaRt))
|
bftSMaRt != null -> {
|
||||||
} else {
|
if (validating) throw IllegalArgumentException("Validating BFTSMaRt notary not supported")
|
||||||
(if (validating) ::ValidatingNotaryService else ::SimpleNotaryService)(services, notaryKey)
|
BFTNonValidatingNotaryService(services, notaryKey, bftSMaRt, makeBFTCluster(notaryKey, bftSMaRt))
|
||||||
|
}
|
||||||
|
mysql != null -> {
|
||||||
|
(if (validating) ::MySQLValidatingNotaryService else ::MySQLNonValidatingNotaryService)(services, notaryKey, mysql, configuration.devMode)
|
||||||
|
}
|
||||||
|
else -> (if (validating) ::ValidatingNotaryService else ::SimpleNotaryService)(services, notaryKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -754,7 +759,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
|
|||||||
Pair("identity", myLegalName)
|
Pair("identity", myLegalName)
|
||||||
} else {
|
} else {
|
||||||
val notaryId = notaryConfig.run {
|
val notaryId = notaryConfig.run {
|
||||||
NotaryService.constructId(validating, raft != null, bftSMaRt != null, custom)
|
NotaryService.constructId(validating, raft != null, bftSMaRt != null, custom, mysql != null)
|
||||||
}
|
}
|
||||||
// The node is part of a distributed notary whose identity must already be generated beforehand.
|
// The node is part of a distributed notary whose identity must already be generated beforehand.
|
||||||
Pair(notaryId, null)
|
Pair(notaryId, null)
|
||||||
|
@ -56,11 +56,12 @@ fun NodeConfiguration.shouldCheckCheckpoints(): Boolean {
|
|||||||
data class NotaryConfig(val validating: Boolean,
|
data class NotaryConfig(val validating: Boolean,
|
||||||
val raft: RaftConfig? = null,
|
val raft: RaftConfig? = null,
|
||||||
val bftSMaRt: BFTSMaRtConfiguration? = null,
|
val bftSMaRt: BFTSMaRtConfiguration? = null,
|
||||||
val custom: Boolean = false
|
val custom: Boolean = false,
|
||||||
|
val mysql: Properties? = null
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
require(raft == null || bftSMaRt == null || !custom) {
|
require(raft == null || bftSMaRt == null || !custom || mysql == null) {
|
||||||
"raft, bftSMaRt, and custom configs cannot be specified together"
|
"raft, bftSMaRt, custom, and mysql configs cannot be specified together"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val isClusterConfig: Boolean get() = raft != null || bftSMaRt != null
|
val isClusterConfig: Boolean get() = raft != null || bftSMaRt != null
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package net.corda.node.services.transactions
|
||||||
|
|
||||||
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.flows.FlowSession
|
||||||
|
import net.corda.core.node.services.TimeWindowChecker
|
||||||
|
import net.corda.core.node.services.TrustedAuthorityNotaryService
|
||||||
|
import net.corda.node.services.api.ServiceHubInternal
|
||||||
|
import java.security.PublicKey
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/** Notary service backed by a replicated MySQL database. */
|
||||||
|
abstract class MySQLNotaryService(
|
||||||
|
final override val services: ServiceHubInternal,
|
||||||
|
override val notaryIdentityKey: PublicKey,
|
||||||
|
dataSourceProperties: Properties,
|
||||||
|
/** Database table will be automatically created in dev mode */
|
||||||
|
val devMode: Boolean) : TrustedAuthorityNotaryService() {
|
||||||
|
|
||||||
|
override val timeWindowChecker = TimeWindowChecker(services.clock)
|
||||||
|
override val uniquenessProvider = MySQLUniquenessProvider(
|
||||||
|
services.monitoringService.metrics,
|
||||||
|
dataSourceProperties
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun start() {
|
||||||
|
if (devMode) uniquenessProvider.createTable()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stop() {
|
||||||
|
uniquenessProvider.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MySQLNonValidatingNotaryService(services: ServiceHubInternal,
|
||||||
|
notaryIdentityKey: PublicKey,
|
||||||
|
dataSourceProperties: Properties,
|
||||||
|
devMode: Boolean = false) : MySQLNotaryService(services, notaryIdentityKey, dataSourceProperties, devMode) {
|
||||||
|
companion object {
|
||||||
|
val id = constructId(validating = false, mysql = true)
|
||||||
|
}
|
||||||
|
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> = NonValidatingNotaryFlow(otherPartySession, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class MySQLValidatingNotaryService(services: ServiceHubInternal,
|
||||||
|
notaryIdentityKey: PublicKey,
|
||||||
|
dataSourceProperties: Properties,
|
||||||
|
devMode: Boolean = false) : MySQLNotaryService(services, notaryIdentityKey, dataSourceProperties, devMode) {
|
||||||
|
companion object {
|
||||||
|
val id = constructId(validating = true, mysql = true)
|
||||||
|
}
|
||||||
|
override fun createServiceFlow(otherPartySession: FlowSession): FlowLogic<Void?> = ValidatingNotaryFlow(otherPartySession, this)
|
||||||
|
}
|
@ -0,0 +1,162 @@
|
|||||||
|
package net.corda.node.services.transactions
|
||||||
|
|
||||||
|
import com.codahale.metrics.MetricRegistry
|
||||||
|
import com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException
|
||||||
|
import com.zaxxer.hikari.HikariConfig
|
||||||
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
|
import net.corda.core.contracts.StateRef
|
||||||
|
import net.corda.core.crypto.SecureHash
|
||||||
|
import net.corda.core.identity.CordaX500Name
|
||||||
|
import net.corda.core.identity.Party
|
||||||
|
import net.corda.core.node.services.UniquenessException
|
||||||
|
import net.corda.core.node.services.UniquenessProvider
|
||||||
|
import net.corda.core.serialization.SingletonSerializeAsToken
|
||||||
|
import net.corda.core.serialization.deserialize
|
||||||
|
import net.corda.core.serialization.serialize
|
||||||
|
import net.corda.core.utilities.loggerFor
|
||||||
|
import java.security.PublicKey
|
||||||
|
import java.sql.BatchUpdateException
|
||||||
|
import java.sql.Connection
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uniqueness provider backed by a MySQL database. It is intended to be used with a multi-master synchronously replicated
|
||||||
|
* variant of MySQL, such as Percona XtraDB Cluster, or MariaDB Galera Cluster.
|
||||||
|
*
|
||||||
|
* Note that no ORM is used since we want to retain full control over table schema and be able to experiment with optimisations.
|
||||||
|
*/
|
||||||
|
class MySQLUniquenessProvider(
|
||||||
|
metrics: MetricRegistry,
|
||||||
|
dataSourceProperties: Properties
|
||||||
|
) : UniquenessProvider, SingletonSerializeAsToken() {
|
||||||
|
companion object {
|
||||||
|
private val log = loggerFor<MySQLUniquenessProvider>()
|
||||||
|
|
||||||
|
// TODO: optimize table schema for InnoDB
|
||||||
|
private val createTableStatement =
|
||||||
|
"CREATE TABLE IF NOT EXISTS committed_states (" +
|
||||||
|
"issue_tx_id BINARY(32) NOT NULL," +
|
||||||
|
"issue_tx_output_id INT NOT NULL," +
|
||||||
|
"consuming_tx_id BINARY(32) NOT NULL," +
|
||||||
|
"consuming_tx_input_id INT UNSIGNED NOT NULL," +
|
||||||
|
"consuming_party_name TEXT NOT NULL," +
|
||||||
|
// TODO: do we need to store the key? X500 name should be sufficient
|
||||||
|
"consuming_party_key BLOB NOT NULL," +
|
||||||
|
"commit_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP," +
|
||||||
|
"CONSTRAINT id PRIMARY KEY (issue_tx_id, issue_tx_output_id)" +
|
||||||
|
")"
|
||||||
|
private val insertStatement = "INSERT INTO committed_states (issue_tx_id, issue_tx_output_id, consuming_tx_id, consuming_tx_input_id, consuming_party_name, consuming_party_key) VALUES (?, ?, ?, ?, ?, ?)"
|
||||||
|
private val findStatement = "SELECT consuming_tx_id, consuming_tx_input_id, consuming_party_name, consuming_party_key FROM committed_states WHERE issue_tx_id = ? AND issue_tx_output_id = ?"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val metricPrefix = MySQLUniquenessProvider::class.simpleName
|
||||||
|
/** Transaction commit duration and rate metric timer */
|
||||||
|
private val commitTimer = metrics.timer("$metricPrefix.Commit")
|
||||||
|
/**
|
||||||
|
* When writing to multiple masters with Galera, transaction rollbacks may happen due to high write contention.
|
||||||
|
* This is a useful heath metric.
|
||||||
|
*/
|
||||||
|
private val rollbackCounter = metrics.counter("$metricPrefix.Rollback")
|
||||||
|
/** Track double spend attempts. Note that this will also include notarisation retries. */
|
||||||
|
private val conflictCounter = metrics.counter("$metricPrefix.Conflicts")
|
||||||
|
|
||||||
|
val dataSource = HikariDataSource(HikariConfig(dataSourceProperties))
|
||||||
|
|
||||||
|
private val connection: Connection
|
||||||
|
get() = dataSource.connection
|
||||||
|
|
||||||
|
fun createTable() {
|
||||||
|
log.debug("Attempting to create DB table if it does not yet exist: $createTableStatement")
|
||||||
|
connection.use {
|
||||||
|
it.createStatement().execute(createTableStatement)
|
||||||
|
it.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
dataSource.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun commit(states: List<StateRef>, txId: SecureHash, callerIdentity: Party) {
|
||||||
|
val timer = commitTimer.time()
|
||||||
|
try {
|
||||||
|
retryTransaction(CommitAll(states, txId, callerIdentity))
|
||||||
|
} catch (e: BatchUpdateException) {
|
||||||
|
log.info("Unable to commit input states, finding conflicts", e)
|
||||||
|
conflictCounter.inc()
|
||||||
|
retryTransaction(FindConflicts(states))
|
||||||
|
} finally {
|
||||||
|
timer.stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retryTransaction(tx: RetryableTransaction) {
|
||||||
|
connection.use {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
tx.run(it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
it.rollback()
|
||||||
|
if (e is MySQLTransactionRollbackException) {
|
||||||
|
log.warn("Rollback exception occurred, retrying", e)
|
||||||
|
rollbackCounter.inc()
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
it.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RetryableTransaction {
|
||||||
|
fun run(conn: Connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommitAll(val states: List<StateRef>, val txId: SecureHash, val callerIdentity: Party) : RetryableTransaction {
|
||||||
|
override fun run(conn: Connection) {
|
||||||
|
conn.prepareStatement(insertStatement).apply {
|
||||||
|
states.forEachIndexed { index, stateRef ->
|
||||||
|
// StateRef
|
||||||
|
setBytes(1, stateRef.txhash.bytes)
|
||||||
|
setInt(2, stateRef.index)
|
||||||
|
// Consuming transaction
|
||||||
|
setBytes(3, txId.bytes)
|
||||||
|
setInt(4, index)
|
||||||
|
setString(5, callerIdentity.name.toString())
|
||||||
|
setBytes(6, callerIdentity.owningKey.serialize().bytes)
|
||||||
|
|
||||||
|
addBatch()
|
||||||
|
clearParameters()
|
||||||
|
}
|
||||||
|
executeBatch()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FindConflicts(val states: List<StateRef>) : RetryableTransaction {
|
||||||
|
override fun run(conn: Connection) {
|
||||||
|
val conflicts = mutableMapOf<StateRef, UniquenessProvider.ConsumingTx>()
|
||||||
|
states.forEach {
|
||||||
|
val st = conn.prepareStatement(findStatement).apply {
|
||||||
|
setBytes(1, it.txhash.bytes)
|
||||||
|
setInt(2, it.index)
|
||||||
|
}
|
||||||
|
val result = st.executeQuery()
|
||||||
|
|
||||||
|
if (result.next()) {
|
||||||
|
val consumingTxId = SecureHash.SHA256(result.getBytes(1))
|
||||||
|
val inputIndex = result.getInt(2)
|
||||||
|
val partyName = CordaX500Name.parse(result.getString(3))
|
||||||
|
val partyKey: PublicKey = result.getBytes(4).deserialize()
|
||||||
|
conflicts[it] = UniquenessProvider.ConsumingTx(consumingTxId, inputIndex, Party(partyName, partyKey))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.commit()
|
||||||
|
if (conflicts.isNotEmpty()) throw UniquenessException(UniquenessProvider.Conflict(conflicts))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,5 +33,4 @@ enterpriseConfiguration = {
|
|||||||
waitInterval = 40000
|
waitInterval = 40000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useAMQPBridges = true
|
useAMQPBridges = true
|
@ -46,10 +46,8 @@ import java.util.stream.StreamSupport;
|
|||||||
import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
|
import static net.corda.core.node.services.vault.QueryCriteriaUtils.DEFAULT_PAGE_NUM;
|
||||||
import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
|
import static net.corda.core.node.services.vault.QueryCriteriaUtils.MAX_PAGE_SIZE;
|
||||||
import static net.corda.core.utilities.ByteArrays.toHexString;
|
import static net.corda.core.utilities.ByteArrays.toHexString;
|
||||||
|
import static net.corda.testing.TestConstants.*;
|
||||||
import static net.corda.testing.internal.InternalTestUtilsKt.rigorousMock;
|
import static net.corda.testing.internal.InternalTestUtilsKt.rigorousMock;
|
||||||
import static net.corda.testing.TestConstants.BOC_NAME;
|
|
||||||
import static net.corda.testing.TestConstants.CHARLIE_NAME;
|
|
||||||
import static net.corda.testing.TestConstants.DUMMY_NOTARY_NAME;
|
|
||||||
import static net.corda.testing.node.MockServices.makeTestDatabaseAndMockServices;
|
import static net.corda.testing.node.MockServices.makeTestDatabaseAndMockServices;
|
||||||
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
import static net.corda.testing.node.MockServicesKt.makeTestIdentityService;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@ -74,7 +72,8 @@ public class VaultQueryJavaTests {
|
|||||||
"net.corda.testing.internal.vault",
|
"net.corda.testing.internal.vault",
|
||||||
"net.corda.finance.contracts.asset",
|
"net.corda.finance.contracts.asset",
|
||||||
CashSchemaV1.class.getPackage().getName(),
|
CashSchemaV1.class.getPackage().getName(),
|
||||||
DummyLinearStateSchemaV1.class.getPackage().getName());
|
DummyLinearStateSchemaV1.class.getPackage().getName()
|
||||||
|
);
|
||||||
IdentityServiceInternal identitySvc = makeTestIdentityService(MEGA_CORP.getIdentity(), DUMMY_CASH_ISSUER_INFO.getIdentity(), DUMMY_NOTARY.getIdentity());
|
IdentityServiceInternal identitySvc = makeTestIdentityService(MEGA_CORP.getIdentity(), DUMMY_CASH_ISSUER_INFO.getIdentity(), DUMMY_NOTARY.getIdentity());
|
||||||
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(
|
Pair<CordaPersistence, MockServices> databaseAndServices = makeTestDatabaseAndMockServices(
|
||||||
cordappPackages,
|
cordappPackages,
|
||||||
|
@ -13,11 +13,12 @@ import net.corda.node.services.statemachine.FlowStart
|
|||||||
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import net.corda.testing.*
|
import net.corda.testing.ALICE_NAME
|
||||||
import net.corda.testing.internal.LogHelper
|
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
import net.corda.testing.TestIdentity
|
||||||
|
import net.corda.testing.internal.LogHelper
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
|
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
|
@ -24,26 +24,26 @@ import net.corda.finance.POUNDS
|
|||||||
import net.corda.finance.SWISS_FRANCS
|
import net.corda.finance.SWISS_FRANCS
|
||||||
import net.corda.finance.contracts.asset.Cash
|
import net.corda.finance.contracts.asset.Cash
|
||||||
import net.corda.finance.contracts.asset.DummyFungibleContract
|
import net.corda.finance.contracts.asset.DummyFungibleContract
|
||||||
import net.corda.finance.schemas.CashSchemaV1
|
|
||||||
import net.corda.finance.sampleschemas.SampleCashSchemaV2
|
import net.corda.finance.sampleschemas.SampleCashSchemaV2
|
||||||
import net.corda.finance.sampleschemas.SampleCashSchemaV3
|
import net.corda.finance.sampleschemas.SampleCashSchemaV3
|
||||||
|
import net.corda.finance.schemas.CashSchemaV1
|
||||||
import net.corda.finance.utils.sumCash
|
import net.corda.finance.utils.sumCash
|
||||||
|
import net.corda.node.internal.configureDatabase
|
||||||
|
import net.corda.node.services.api.IdentityServiceInternal
|
||||||
import net.corda.node.services.schema.HibernateObserver
|
import net.corda.node.services.schema.HibernateObserver
|
||||||
import net.corda.node.services.schema.NodeSchemaService
|
import net.corda.node.services.schema.NodeSchemaService
|
||||||
import net.corda.node.services.vault.VaultSchemaV1
|
import net.corda.node.services.vault.VaultSchemaV1
|
||||||
import net.corda.node.internal.configureDatabase
|
|
||||||
import net.corda.node.services.api.IdentityServiceInternal
|
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
|
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.internal.vault.DummyDealStateSchemaV1
|
import net.corda.testing.internal.vault.DummyDealStateSchemaV1
|
||||||
|
import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
|
||||||
|
import net.corda.testing.internal.vault.DummyLinearStateSchemaV2
|
||||||
import net.corda.testing.internal.vault.VaultFiller
|
import net.corda.testing.internal.vault.VaultFiller
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||||
import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
|
|
||||||
import net.corda.testing.internal.vault.DummyLinearStateSchemaV2
|
|
||||||
import org.assertj.core.api.Assertions
|
import org.assertj.core.api.Assertions
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.hibernate.SessionFactory
|
import org.hibernate.SessionFactory
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package net.corda.node.services.vault
|
package net.corda.node.services.vault
|
||||||
|
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.ContractState
|
||||||
|
import net.corda.core.contracts.InsufficientBalanceException
|
||||||
|
import net.corda.core.contracts.LinearState
|
||||||
|
import net.corda.core.contracts.UniqueIdentifier
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import net.corda.core.identity.AnonymousParty
|
import net.corda.core.identity.AnonymousParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
@ -42,7 +45,7 @@ import kotlin.test.fail
|
|||||||
class VaultWithCashTest {
|
class VaultWithCashTest {
|
||||||
private companion object {
|
private companion object {
|
||||||
private val cordappPackages = listOf(
|
private val cordappPackages = listOf(
|
||||||
"net.corda.testing.internal.vault", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName)
|
"net.corda.testing.contracts", "net.corda.finance.contracts.asset", CashSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName)
|
||||||
val BOB = TestIdentity(BOB_NAME, 80).party
|
val BOB = TestIdentity(BOB_NAME, 80).party
|
||||||
val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
|
val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
|
||||||
val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)
|
val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)
|
||||||
|
@ -4,18 +4,17 @@ import com.nhaarman.mockito_kotlin.doReturn
|
|||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import com.r3.corda.enterprise.perftestcordapp.DOLLARS
|
import com.r3.corda.enterprise.perftestcordapp.DOLLARS
|
||||||
import com.r3.corda.enterprise.perftestcordapp.`issued by`
|
import com.r3.corda.enterprise.perftestcordapp.`issued by`
|
||||||
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.*
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.CASH
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.DUMMY_CASH_ISSUER_KEY
|
||||||
|
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.STATE
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.crypto.generateKeyPair
|
|
||||||
import net.corda.core.identity.AnonymousParty
|
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.node.services.Vault
|
import net.corda.core.node.services.Vault
|
||||||
import net.corda.core.node.services.VaultService
|
import net.corda.core.node.services.VaultService
|
||||||
import net.corda.core.transactions.SignedTransaction
|
import net.corda.core.transactions.SignedTransaction
|
||||||
import net.corda.core.transactions.TransactionBuilder
|
|
||||||
import net.corda.core.utilities.days
|
import net.corda.core.utilities.days
|
||||||
import net.corda.core.utilities.seconds
|
|
||||||
import net.corda.node.services.api.IdentityServiceInternal
|
import net.corda.node.services.api.IdentityServiceInternal
|
||||||
import net.corda.testing.*
|
import net.corda.testing.*
|
||||||
import net.corda.testing.dsl.EnforceVerifyOrFail
|
import net.corda.testing.dsl.EnforceVerifyOrFail
|
||||||
@ -24,16 +23,12 @@ import net.corda.testing.dsl.TransactionDSLInterpreter
|
|||||||
import net.corda.testing.internal.rigorousMock
|
import net.corda.testing.internal.rigorousMock
|
||||||
import net.corda.testing.node.MockServices
|
import net.corda.testing.node.MockServices
|
||||||
import net.corda.testing.node.ledger
|
import net.corda.testing.node.ledger
|
||||||
import net.corda.testing.node.makeTestIdentityService
|
|
||||||
import net.corda.testing.node.transaction
|
import net.corda.testing.node.transaction
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.junit.runners.Parameterized
|
import org.junit.runners.Parameterized
|
||||||
import java.time.Instant
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertFailsWith
|
|
||||||
import kotlin.test.assertTrue
|
|
||||||
|
|
||||||
// TODO: The generate functions aren't tested by these tests: add them.
|
// TODO: The generate functions aren't tested by these tests: add them.
|
||||||
|
|
||||||
@ -47,8 +42,7 @@ interface CommercialPaperTestTemplate {
|
|||||||
|
|
||||||
private val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
private val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
||||||
private val MEGA_CORP get() = megaCorp.party
|
private val MEGA_CORP get() = megaCorp.party
|
||||||
private val MEGA_CORP_IDENTITY get() = megaCorp.identity
|
private val MEGA_CORP_PUBKEY get() = megaCorp.keyPair.public
|
||||||
private val MEGA_CORP_PUBKEY get() = megaCorp.publicKey
|
|
||||||
|
|
||||||
|
|
||||||
class KotlinCommercialPaperTest : CommercialPaperTestTemplate {
|
class KotlinCommercialPaperTest : CommercialPaperTestTemplate {
|
||||||
@ -85,21 +79,14 @@ class CommercialPaperTestsGeneric {
|
|||||||
@Parameterized.Parameters @JvmStatic
|
@Parameterized.Parameters @JvmStatic
|
||||||
fun data() = listOf(KotlinCommercialPaperTest(), KotlinCommercialPaperLegacyTest())
|
fun data() = listOf(KotlinCommercialPaperTest(), KotlinCommercialPaperLegacyTest())
|
||||||
|
|
||||||
private val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
|
|
||||||
private val DUMMY_CASH_ISSUER_IDENTITY get() = dummyCashIssuer.identity
|
|
||||||
private val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)
|
|
||||||
private val alice = TestIdentity(ALICE_NAME, 70)
|
private val alice = TestIdentity(ALICE_NAME, 70)
|
||||||
private val BIG_CORP_KEY = generateKeyPair()
|
|
||||||
private val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
|
private val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
|
||||||
private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
|
private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
|
||||||
private val ALICE get() = alice.party
|
private val ALICE get() = alice.party
|
||||||
private val ALICE_KEY get() = alice.keyPair
|
private val ALICE_PUBKEY get() = alice.keyPair.public
|
||||||
private val ALICE_PUBKEY get() = alice.publicKey
|
|
||||||
private val DUMMY_NOTARY get() = dummyNotary.party
|
private val DUMMY_NOTARY get() = dummyNotary.party
|
||||||
private val DUMMY_NOTARY_IDENTITY get() = dummyNotary.identity
|
|
||||||
private val MINI_CORP get() = miniCorp.party
|
private val MINI_CORP get() = miniCorp.party
|
||||||
private val MINI_CORP_IDENTITY get() = miniCorp.identity
|
private val MINI_CORP_PUBKEY get() = miniCorp.keyPair.public
|
||||||
private val MINI_CORP_PUBKEY get() = miniCorp.publicKey
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +146,10 @@ class CommercialPaperTestsGeneric {
|
|||||||
output(Cash.PROGRAM_ID, "Alice's profit", aliceGetsBack.STATE ownedBy ALICE)
|
output(Cash.PROGRAM_ID, "Alice's profit", aliceGetsBack.STATE ownedBy ALICE)
|
||||||
output(Cash.PROGRAM_ID, "Change", (someProfits - aliceGetsBack).STATE ownedBy MEGA_CORP)
|
output(Cash.PROGRAM_ID, "Change", (someProfits - aliceGetsBack).STATE ownedBy MEGA_CORP)
|
||||||
}
|
}
|
||||||
|
|
||||||
command(MEGA_CORP_PUBKEY, Cash.Commands.Move())
|
command(MEGA_CORP_PUBKEY, Cash.Commands.Move())
|
||||||
command(ALICE_PUBKEY, thisTest.getRedeemCommand(DUMMY_NOTARY))
|
command(ALICE_PUBKEY, thisTest.getRedeemCommand(DUMMY_NOTARY))
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
outputs(700.DOLLARS `issued by` issuer)
|
outputs(700.DOLLARS `issued by` issuer)
|
||||||
timeWindow(TEST_TX_TIME + 8.days)
|
timeWindow(TEST_TX_TIME + 8.days)
|
||||||
@ -252,96 +241,7 @@ class CommercialPaperTestsGeneric {
|
|||||||
private lateinit var alicesVault: Vault<ContractState>
|
private lateinit var alicesVault: Vault<ContractState>
|
||||||
|
|
||||||
private val notaryServices = MockServices(emptyList(), rigorousMock(), MEGA_CORP.name, dummyNotary.keyPair)
|
private val notaryServices = MockServices(emptyList(), rigorousMock(), MEGA_CORP.name, dummyNotary.keyPair)
|
||||||
private val issuerServices = MockServices(listOf("net.corda.finance.contracts", "net.corda.finance.schemas"), rigorousMock(), MEGA_CORP.name, dummyCashIssuer.keyPair)
|
private val issuerServices = MockServices(emptyList(), rigorousMock(), MEGA_CORP.name, DUMMY_CASH_ISSUER_KEY)
|
||||||
|
|
||||||
private lateinit var moveTX: SignedTransaction
|
private lateinit var moveTX: SignedTransaction
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `issue move and then redeem`() {
|
|
||||||
val aliceDatabaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
|
||||||
listOf("net.corda.finance.contracts"),
|
|
||||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY),
|
|
||||||
TestIdentity(MEGA_CORP.name, ALICE_KEY))
|
|
||||||
val databaseAlice = aliceDatabaseAndServices.first
|
|
||||||
aliceServices = aliceDatabaseAndServices.second
|
|
||||||
aliceVaultService = aliceServices.vaultService
|
|
||||||
|
|
||||||
databaseAlice.transaction {
|
|
||||||
alicesVault = aliceServices.fillWithSomeTestCash(9000.DOLLARS, issuerServices, issuedBy = DUMMY_CASH_ISSUER, outputNotary = DUMMY_NOTARY)
|
|
||||||
aliceVaultService = aliceServices.vaultService
|
|
||||||
}
|
|
||||||
|
|
||||||
val bigCorpDatabaseAndServices = MockServices.makeTestDatabaseAndMockServices(
|
|
||||||
listOf("net.corda.finance.contracts"),
|
|
||||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY),
|
|
||||||
TestIdentity(MEGA_CORP.name, BIG_CORP_KEY))
|
|
||||||
val databaseBigCorp = bigCorpDatabaseAndServices.first
|
|
||||||
bigCorpServices = bigCorpDatabaseAndServices.second
|
|
||||||
bigCorpVaultService = bigCorpServices.vaultService
|
|
||||||
|
|
||||||
databaseBigCorp.transaction {
|
|
||||||
bigCorpVault = bigCorpServices.fillWithSomeTestCash(13000.DOLLARS, issuerServices, issuedBy = DUMMY_CASH_ISSUER, outputNotary = DUMMY_NOTARY)
|
|
||||||
bigCorpVaultService = bigCorpServices.vaultService
|
|
||||||
}
|
|
||||||
|
|
||||||
// Propagate the cash transactions to each side.
|
|
||||||
aliceServices.recordTransactions(bigCorpVault.states.map { bigCorpServices.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
|
||||||
bigCorpServices.recordTransactions(alicesVault.states.map { aliceServices.validatedTransactions.getTransaction(it.ref.txhash)!! })
|
|
||||||
|
|
||||||
// BigCorp™ issues $10,000 of commercial paper, to mature in 30 days, owned initially by itself.
|
|
||||||
val faceValue = 10000.DOLLARS `issued by` DUMMY_CASH_ISSUER
|
|
||||||
val issuance = bigCorpServices.myInfo.chooseIdentity().ref(1)
|
|
||||||
val issueBuilder = CommercialPaper().generateIssue(issuance, faceValue, TEST_TX_TIME + 30.days, DUMMY_NOTARY)
|
|
||||||
issueBuilder.setTimeWindow(TEST_TX_TIME, 30.seconds)
|
|
||||||
val issuePtx = bigCorpServices.signInitialTransaction(issueBuilder)
|
|
||||||
val issueTx = notaryServices.addSignature(issuePtx)
|
|
||||||
|
|
||||||
databaseAlice.transaction {
|
|
||||||
// Alice pays $9000 to BigCorp to own some of their debt.
|
|
||||||
moveTX = run {
|
|
||||||
val builder = TransactionBuilder(DUMMY_NOTARY)
|
|
||||||
Cash.generateSpend(aliceServices, builder, 9000.DOLLARS, AnonymousParty(BIG_CORP_KEY.public))
|
|
||||||
CommercialPaper().generateMove(builder, issueTx.tx.outRef(0), AnonymousParty(ALICE_PUBKEY))
|
|
||||||
val ptx = aliceServices.signInitialTransaction(builder)
|
|
||||||
val ptx2 = bigCorpServices.addSignature(ptx)
|
|
||||||
val stx = notaryServices.addSignature(ptx2)
|
|
||||||
stx
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseBigCorp.transaction {
|
|
||||||
// Verify the txns are valid and insert into both sides.
|
|
||||||
listOf(issueTx, moveTX).forEach {
|
|
||||||
it.toLedgerTransaction(aliceServices).verify()
|
|
||||||
aliceServices.recordTransactions(it)
|
|
||||||
bigCorpServices.recordTransactions(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseBigCorp.transaction {
|
|
||||||
fun makeRedeemTX(time: Instant): Pair<SignedTransaction, UUID> {
|
|
||||||
val builder = TransactionBuilder(DUMMY_NOTARY)
|
|
||||||
builder.setTimeWindow(time, 30.seconds)
|
|
||||||
CommercialPaper().generateRedeem(builder, moveTX.tx.outRef(1), bigCorpServices, bigCorpServices.myInfo.chooseIdentityAndCert())
|
|
||||||
val ptx = aliceServices.signInitialTransaction(builder)
|
|
||||||
val ptx2 = bigCorpServices.addSignature(ptx)
|
|
||||||
val stx = notaryServices.addSignature(ptx2)
|
|
||||||
return Pair(stx, builder.lockId)
|
|
||||||
}
|
|
||||||
|
|
||||||
val redeemTX = makeRedeemTX(TEST_TX_TIME + 10.days)
|
|
||||||
val tooEarlyRedemption = redeemTX.first
|
|
||||||
val tooEarlyRedemptionLockId = redeemTX.second
|
|
||||||
val e = assertFailsWith(TransactionVerificationException::class) {
|
|
||||||
tooEarlyRedemption.toLedgerTransaction(aliceServices).verify()
|
|
||||||
}
|
|
||||||
// manually release locks held by this failing transaction
|
|
||||||
aliceServices.vaultService.softLockRelease(tooEarlyRedemptionLockId)
|
|
||||||
assertTrue(e.cause!!.message!!.contains("paper must have matured"))
|
|
||||||
|
|
||||||
val validRedemption = makeRedeemTX(TEST_TX_TIME + 31.days).first
|
|
||||||
validRedemption.toLedgerTransaction(aliceServices).verify()
|
|
||||||
// soft lock not released after success either!!! (as transaction not recorded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -137,13 +137,19 @@ class CashTests {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
LogHelper.setLevel(NodeVaultService::class)
|
LogHelper.setLevel(NodeVaultService::class)
|
||||||
megaCorpServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"), rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
|
megaCorpServices = MockServices(
|
||||||
miniCorpServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"), rigorousMock<IdentityServiceInternal>().also {
|
|
||||||
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name })
|
|
||||||
}, MINI_CORP.name, MINI_CORP_KEY)
|
|
||||||
val notaryServices = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"), rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
|
||||||
val databaseAndServices = makeTestDatabaseAndMockServices(
|
|
||||||
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
|
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
|
||||||
|
rigorousMock(), MEGA_CORP.name, MEGA_CORP_KEY)
|
||||||
|
miniCorpServices = MockServices(
|
||||||
|
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
|
||||||
|
rigorousMock<IdentityServiceInternal>().also {
|
||||||
|
doNothing().whenever(it).justVerifyAndRegisterIdentity(argThat { name == MINI_CORP.name })
|
||||||
|
}, MINI_CORP.name, MINI_CORP_KEY)
|
||||||
|
val notaryServices = MockServices(
|
||||||
|
listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset", "com.r3.corda.enterprise.perftestcordapp.schemas"),
|
||||||
|
rigorousMock(), DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||||
|
val databaseAndServices = makeTestDatabaseAndMockServices(
|
||||||
|
listOf("net.corda.finance.contracts.asset", "net.corda.finance.schemas"),
|
||||||
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY),
|
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, DUMMY_CASH_ISSUER_IDENTITY, DUMMY_NOTARY_IDENTITY),
|
||||||
TestIdentity(CordaX500Name("Me", "London", "GB")))
|
TestIdentity(CordaX500Name("Me", "London", "GB")))
|
||||||
database = databaseAndServices.first
|
database = databaseAndServices.first
|
||||||
@ -879,7 +885,7 @@ class CashTests {
|
|||||||
transaction {
|
transaction {
|
||||||
attachment(Cash.PROGRAM_ID)
|
attachment(Cash.PROGRAM_ID)
|
||||||
input("MEGA_CORP cash")
|
input("MEGA_CORP cash")
|
||||||
// We send it to another publicKey so that the transaction is not identical to the previous one
|
// We send it to another pubkey so that the transaction is not identical to the previous one
|
||||||
output(Cash.PROGRAM_ID, "MEGA_CORP cash 3", "MEGA_CORP cash".output<Cash.State>().copy(owner = ALICE))
|
output(Cash.PROGRAM_ID, "MEGA_CORP cash 3", "MEGA_CORP cash".output<Cash.State>().copy(owner = ALICE))
|
||||||
command(MEGA_CORP_PUBKEY, Cash.Commands.Move())
|
command(MEGA_CORP_PUBKEY, Cash.Commands.Move())
|
||||||
this.verifies()
|
this.verifies()
|
||||||
|
@ -51,6 +51,9 @@ include 'samples:notary-demo'
|
|||||||
include 'samples:bank-of-corda-demo'
|
include 'samples:bank-of-corda-demo'
|
||||||
include 'samples:business-network-demo'
|
include 'samples:business-network-demo'
|
||||||
include 'cordform-common'
|
include 'cordform-common'
|
||||||
|
include 'network-management'
|
||||||
|
include 'network-management:capsule'
|
||||||
|
include 'network-management:capsule-hsm'
|
||||||
include 'verify-enclave'
|
include 'verify-enclave'
|
||||||
include 'hsm-tool'
|
include 'hsm-tool'
|
||||||
project(':hsm-tool').with {
|
project(':hsm-tool').with {
|
||||||
|
@ -268,8 +268,7 @@ class InMemoryMessagingNetwork internal constructor(
|
|||||||
private val peerHandle: PeerHandle,
|
private val peerHandle: PeerHandle,
|
||||||
private val executor: AffinityExecutor,
|
private val executor: AffinityExecutor,
|
||||||
private val database: CordaPersistence) : SingletonSerializeAsToken(), MessagingService {
|
private val database: CordaPersistence) : SingletonSerializeAsToken(), MessagingService {
|
||||||
private inner class Handler(val topicSession: String,
|
inner class Handler(val topicSession: String, val callback: MessageHandler) : MessageHandlerRegistration
|
||||||
val callback: MessageHandler) : MessageHandlerRegistration
|
|
||||||
|
|
||||||
@Volatile
|
@Volatile
|
||||||
private var running = true
|
private var running = true
|
||||||
|
@ -398,7 +398,7 @@ class MockNetwork(private val cordappPackages: List<String>,
|
|||||||
val config = mockNodeConfiguration().also {
|
val config = mockNodeConfiguration().also {
|
||||||
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
|
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
|
||||||
doReturn(parameters.legalName ?: CordaX500Name("Mock Company $id", "London", "GB")).whenever(it).myLegalName
|
doReturn(parameters.legalName ?: CordaX500Name("Mock Company $id", "London", "GB")).whenever(it).myLegalName
|
||||||
doReturn(makeTestDataSourceProperties("node_$id", "net_$networkId")).whenever(it).dataSourceProperties
|
doReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")).whenever(it).dataSourceProperties
|
||||||
doReturn(makeTestDatabaseProperties("node_$id")).whenever(it).database
|
doReturn(makeTestDatabaseProperties("node_$id")).whenever(it).database
|
||||||
parameters.configOverrides(it)
|
parameters.configOverrides(it)
|
||||||
}
|
}
|
||||||
@ -503,6 +503,5 @@ private fun mockNodeConfiguration(): NodeConfiguration {
|
|||||||
doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec
|
doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec
|
||||||
doReturn(null).whenever(it).devModeOptions
|
doReturn(null).whenever(it).devModeOptions
|
||||||
doReturn(true).whenever(it).useAMQPBridges
|
doReturn(true).whenever(it).useAMQPBridges
|
||||||
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000))).whenever(it).enterpriseConfiguration
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,9 @@ import net.corda.core.serialization.internal.effectiveSerializationEnv
|
|||||||
import net.corda.core.transactions.TransactionBuilder
|
import net.corda.core.transactions.TransactionBuilder
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.node.services.api.StartedNodeServices
|
import net.corda.node.services.api.StartedNodeServices
|
||||||
import net.corda.testing.*
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
|
import net.corda.testing.TestIdentity
|
||||||
|
import net.corda.testing.chooseIdentity
|
||||||
import net.corda.testing.dsl.*
|
import net.corda.testing.dsl.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +39,9 @@ dependencies {
|
|||||||
runtime group: 'org.apache.jmeter', name: 'ApacheJMeter_config', version: "$jmVersion"
|
runtime group: 'org.apache.jmeter', name: 'ApacheJMeter_config', version: "$jmVersion"
|
||||||
runtime group: 'org.apache.jmeter', name: 'ApacheJMeter', version: "$jmVersion"
|
runtime group: 'org.apache.jmeter', name: 'ApacheJMeter', version: "$jmVersion"
|
||||||
runtime group: 'org.apache.jmeter', name: 'jorphan', version: "$jmVersion"
|
runtime group: 'org.apache.jmeter', name: 'jorphan', version: "$jmVersion"
|
||||||
|
//For Azure SQL and SQL Server support in persistence
|
||||||
|
runtime group: 'com.microsoft.sqlserver', name: 'mssql-jdbc', version: '6.2.1.jre8'
|
||||||
|
|
||||||
|
|
||||||
testCompile project(':test-utils')
|
testCompile project(':test-utils')
|
||||||
testCompile project(':node-driver')
|
testCompile project(':node-driver')
|
||||||
|
244
tools/jmeter/src/main/resources/Testplans/SQL.jmx
Normal file
244
tools/jmeter/src/main/resources/Testplans/SQL.jmx
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
||||||
|
<hashTree>
|
||||||
|
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
|
||||||
|
<stringProp name="TestPlan.comments"></stringProp>
|
||||||
|
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||||||
|
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
||||||
|
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||||
|
</TestPlan>
|
||||||
|
<hashTree>
|
||||||
|
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
||||||
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">40000</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="ThreadGroup.num_threads">3</stringProp>
|
||||||
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
|
<longProp name="ThreadGroup.start_time">1509455820000</longProp>
|
||||||
|
<longProp name="ThreadGroup.end_time">1509455820000</longProp>
|
||||||
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
|
</ThreadGroup>
|
||||||
|
<hashTree>
|
||||||
|
<JDBCDataSource guiclass="TestBeanGUI" testclass="JDBCDataSource" testname="JDBC Connection Configuration" enabled="true">
|
||||||
|
<boolProp name="autocommit">true</boolProp>
|
||||||
|
<stringProp name="checkQuery"></stringProp>
|
||||||
|
<stringProp name="connectionAge">5000</stringProp>
|
||||||
|
<stringProp name="dataSource">testpool</stringProp>
|
||||||
|
<stringProp name="dbUrl">jdbc:sqlserver://perfperformancetest.database.windows.net:1433;databaseName=perftesting</stringProp>
|
||||||
|
<stringProp name="driver">com.microsoft.sqlserver.jdbc.SQLServerDriver</stringProp>
|
||||||
|
<boolProp name="keepAlive">true</boolProp>
|
||||||
|
<stringProp name="password">yourStrong(!)Password</stringProp>
|
||||||
|
<stringProp name="poolMax">0</stringProp>
|
||||||
|
<stringProp name="timeout">10000</stringProp>
|
||||||
|
<stringProp name="transactionIsolation">TRANSACTION_REPEATABLE_READ</stringProp>
|
||||||
|
<stringProp name="trimInterval">60000</stringProp>
|
||||||
|
<stringProp name="username">perfnode1@perfperformancetest</stringProp>
|
||||||
|
</JDBCDataSource>
|
||||||
|
<hashTree/>
|
||||||
|
<JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC Request" enabled="true">
|
||||||
|
<stringProp name="dataSource">testpool</stringProp>
|
||||||
|
<stringProp name="query">select dbtransact0_.tx_id as tx_id1_22_0_, dbtransact0_.transaction_value as transact2_22_0_ from perfnode1.node_transactions dbtransact0_ where dbtransact0_.tx_id='${__UUID()}'</stringProp>
|
||||||
|
<stringProp name="queryArguments"></stringProp>
|
||||||
|
<stringProp name="queryArgumentsTypes"></stringProp>
|
||||||
|
<stringProp name="queryTimeout"></stringProp>
|
||||||
|
<stringProp name="queryType">Select Statement</stringProp>
|
||||||
|
<stringProp name="resultSetHandler">Store as String</stringProp>
|
||||||
|
<stringProp name="resultVariable"></stringProp>
|
||||||
|
<stringProp name="variableNames"></stringProp>
|
||||||
|
</JDBCSampler>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<WorkBench guiclass="WorkBenchGui" testclass="WorkBench" testname="WorkBench" enabled="true">
|
||||||
|
<boolProp name="WorkBench.save">true</boolProp>
|
||||||
|
</WorkBench>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</jmeterTestPlan>
|
246
tools/jmeter/src/main/resources/Testplans/SQL_parmeterized.jmx
Normal file
246
tools/jmeter/src/main/resources/Testplans/SQL_parmeterized.jmx
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<jmeterTestPlan version="1.2" properties="3.2" jmeter="3.3 r1808647">
|
||||||
|
<hashTree>
|
||||||
|
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
|
||||||
|
<stringProp name="TestPlan.comments"></stringProp>
|
||||||
|
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||||||
|
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
||||||
|
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||||
|
<collectionProp name="Arguments.arguments"/>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||||
|
</TestPlan>
|
||||||
|
<hashTree>
|
||||||
|
<JDBCDataSource guiclass="TestBeanGUI" testclass="JDBCDataSource" testname="JDBC Connection Configuration" enabled="true">
|
||||||
|
<boolProp name="autocommit">true</boolProp>
|
||||||
|
<stringProp name="checkQuery"></stringProp>
|
||||||
|
<stringProp name="connectionAge">5000</stringProp>
|
||||||
|
<stringProp name="dataSource">testpool</stringProp>
|
||||||
|
<stringProp name="dbUrl">jdbc:sqlserver://perfperformancetest.database.windows.net:1433;databaseName=perftesting</stringProp>
|
||||||
|
<stringProp name="driver">com.microsoft.sqlserver.jdbc.SQLServerDriver</stringProp>
|
||||||
|
<boolProp name="keepAlive">true</boolProp>
|
||||||
|
<stringProp name="password">yourStrong(!)Password</stringProp>
|
||||||
|
<stringProp name="poolMax">0</stringProp>
|
||||||
|
<stringProp name="timeout">10000</stringProp>
|
||||||
|
<stringProp name="transactionIsolation">TRANSACTION_REPEATABLE_READ</stringProp>
|
||||||
|
<stringProp name="trimInterval">60000</stringProp>
|
||||||
|
<stringProp name="username">perfnode1@perfperformancetest</stringProp>
|
||||||
|
</JDBCDataSource>
|
||||||
|
<hashTree/>
|
||||||
|
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
||||||
|
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||||
|
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||||
|
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||||
|
<stringProp name="LoopController.loops">40000</stringProp>
|
||||||
|
</elementProp>
|
||||||
|
<stringProp name="ThreadGroup.num_threads">3</stringProp>
|
||||||
|
<stringProp name="ThreadGroup.ramp_time">1</stringProp>
|
||||||
|
<longProp name="ThreadGroup.start_time">1509455820000</longProp>
|
||||||
|
<longProp name="ThreadGroup.end_time">1509455820000</longProp>
|
||||||
|
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||||
|
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||||
|
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||||
|
</ThreadGroup>
|
||||||
|
<hashTree>
|
||||||
|
<JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC Request" enabled="true">
|
||||||
|
<stringProp name="dataSource">testpool</stringProp>
|
||||||
|
<stringProp name="query">declare @sql nvarchar(4000)
|
||||||
|
set @sql = N'select dbtransact0_.tx_id as tx_id1_22_0_, dbtransact0_.transaction_value as transact2_22_0_ from perfnode1.node_transactions dbtransact0_ where dbtransact0_.tx_id=@P0'
|
||||||
|
exec sp_executesql @sql, N'@P0 nvarchar(4000)', '${__UUID()}'</stringProp>
|
||||||
|
<stringProp name="queryArguments"></stringProp>
|
||||||
|
<stringProp name="queryArgumentsTypes"></stringProp>
|
||||||
|
<stringProp name="queryTimeout"></stringProp>
|
||||||
|
<stringProp name="queryType">Select Statement</stringProp>
|
||||||
|
<stringProp name="resultSetHandler">Store as String</stringProp>
|
||||||
|
<stringProp name="resultVariable"></stringProp>
|
||||||
|
<stringProp name="variableNames"></stringProp>
|
||||||
|
</JDBCSampler>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="GraphVisualizer" testclass="ResultCollector" testname="Graph Results" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
|
||||||
|
<boolProp name="ResultCollector.error_logging">false</boolProp>
|
||||||
|
<objProp>
|
||||||
|
<name>saveConfig</name>
|
||||||
|
<value class="SampleSaveConfiguration">
|
||||||
|
<time>true</time>
|
||||||
|
<latency>true</latency>
|
||||||
|
<timestamp>true</timestamp>
|
||||||
|
<success>true</success>
|
||||||
|
<label>true</label>
|
||||||
|
<code>true</code>
|
||||||
|
<message>true</message>
|
||||||
|
<threadName>true</threadName>
|
||||||
|
<dataType>true</dataType>
|
||||||
|
<encoding>false</encoding>
|
||||||
|
<assertions>true</assertions>
|
||||||
|
<subresults>true</subresults>
|
||||||
|
<responseData>false</responseData>
|
||||||
|
<samplerData>false</samplerData>
|
||||||
|
<xml>false</xml>
|
||||||
|
<fieldNames>true</fieldNames>
|
||||||
|
<responseHeaders>false</responseHeaders>
|
||||||
|
<requestHeaders>false</requestHeaders>
|
||||||
|
<responseDataOnError>false</responseDataOnError>
|
||||||
|
<saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
|
||||||
|
<assertionsResultsToSave>0</assertionsResultsToSave>
|
||||||
|
<bytes>true</bytes>
|
||||||
|
<sentBytes>true</sentBytes>
|
||||||
|
<threadCounts>true</threadCounts>
|
||||||
|
<idleTime>true</idleTime>
|
||||||
|
<connectTime>true</connectTime>
|
||||||
|
</value>
|
||||||
|
</objProp>
|
||||||
|
<stringProp name="filename"></stringProp>
|
||||||
|
</ResultCollector>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
<WorkBench guiclass="WorkBenchGui" testclass="WorkBench" testname="WorkBench" enabled="true">
|
||||||
|
<boolProp name="WorkBench.save">true</boolProp>
|
||||||
|
</WorkBench>
|
||||||
|
<hashTree/>
|
||||||
|
</hashTree>
|
||||||
|
</jmeterTestPlan>
|
@ -34,14 +34,13 @@ class NativeSgxApiTest {
|
|||||||
val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1)
|
val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1)
|
||||||
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
||||||
val MEGA_CORP get() = megaCorp.party
|
val MEGA_CORP get() = megaCorp.party
|
||||||
val MEGA_CORP_PUBKEY get() = megaCorp.publicKey
|
val MEGA_CORP_PUBKEY get() = megaCorp.keyPair.public
|
||||||
val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).publicKey
|
val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).keyPair.public
|
||||||
}
|
}
|
||||||
|
|
||||||
private val identityService = rigorousMock<IdentityServiceInternal>().also {
|
private val ledgerServices = MockServices(emptyList(), rigorousMock<IdentityServiceInternal>().also {
|
||||||
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
|
doReturn(NativeSgxApiTest.MEGA_CORP).whenever(it).partyFromKey(NativeSgxApiTest.MEGA_CORP_PUBKEY)
|
||||||
}
|
}, NativeSgxApiTest.MEGA_CORP.name)
|
||||||
private val ledgerServices = MockServices(emptyList(), identityService, MEGA_CORP.name)
|
|
||||||
|
|
||||||
@Ignore("The SGX code is not part of the standard build yet")
|
@Ignore("The SGX code is not part of the standard build yet")
|
||||||
@Test
|
@Test
|
||||||
|
@ -32,17 +32,16 @@ class EnclaveletTest {
|
|||||||
val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1)
|
val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1)
|
||||||
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB"))
|
||||||
val MEGA_CORP get() = megaCorp.party
|
val MEGA_CORP get() = megaCorp.party
|
||||||
val MEGA_CORP_PUBKEY get() = megaCorp.publicKey
|
val MEGA_CORP_PUBKEY get() = megaCorp.keyPair.public
|
||||||
val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).publicKey
|
val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).keyPair.public
|
||||||
}
|
}
|
||||||
@Rule
|
@Rule
|
||||||
@JvmField
|
@JvmField
|
||||||
val testSerialization = SerializationEnvironmentRule()
|
val testSerialization = SerializationEnvironmentRule()
|
||||||
|
|
||||||
private val identityService = rigorousMock<IdentityServiceInternal>().also {
|
private val ledgerServices = MockServices(emptyList(), rigorousMock<IdentityServiceInternal>().also {
|
||||||
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
|
doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY)
|
||||||
}
|
}, MEGA_CORP.name)
|
||||||
private val ledgerServices = MockServices(emptyList(), identityService, MEGA_CORP.name)
|
|
||||||
|
|
||||||
@Ignore("Pending Gradle bug: https://github.com/gradle/gradle/issues/2657")
|
@Ignore("Pending Gradle bug: https://github.com/gradle/gradle/issues/2657")
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user