diff --git a/.idea/compiler.xml b/.idea/compiler.xml index fa9e72cfc4..7ca71b5aa7 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -28,6 +28,9 @@ + + + @@ -83,9 +86,11 @@ - + + + diff --git a/build.gradle b/build.gradle index 5fd2cd863e..ba78f59ae8 100644 --- a/build.gradle +++ b/build.gradle @@ -251,7 +251,7 @@ bintrayConfig { projectUrl = 'https://github.com/corda/corda' gpgSign = true gpgPassphrase = System.getenv('CORDA_BINTRAY_GPG_PASSPHRASE') - publications = ['corda-jfx', 'corda-mock', 'corda-rpc', 'corda-core', 'corda', 'corda-finance', 'corda-node', 'corda-node-api', 'corda-test-common', 'corda-test-utils', 'corda-jackson', 'corda-verifier', 'corda-webserver-impl', 'corda-webserver'] + publications = ['corda-jfx', 'corda-mock', 'corda-rpc', 'corda-core', 'corda', 'corda-finance', 'corda-node', 'corda-node-api', 'corda-test-common', 'corda-test-utils', 'corda-jackson', 'corda-verifier', 'corda-webserver-impl', 'corda-webserver', 'corda-node-driver'] license { name = 'Apache-2.0' url = 'https://www.apache.org/licenses/LICENSE-2.0' @@ -286,7 +286,7 @@ artifactory { password = System.getenv('CORDA_ARTIFACTORY_PASSWORD') } defaults { - publications('corda-jfx', 'corda-mock', 'corda-rpc', 'corda-core', 'corda', 'cordform-common', 'corda-finance', 'corda-node', 'corda-node-api', 'corda-test-common', 'corda-test-utils', 'corda-jackson', 'corda-verifier', 'corda-webserver-impl', 'corda-webserver') + publications('corda-jfx', 'corda-mock', 'corda-rpc', 'corda-core', 'corda', 'cordform-common', 'corda-finance', 'corda-node', 'corda-node-api', 'corda-test-common', 'corda-test-utils', 'corda-jackson', 'corda-verifier', 'corda-webserver-impl', 'corda-webserver', 'corda-node-driver') } } } diff --git a/client/jfx/build.gradle b/client/jfx/build.gradle index 8b8c677e4b..ef9602e810 100644 --- a/client/jfx/build.gradle +++ b/client/jfx/build.gradle @@ -50,6 +50,7 @@ dependencies { // Integration test helpers integrationTestCompile "junit:junit:$junit_version" + integrationTestCompile project(':node-driver') } task integrationTest(type: Test) { diff --git a/client/rpc/build.gradle b/client/rpc/build.gradle index 70ebc5ed57..2b3c020f49 100644 --- a/client/rpc/build.gradle +++ b/client/rpc/build.gradle @@ -67,7 +67,7 @@ dependencies { testCompile "junit:junit:$junit_version" testCompile "org.assertj:assertj-core:${assertj_version}" - testCompile project(':test-utils') + testCompile project(':node-driver') testCompile project(':client:mock') // Smoke tests do NOT have any Node code on the classpath! diff --git a/core/build.gradle b/core/build.gradle index 4594b9233b..655067d680 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -22,7 +22,7 @@ dependencies { // Bring in the MockNode infrastructure for writing protocol unit tests. testCompile project(":node") - testCompile project(":test-utils") + testCompile project(":node-driver") compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index 7b5ee5b8dd..e5e7a5a008 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -32,7 +32,7 @@ compileTestJava.dependsOn tasks.getByPath(':node:capsule:buildCordaJAR') dependencies { cordaCompile project(':core') cordaCompile project(':client:jfx') - cordaCompile project(':test-utils') + cordaCompile project(':node-driver') testCompile project(':verifier') compile "org.graphstream:gs-core:1.3" diff --git a/experimental/build.gradle b/experimental/build.gradle index 2c9257d2d6..c5a39773ee 100644 --- a/experimental/build.gradle +++ b/experimental/build.gradle @@ -29,5 +29,5 @@ dependencies { compile "com.google.guava:guava:$guava_version" testCompile "junit:junit:$junit_version" - testCompile project(':test-utils') + testCompile project(':node-driver') } diff --git a/finance/src/test/java/net/corda/finance/contracts/asset/CashTestsJava.java b/finance/src/test/java/net/corda/finance/contracts/asset/CashTestsJava.java index 9ae136d9dd..fabf51ef34 100644 --- a/finance/src/test/java/net/corda/finance/contracts/asset/CashTestsJava.java +++ b/finance/src/test/java/net/corda/finance/contracts/asset/CashTestsJava.java @@ -9,6 +9,7 @@ import org.junit.Test; import static net.corda.finance.CurrencyUtils.DOLLARS; import static net.corda.finance.CurrencyUtils.issuedBy; import static net.corda.testing.CoreTestUtils.*; +import static net.corda.testing.NodeTestUtils.*; /** * This is an incomplete Java replica of CashTests.kt to show how to use the Java test DSL diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index 050eb95246..f5e436df20 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -30,7 +30,7 @@ dependencies { cordaCompile project(path: ":webserver:webcapsule", configuration: 'runtimeArtifacts') cordaCompile project(':core') cordaCompile project(':webserver') - cordaCompile project(':test-utils') + cordaCompile project(':node-driver') } task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { diff --git a/samples/bank-of-corda-demo/build.gradle b/samples/bank-of-corda-demo/build.gradle index f1485103f6..22bdb29b35 100644 --- a/samples/bank-of-corda-demo/build.gradle +++ b/samples/bank-of-corda-demo/build.gradle @@ -34,7 +34,7 @@ dependencies { cordaCompile project(':client:jfx') cordaCompile project(':client:rpc') cordaCompile project(':webserver') - cordaCompile project(':test-utils') + cordaCompile project(':node-driver') // Javax is required for webapis compile "org.glassfish.jersey.core:jersey-server:${jersey_version}" diff --git a/samples/irs-demo/build.gradle b/samples/irs-demo/build.gradle index e9f572b106..66f894dd1a 100644 --- a/samples/irs-demo/build.gradle +++ b/samples/irs-demo/build.gradle @@ -43,7 +43,7 @@ dependencies { // Specify your cordapp's dependencies below, including dependent cordapps compile "com.squareup.okhttp3:okhttp:$okhttp_version" - testCompile project(':test-utils') + testCompile project(':node-driver') testCompile "junit:junit:$junit_version" testCompile "org.assertj:assertj-core:${assertj_version}" } diff --git a/samples/network-visualiser/build.gradle b/samples/network-visualiser/build.gradle index d925345afe..d472b1e5b3 100644 --- a/samples/network-visualiser/build.gradle +++ b/samples/network-visualiser/build.gradle @@ -7,7 +7,7 @@ apply plugin: 'us.kirchmeier.capsule' dependencies { compile project(':samples:irs-demo') - compile project(':test-utils') + compile project(':node-driver') compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" testCompile "junit:junit:$junit_version" diff --git a/samples/notary-demo/build.gradle b/samples/notary-demo/build.gradle index d6b9266937..b2d3f3e341 100644 --- a/samples/notary-demo/build.gradle +++ b/samples/notary-demo/build.gradle @@ -23,8 +23,7 @@ dependencies { cordaCompile project(':core') cordaCompile project(':client:jfx') cordaCompile project(':client:rpc') - cordaCompile project(':test-utils') - cordaCompile project(':cordform-common') + cordaCompile project(':node-driver') } idea { diff --git a/samples/simm-valuation-demo/build.gradle b/samples/simm-valuation-demo/build.gradle index 7c39385cb5..7b4a941edc 100644 --- a/samples/simm-valuation-demo/build.gradle +++ b/samples/simm-valuation-demo/build.gradle @@ -56,7 +56,7 @@ dependencies { compile "com.opengamma.strata:strata-math:${strata_version}" // Test dependencies - testCompile project(':test-utils') + testCompile project(':node-driver') testCompile "junit:junit:$junit_version" testCompile "org.assertj:assertj-core:${assertj_version}" } diff --git a/settings.gradle b/settings.gradle index e61b68e83e..8c4324969c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -21,6 +21,8 @@ include 'verifier' include 'test-common' include 'test-utils' include 'smoke-test-utils' +include 'node-driver' +project(':node-driver').projectDir = new File("$settingsDir/testing/node-driver") include 'tools:explorer' include 'tools:explorer:capsule' include 'tools:demobench' diff --git a/test-utils/build.gradle b/test-utils/build.gradle index e67533db44..350a94d766 100644 --- a/test-utils/build.gradle +++ b/test-utils/build.gradle @@ -10,22 +10,6 @@ description 'Testing utilities for Corda' configurations { // we don't want isolated.jar in classPath, since we want to test jar being dynamically loaded as an attachment runtime.exclude module: 'isolated' - - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime -} - -sourceSets { - integrationTest { - kotlin { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file('src/integration-test/kotlin') - } - resources { - srcDir file('src/integration-test/resources') - } - } } dependencies { @@ -49,15 +33,6 @@ dependencies { // OkHTTP: Simple HTTP library. compile "com.squareup.okhttp3:okhttp:$okhttp_version" - - // Integration test helpers - integrationTestCompile "org.assertj:assertj-core:${assertj_version}" - integrationTestCompile "junit:junit:$junit_version" -} - -task integrationTest(type: Test) { - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath } jar { diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 9ebc941fad..87eb8dd992 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -3,34 +3,26 @@ package net.corda.testing -import com.nhaarman.mockito_kotlin.spy -import com.nhaarman.mockito_kotlin.whenever import net.corda.core.contracts.StateRef import net.corda.core.crypto.* import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate -import net.corda.core.node.ServiceHub import net.corda.core.node.services.IdentityService -import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.* +import net.corda.core.utilities.NetworkHostAndPort +import net.corda.core.utilities.OpaqueBytes +import net.corda.core.utilities.loggerFor import net.corda.finance.contracts.asset.DUMMY_CASH_ISSUER -import net.corda.node.services.config.NodeConfiguration -import net.corda.node.services.config.VerifierType import net.corda.node.services.config.configureDevKeyAndTrustStores import net.corda.node.services.identity.InMemoryIdentityService import net.corda.node.utilities.CertificateType import net.corda.node.utilities.X509Utilities import net.corda.nodeapi.config.SSLConfiguration import net.corda.nodeapi.internal.serialization.AMQP_ENABLED -import net.corda.testing.node.MockServices -import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties -import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties import org.bouncycastle.asn1.x500.X500Name import org.bouncycastle.asn1.x500.X500NameBuilder import org.bouncycastle.asn1.x500.style.BCStyle -import java.net.URL import java.nio.file.Files -import java.nio.file.Path import java.security.KeyPair import java.security.PublicKey import java.security.cert.CertificateFactory @@ -126,62 +118,6 @@ fun getFreeLocalPorts(hostName: String, numberToAlloc: Int): List.() -> Unit -): LedgerDSL { - if (initialiseSerialization) initialiseTestSerialization() - try { - val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(services)) - dsl(ledgerDsl) - return ledgerDsl - } finally { - if (initialiseSerialization) resetTestSerialization() - } -} - -/** - * Creates a ledger with a single transaction, built by the passed in dsl. - * - * @see LedgerDSLInterpreter._transaction - */ -@JvmOverloads fun transaction( - transactionLabel: String? = null, - transactionBuilder: TransactionBuilder = TransactionBuilder(notary = DUMMY_NOTARY), - initialiseSerialization: Boolean = true, - dsl: TransactionDSL.() -> EnforceVerifyOrFail -) = ledger(initialiseSerialization = initialiseSerialization) { - dsl(TransactionDSL(TestTransactionDSLInterpreter(this.interpreter, transactionBuilder))) -} - -fun testNodeConfiguration( - baseDirectory: Path, - myLegalName: X500Name): NodeConfiguration { - abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters. - val nc = spy() - whenever(nc.baseDirectory).thenReturn(baseDirectory) - whenever(nc.myLegalName).thenReturn(myLegalName) - whenever(nc.minimumPlatformVersion).thenReturn(1) - whenever(nc.keyStorePassword).thenReturn("cordacadevpass") - whenever(nc.trustStorePassword).thenReturn("trustpass") - whenever(nc.rpcUsers).thenReturn(emptyList()) - whenever(nc.dataSourceProperties).thenReturn(makeTestDataSourceProperties(myLegalName.commonName)) - whenever(nc.database).thenReturn(makeTestDatabaseProperties()) - whenever(nc.emailAddress).thenReturn("") - whenever(nc.exportJMXto).thenReturn("") - whenever(nc.devMode).thenReturn(true) - whenever(nc.certificateSigningService).thenReturn(URL("http://localhost")) - whenever(nc.certificateChainCheckPolicies).thenReturn(emptyList()) - whenever(nc.verifierType).thenReturn(VerifierType.InMemory) - whenever(nc.messageRedeliveryDelaySeconds).thenReturn(5) - return nc -} - @JvmOverloads fun configureTestSSL(legalName: X500Name = MEGA_CORP.name): SSLConfiguration = object : SSLConfiguration { override val certificatesDirectory = Files.createTempDirectory("certs") diff --git a/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt b/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt index 3a8669e7cb..9cfca24f74 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/TestConstants.kt @@ -9,13 +9,7 @@ import net.corda.core.crypto.entropyToKeyPair import net.corda.core.crypto.generateKeyPair import net.corda.core.identity.Party import net.corda.core.identity.PartyAndCertificate -import net.corda.core.internal.concurrent.transpose -import net.corda.core.messaging.CordaRPCOps -import net.corda.core.node.services.ServiceInfo -import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.utilities.X509Utilities -import net.corda.nodeapi.User -import net.corda.testing.driver.DriverDSLExposedInterface import org.bouncycastle.asn1.x500.X500Name import java.math.BigInteger import java.security.KeyPair @@ -81,51 +75,3 @@ object DummyCommandData : TypeOnlyCommandData() val DUMMY_IDENTITY_1: PartyAndCertificate get() = getTestPartyAndCertificate(DUMMY_PARTY) val DUMMY_PARTY: Party get() = Party(X500Name("CN=Dummy,O=Dummy,L=Madrid,C=ES"), DUMMY_KEY_1.public) - -// -// Extensions to the Driver DSL to auto-manufacture nodes by name. -// - -/** - * A simple wrapper for objects provided by the integration test driver DSL. The fields are lazy so - * node construction won't start until you access the members. You can get one of these from the - * [alice], [bob] and [aliceBobAndNotary] functions. - */ -class PredefinedTestNode internal constructor(party: Party, driver: DriverDSLExposedInterface, services: Set) { - val rpcUsers = listOf(User("admin", "admin", setOf("ALL"))) // TODO: Randomize? - val nodeFuture by lazy { driver.startNode(providedName = party.name, rpcUsers = rpcUsers, advertisedServices = services) } - val node by lazy { nodeFuture.get()!! } - val rpc by lazy { node.rpcClientToNode() } - - fun useRPC(block: (CordaRPCOps) -> R) = rpc.use(rpcUsers[0].username, rpcUsers[0].password) { block(it.proxy) } -} - -// TODO: Probably we should inject the above keys through the driver to make the nodes use it, rather than have the warnings below. - -/** - * Returns a plain, entirely stock node pre-configured with the [ALICE] identity. Note that a random key will be generated - * for it: you won't have [ALICE_KEY]. - */ -fun DriverDSLExposedInterface.alice(): PredefinedTestNode = PredefinedTestNode(ALICE, this, emptySet()) -/** - * Returns a plain, entirely stock node pre-configured with the [BOB] identity. Note that a random key will be generated - * for it: you won't have [BOB_KEY]. - */ -fun DriverDSLExposedInterface.bob(): PredefinedTestNode = PredefinedTestNode(BOB, this, emptySet()) -/** - * Returns a plain single node notary pre-configured with the [DUMMY_NOTARY] identity. Note that a random key will be generated - * for it: you won't have [DUMMY_NOTARY_KEY]. - */ -fun DriverDSLExposedInterface.notary(): PredefinedTestNode = PredefinedTestNode(DUMMY_NOTARY, this, setOf(ServiceInfo(ValidatingNotaryService.type))) - -/** - * Returns plain, entirely stock nodes pre-configured with the [ALICE], [BOB] and [DUMMY_NOTARY] X.500 names in that - * order. They have been started up in parallel and are now ready to use. - */ -fun DriverDSLExposedInterface.aliceBobAndNotary(): List { - val alice = alice() - val bob = bob() - val notary = notary() - listOf(alice.nodeFuture, bob.nodeFuture, notary.nodeFuture).transpose().get() - return listOf(alice, bob, notary) -} \ No newline at end of file diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockAttachmentStorage.kt b/test-utils/src/main/kotlin/net/corda/testing/node/MockAttachmentStorage.kt new file mode 100644 index 0000000000..618060be0e --- /dev/null +++ b/test-utils/src/main/kotlin/net/corda/testing/node/MockAttachmentStorage.kt @@ -0,0 +1,41 @@ +package net.corda.testing.node + +import net.corda.core.contracts.Attachment +import net.corda.core.crypto.SecureHash +import net.corda.core.crypto.sha256 +import net.corda.core.internal.AbstractAttachment +import net.corda.core.node.services.AttachmentStorage +import net.corda.core.serialization.SingletonSerializeAsToken +import java.io.ByteArrayOutputStream +import java.io.File +import java.io.InputStream +import java.util.HashMap +import java.util.jar.JarInputStream + +class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { + val files = HashMap() + + override fun openAttachment(id: SecureHash): Attachment? { + val f = files[id] ?: return null + return object : AbstractAttachment({ f }) { + override val id = id + } + } + + override fun importAttachment(jar: InputStream): SecureHash { + // JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here. + require(jar !is JarInputStream) + + val bytes = run { + val s = ByteArrayOutputStream() + jar.copyTo(s) + s.close() + s.toByteArray() + } + val sha256 = bytes.sha256() + if (files.containsKey(sha256)) + throw FileAlreadyExistsException(File("!! MOCK FILE NAME")) + files[sha256] = bytes + return sha256 + } +} diff --git a/testing/node-driver/build.gradle b/testing/node-driver/build.gradle new file mode 100644 index 0000000000..2196330ae4 --- /dev/null +++ b/testing/node-driver/build.gradle @@ -0,0 +1,49 @@ +apply plugin: 'kotlin' +apply plugin: 'kotlin-jpa' +apply plugin: 'net.corda.plugins.quasar-utils' +apply plugin: 'net.corda.plugins.publish-utils' +apply plugin: 'com.jfrog.artifactory' + +//noinspection GroovyAssignabilityCheck +configurations { + // we don't want isolated.jar in classPath, since we want to test jar being dynamically loaded as an attachment + runtime.exclude module: 'isolated' + + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime +} + +sourceSets { + integrationTest { + kotlin { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/kotlin') + } + resources { + srcDir file('src/integration-test/resources') + } + } +} + +dependencies { + compile project(':test-utils') + compile project(':cordform-common') + + // Integration test helpers + integrationTestCompile "org.assertj:assertj-core:${assertj_version}" + integrationTestCompile "junit:junit:$junit_version" +} + +task integrationTest(type: Test) { + testClassesDirs = sourceSets.integrationTest.output.classesDirs + classpath = sourceSets.integrationTest.runtimeClasspath +} + +jar { + baseName 'corda-node-driver' +} + +publish { + name jar.baseName +} diff --git a/test-utils/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt similarity index 100% rename from test-utils/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt rename to testing/node-driver/src/integration-test/kotlin/net/corda/testing/FlowStackSnapshotTest.kt diff --git a/test-utils/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt similarity index 100% rename from test-utils/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt rename to testing/node-driver/src/integration-test/kotlin/net/corda/testing/driver/DriverTests.kt diff --git a/samples/notary-demo/src/main/kotlin/net/corda/demorun/DemoRunner.kt b/testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt similarity index 100% rename from samples/notary-demo/src/main/kotlin/net/corda/demorun/DemoRunner.kt rename to testing/node-driver/src/main/kotlin/net/corda/demorun/DemoRunner.kt diff --git a/samples/notary-demo/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt similarity index 100% rename from samples/notary-demo/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt rename to testing/node-driver/src/main/kotlin/net/corda/demorun/util/DemoUtils.kt diff --git a/test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt b/testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt rename to testing/node-driver/src/main/kotlin/net/corda/node/testing/MockServiceHubInternal.kt diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/DriverConstants.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/DriverConstants.kt new file mode 100644 index 0000000000..709f48da8a --- /dev/null +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/DriverConstants.kt @@ -0,0 +1,59 @@ +@file:JvmName("DriverConstants") + +package net.corda.testing + +import net.corda.core.identity.Party +import net.corda.core.internal.concurrent.transpose +import net.corda.core.messaging.CordaRPCOps +import net.corda.core.node.services.ServiceInfo +import net.corda.node.services.transactions.ValidatingNotaryService +import net.corda.nodeapi.User +import net.corda.testing.driver.DriverDSLExposedInterface + +// +// Extensions to the Driver DSL to auto-manufacture nodes by name. +// + +/** + * A simple wrapper for objects provided by the integration test driver DSL. The fields are lazy so + * node construction won't start until you access the members. You can get one of these from the + * [alice], [bob] and [aliceBobAndNotary] functions. + */ +class PredefinedTestNode internal constructor(party: Party, driver: DriverDSLExposedInterface, services: Set) { + val rpcUsers = listOf(User("admin", "admin", setOf("ALL"))) // TODO: Randomize? + val nodeFuture by lazy { driver.startNode(providedName = party.name, rpcUsers = rpcUsers, advertisedServices = services) } + val node by lazy { nodeFuture.get()!! } + val rpc by lazy { node.rpcClientToNode() } + + fun useRPC(block: (CordaRPCOps) -> R) = rpc.use(rpcUsers[0].username, rpcUsers[0].password) { block(it.proxy) } +} + +// TODO: Probably we should inject the above keys through the driver to make the nodes use it, rather than have the warnings below. + +/** + * Returns a plain, entirely stock node pre-configured with the [ALICE] identity. Note that a random key will be generated + * for it: you won't have [ALICE_KEY]. + */ +fun DriverDSLExposedInterface.alice(): PredefinedTestNode = PredefinedTestNode(ALICE, this, emptySet()) +/** + * Returns a plain, entirely stock node pre-configured with the [BOB] identity. Note that a random key will be generated + * for it: you won't have [BOB_KEY]. + */ +fun DriverDSLExposedInterface.bob(): PredefinedTestNode = PredefinedTestNode(BOB, this, emptySet()) +/** + * Returns a plain single node notary pre-configured with the [DUMMY_NOTARY] identity. Note that a random key will be generated + * for it: you won't have [DUMMY_NOTARY_KEY]. + */ +fun DriverDSLExposedInterface.notary(): PredefinedTestNode = PredefinedTestNode(DUMMY_NOTARY, this, setOf(ServiceInfo(ValidatingNotaryService.type))) + +/** + * Returns plain, entirely stock nodes pre-configured with the [ALICE], [BOB] and [DUMMY_NOTARY] X.500 names in that + * order. They have been started up in parallel and are now ready to use. + */ +fun DriverDSLExposedInterface.aliceBobAndNotary(): List { + val alice = alice() + val bob = bob() + val notary = notary() + listOf(alice.nodeFuture, bob.nodeFuture, notary.nodeFuture).transpose().get() + return listOf(alice, bob, notary) +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt new file mode 100644 index 0000000000..3d917e4bde --- /dev/null +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/NodeTestUtils.kt @@ -0,0 +1,73 @@ +@file:JvmName("NodeTestUtils") + +package net.corda.testing + +import com.nhaarman.mockito_kotlin.spy +import com.nhaarman.mockito_kotlin.whenever +import net.corda.core.node.ServiceHub +import net.corda.core.transactions.TransactionBuilder +import net.corda.core.utilities.commonName +import net.corda.node.services.config.NodeConfiguration +import net.corda.node.services.config.VerifierType +import net.corda.testing.node.MockServices +import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties +import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties +import org.bouncycastle.asn1.x500.X500Name +import java.net.URL +import java.nio.file.Path + +/** + * Creates and tests a ledger built by the passed in dsl. The provided services can be customised, otherwise a default + * of a freshly built [MockServices] is used. + */ +@JvmOverloads fun ledger( + services: ServiceHub = MockServices(), + initialiseSerialization: Boolean = true, + dsl: LedgerDSL.() -> Unit +): LedgerDSL { + if (initialiseSerialization) initialiseTestSerialization() + try { + val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(services)) + dsl(ledgerDsl) + return ledgerDsl + } finally { + if (initialiseSerialization) resetTestSerialization() + } +} + +/** + * Creates a ledger with a single transaction, built by the passed in dsl. + * + * @see LedgerDSLInterpreter._transaction + */ +@JvmOverloads fun transaction( + transactionLabel: String? = null, + transactionBuilder: TransactionBuilder = TransactionBuilder(notary = DUMMY_NOTARY), + initialiseSerialization: Boolean = true, + dsl: TransactionDSL.() -> EnforceVerifyOrFail +) = ledger(initialiseSerialization = initialiseSerialization) { + dsl(TransactionDSL(TestTransactionDSLInterpreter(this.interpreter, transactionBuilder))) +} + +fun testNodeConfiguration( + baseDirectory: Path, + myLegalName: X500Name): NodeConfiguration { + abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters. + val nc = spy() + whenever(nc.baseDirectory).thenReturn(baseDirectory) + whenever(nc.myLegalName).thenReturn(myLegalName) + whenever(nc.minimumPlatformVersion).thenReturn(1) + whenever(nc.keyStorePassword).thenReturn("cordacadevpass") + whenever(nc.trustStorePassword).thenReturn("trustpass") + whenever(nc.rpcUsers).thenReturn(emptyList()) + whenever(nc.dataSourceProperties).thenReturn(makeTestDataSourceProperties(myLegalName.commonName)) + whenever(nc.database).thenReturn(makeTestDatabaseProperties()) + whenever(nc.emailAddress).thenReturn("") + whenever(nc.exportJMXto).thenReturn("") + whenever(nc.devMode).thenReturn(true) + whenever(nc.certificateSigningService).thenReturn(URL("http://localhost")) + whenever(nc.certificateChainCheckPolicies).thenReturn(emptyList()) + whenever(nc.verifierType).thenReturn(VerifierType.InMemory) + whenever(nc.messageRedeliveryDelaySeconds).thenReturn(5) + return nc +} diff --git a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/RPCDriver.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/driver/Driver.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/driver/NetworkMapStartStrategy.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/driver/ProcessUtilities.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/ProcessUtilities.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/driver/ProcessUtilities.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/driver/ProcessUtilities.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/DriverBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/DriverBasedTest.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/DriverBasedTest.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/DriverBasedTest.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/InMemoryMessagingNetwork.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetworkMapCache.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/MockNode.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNode.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt similarity index 91% rename from test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt index 83394c5180..ca9f7e5632 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/node/MockServices.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockServices.kt @@ -1,7 +1,5 @@ package net.corda.testing.node -import net.corda.core.internal.AbstractAttachment -import net.corda.core.contracts.Attachment import net.corda.core.crypto.* import net.corda.core.flows.StateMachineRunId import net.corda.core.identity.PartyAndCertificate @@ -37,16 +35,12 @@ import net.corda.testing.schemas.DummyLinearStateSchemaV1 import org.bouncycastle.operator.ContentSigner import rx.Observable import rx.subjects.PublishSubject -import java.io.ByteArrayOutputStream -import java.io.File -import java.io.InputStream import java.security.KeyPair import java.security.PrivateKey import java.security.PublicKey import java.sql.Connection import java.time.Clock import java.util.* -import java.util.jar.JarInputStream // TODO: We need a single, rationalised unit testing environment that is usable for everything. Fix this! // That means it probably shouldn't be in the 'core' module, which lacks enough code to create a realistic test env. @@ -217,34 +211,6 @@ class MockKeyManagementService(val identityService: IdentityService, } } -class MockAttachmentStorage : AttachmentStorage, SingletonSerializeAsToken() { - val files = HashMap() - - override fun openAttachment(id: SecureHash): Attachment? { - val f = files[id] ?: return null - return object : AbstractAttachment({ f }) { - override val id = id - } - } - - override fun importAttachment(jar: InputStream): SecureHash { - // JIS makes read()/readBytes() return bytes of the current file, but we want to hash the entire container here. - require(jar !is JarInputStream) - - val bytes = run { - val s = ByteArrayOutputStream() - jar.copyTo(s) - s.close() - s.toByteArray() - } - val sha256 = bytes.sha256() - if (files.containsKey(sha256)) - throw FileAlreadyExistsException(File("!! MOCK FILE NAME")) - files[sha256] = bytes - return sha256 - } -} - class MockStateMachineRecordedTransactionMappingStorage( val storage: StateMachineRecordedTransactionMappingStorage = InMemoryStateMachineRecordedTransactionMappingStorage() ) : StateMachineRecordedTransactionMappingStorage by storage diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/NodeBasedTest.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/SimpleNode.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/SimpleNode.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/node/TestClock.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestClock.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/node/TestClock.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/node/TestClock.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/performance/Injectors.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/performance/Injectors.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/performance/Injectors.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/performance/Injectors.kt diff --git a/test-utils/src/main/kotlin/net/corda/testing/performance/Reporter.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/performance/Reporter.kt similarity index 100% rename from test-utils/src/main/kotlin/net/corda/testing/performance/Reporter.kt rename to testing/node-driver/src/main/kotlin/net/corda/testing/performance/Reporter.kt diff --git a/tools/explorer/build.gradle b/tools/explorer/build.gradle index 9e05041c1f..3ffc1e543c 100644 --- a/tools/explorer/build.gradle +++ b/tools/explorer/build.gradle @@ -27,7 +27,7 @@ dependencies { compile project(':core') compile project(':client:jfx') compile project(':client:mock') - compile project(':test-utils') + compile project(':node-driver') compile project(':finance') // Capsule is a library for building independently executable fat JARs. diff --git a/tools/loadtest/build.gradle b/tools/loadtest/build.gradle index 68a5a50774..af7012b2e6 100644 --- a/tools/loadtest/build.gradle +++ b/tools/loadtest/build.gradle @@ -6,7 +6,7 @@ mainClassName = 'net.corda.loadtest.MainKt' dependencies { compile project(':client:mock') compile project(':client:rpc') - compile project(':test-utils') + compile project(':node-driver') // https://mvnrepository.com/artifact/com.jcraft/jsch compile group: 'com.jcraft', name: 'jsch', version: '0.1.54' diff --git a/verifier/build.gradle b/verifier/build.gradle index 2e61f06ce2..33e4869dfd 100644 --- a/verifier/build.gradle +++ b/verifier/build.gradle @@ -39,7 +39,7 @@ dependencies { compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" compile "org.apache.logging.log4j:log4j-core:${log4j_version}" - integrationTestCompile project(":test-utils") + integrationTestCompile project(":node-driver") integrationTestCompile project(":client:mock") // Integration test helpers diff --git a/webserver/build.gradle b/webserver/build.gradle index a4f729f54a..15fa109983 100644 --- a/webserver/build.gradle +++ b/webserver/build.gradle @@ -57,7 +57,7 @@ dependencies { // For rendering the index page. compile "org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.3" - testCompile project(':test-utils') + integrationTestCompile project(':node-driver') testCompile "junit:junit:$junit_version" }