Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORDA-2345: Simplified TestCordapp to make it inline with the recent CorDapp versioning changes #4434

Merged
merged 5 commits into from Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -387,7 +387,7 @@ val Class<*>.location: URL get() = protectionDomain.codeSource.location

/** Convenience method to get the package name of a class literal. */
val KClass<*>.packageName: String get() = java.packageName
val Class<*>.packageName: String get() = `package`.name
val Class<*>.packageName: String get() = requireNotNull(`package`?.name) { "$this not defined inside a package" }

inline val Class<*>.isAbstractClass: Boolean get() = Modifier.isAbstract(modifiers)

Expand Down
Expand Up @@ -14,7 +14,6 @@ import net.corda.finance.issuedBy
import net.corda.testing.core.*
import net.corda.testing.internal.matchers.flow.willReturn
import net.corda.testing.internal.matchers.flow.willThrow
import net.corda.testing.node.TestCordapp
import net.corda.testing.node.internal.*
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatIllegalArgumentException
Expand Down Expand Up @@ -77,7 +76,7 @@ class FinalityFlowTests : WithFinality {
@Test
fun `allow use of the old API if the CorDapp target version is 3`() {
// We need Bob to load at least one old CorDapp so that its FinalityHandler is enabled
val bob = createBob(cordapps = listOf(cordappForPackages("com.template").withTargetVersion(3)))
val bob = createBob(cordapps = listOf(cordappWithPackages("com.template").copy(targetPlatformVersion = 3)))
val stx = aliceNode.issuesCashTo(bob)
val resultFuture = CordappResolver.withCordapp(targetPlatformVersion = 3) {
@Suppress("DEPRECATION")
Expand All @@ -87,7 +86,7 @@ class FinalityFlowTests : WithFinality {
assertThat(bob.services.validatedTransactions.getTransaction(stx.id)).isNotNull()
}

private fun createBob(cordapps: List<TestCordapp> = emptyList()): TestStartedNode {
private fun createBob(cordapps: List<TestCordappInternal> = emptyList()): TestStartedNode {
return mockNet.createNode(InternalMockNodeParameters(legalName = BOB_NAME, additionalCordapps = cordapps))
}

Expand Down
12 changes: 9 additions & 3 deletions docs/source/changelog.rst
Expand Up @@ -34,6 +34,15 @@ Unreleased
This allows Corda 4 signed CorDapps using signature constraints to consume existing hash constrained states generated
by unsigned CorDapps in previous versions of Corda.

* You can now load different CorDapps for different nodes in the node-driver and mock-network. This previously wasn't possible with the
``DriverParameters.extraCordappPackagesToScan`` and ``MockNetwork.cordappPackages`` parameters as all the nodes would get the same CorDapps.
See ``TestCordapp``, ``NodeParameters.additionalCordapps`` and ``MockNodeParameters.additionalCordapps``.

* ``DriverParameters.extraCordappPackagesToScan`` and ``MockNetwork.cordappPackages`` have been deprecated as they do not support the new
CorDapp versioning and MANIFEST metadata support that has been added. They create artificial CorDapp jars which do not preserve these
settings and thus may produce incorrect results when testing. It is recommended ``DriverParameters.cordappsForAllNodes`` and
``MockNetworkParameters.cordappsForAllNodes`` be used instead.

* Fixed a problem with IRS demo not being able to simulate future dates as expected (https://github.com/corda/corda/issues/3851).

* Fixed a problem that was preventing `Cash.generateSpend` to be used more than once per transaction (https://github.com/corda/corda/issues/4110).
Expand Down Expand Up @@ -136,9 +145,6 @@ Unreleased
* "app", "rpc", "p2p" and "unknown" are no longer allowed as uploader values when importing attachments. These are used
internally in security sensitive code.

* Introduced ``TestCorDapp`` and utilities to support asymmetric setups for nodes through ``DriverDSL``, ``MockNetwork``
and ``MockServices``.

* Change type of the ``checkpoint_value`` column. Please check the upgrade-notes on how to update your database.

* Removed buggy :serverNameTablePrefix: configuration.
Expand Down
Expand Up @@ -23,6 +23,7 @@
import java.util.List;

import static java.util.Arrays.asList;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static net.corda.finance.Currencies.DOLLARS;
import static net.corda.node.services.Permissions.invokeRpc;
Expand All @@ -32,6 +33,7 @@
import static net.corda.testing.core.TestConstants.ALICE_NAME;
import static net.corda.testing.core.TestConstants.BOB_NAME;
import static net.corda.testing.driver.Driver.driver;
import static net.corda.testing.node.internal.TestCordappsUtilsKt.FINANCE_CORDAPP;
import static org.junit.Assert.assertEquals;

public class JavaIntegrationTestingTutorial {
Expand All @@ -40,7 +42,7 @@ public void aliceBobCashExchangeExample() {
// START 1
driver(new DriverParameters()
.withStartNodesInProcess(true)
.withExtraCordappPackagesToScan(singletonList("net.corda.finance")), dsl -> {
.withCordappsForAllNodes(singleton(FINANCE_CORDAPP)), dsl -> {

User aliceUser = new User("aliceUser", "testPassword1", new HashSet<>(asList(
startFlow(CashIssueAndPaymentFlow.class),
Expand Down
Expand Up @@ -20,6 +20,7 @@ import net.corda.testing.core.*
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.User
import net.corda.testing.node.internal.FINANCE_CORDAPP
import org.junit.Test
import rx.Observable
import java.util.*
Expand All @@ -29,7 +30,7 @@ class KotlinIntegrationTestingTutorial {
@Test
fun `alice bob cash exchange example`() {
// START 1
driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.finance"))) {
driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = listOf(FINANCE_CORDAPP))) {
val aliceUser = User("aliceUser", "testPassword1", permissions = setOf(
startFlow<CashIssueAndPaymentFlow>(),
invokeRpc("vaultTrackBy")
Expand Down
7 changes: 5 additions & 2 deletions docs/source/upgrade-notes.rst
Expand Up @@ -176,8 +176,8 @@ has been adjusted in the same way as ``FinalityFlow`` above, to close problems w
outside of other flow context. Old code will still work, but it is recommended to adjust your call sites so a session is passed into
the ``SwapIdentitiesFlow``.

Step 5. Possibly, adjust unit test code
---------------------------------------
Step 5. Possibly, adjust test code
----------------------------------

``MockNodeParameters`` and functions creating it no longer use a lambda expecting a ``NodeConfiguration`` object.
Use a ``MockNetworkConfigOverrides`` object instead. This is an API change we regret, but unfortunately in Corda 3 we accidentally exposed
Expand All @@ -202,6 +202,9 @@ becomes::
initialIdentity = TestIdentity(CordaX500Name("TestIdentity", "", "GB"))
)

You may need to use the new ``TestCordapp`` API when testing with the node driver or mock network, especially if you decide to stick with the
old ``FinalityFlow`` API. The previous way of pulling in CorDapps into your tests does not honour CorDapp versioning.
shamsasari marked this conversation as resolved.
Show resolved Hide resolved

Step 6. Security: refactor to avoid violating sealed packages
-------------------------------------------------------------

Expand Down
Expand Up @@ -7,7 +7,7 @@ import net.corda.finance.USD
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.cordappForPackages
import net.corda.testing.node.internal.cordappWithPackages
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Test
Expand All @@ -21,7 +21,7 @@ class CashConfigDataFlowTest {
@Test
fun `issuable currencies read in from cordapp config`() {
val node = mockNet.createNode(MockNodeParameters(additionalCordapps = listOf(
cordappForPackages(javaClass.packageName).withConfig(mapOf("issuableCurrencies" to listOf("EUR", "USD")))
cordappWithPackages(javaClass.packageName).copy(config = mapOf("issuableCurrencies" to listOf("EUR", "USD")))
)))
val config = node.startFlow(CashConfigDataFlow()).getOrThrow()
assertThat(config.issuableCurrencies).containsExactly(EUR, USD)
Expand Down
Expand Up @@ -26,8 +26,7 @@ import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.internal.MockCordappConfigProvider
import net.corda.testing.internal.rigorousMock
import net.corda.testing.node.internal.TestCordappDirectories
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.cordappWithPackages
import net.corda.testing.services.MockAttachmentStorage
import org.assertj.core.api.Assertions.assertThat
import org.junit.Assert.assertEquals
Expand Down Expand Up @@ -112,7 +111,6 @@ class AttachmentsClassLoaderStaticContractTests {
}

private fun cordappLoaderForPackages(packages: Collection<String>): CordappLoader {
val dirs = cordappsForPackages(packages).map { TestCordappDirectories.getJarDirectory(it) }
return JarScanningCordappLoader.fromDirectories(dirs)
return JarScanningCordappLoader.fromJarUrls(listOf(cordappWithPackages(*packages.toTypedArray()).jarFile.toUri().toURL()))
}
}
Expand Up @@ -6,6 +6,8 @@ import net.corda.core.contracts.*
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.internal.deleteRecursively
import net.corda.core.internal.div
import net.corda.core.internal.packageName
import net.corda.core.messaging.startFlow
import net.corda.core.transactions.LedgerTransaction
Expand All @@ -23,7 +25,7 @@ import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.NodeParameters
import net.corda.testing.driver.internal.incrementalPortAllocation
import net.corda.testing.node.User
import net.corda.testing.node.internal.cordappForPackages
import net.corda.testing.node.internal.cordappWithPackages
import net.corda.testing.node.internal.internalDriver
import org.junit.Assume.assumeFalse
import org.junit.Test
Expand All @@ -34,9 +36,9 @@ import kotlin.test.assertNotNull

class SignatureConstraintVersioningTests {

private val base = cordappForPackages(MessageState::class.packageName, DummyMessageContract::class.packageName)
private val oldCordapp = base.withVersion("2")
private val newCordapp = base.withVersion("3")
private val base = cordappWithPackages(MessageState::class.packageName, DummyMessageContract::class.packageName).signed()
private val oldCordapp = base.copy(versionId = 2)
private val newCordapp = base.copy(versionId = 3)
private val user = User("mark", "dadada", setOf(startFlow<CreateMessage>(), startFlow<ConsumeMessage>(), invokeRpc("vaultQuery")))
private val message = Message("Hello world!")
private val transformetMessage = Message(message.value + "A")
Expand All @@ -45,20 +47,23 @@ class SignatureConstraintVersioningTests {
fun `can evolve from lower contract class version to higher one`() {
assumeFalse(System.getProperty("os.name").toLowerCase().startsWith("win")) // See NodeStatePersistenceTests.kt.

val stateAndRef: StateAndRef<MessageState>? = internalDriver(inMemoryDB = false,
val stateAndRef: StateAndRef<MessageState>? = internalDriver(
inMemoryDB = false,
startNodesInProcess = isQuasarAgentSpecified(),
networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4), signCordapps = true) {
var nodeName = {
val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp), regenerateCordappsOnStart = true)).getOrThrow()
networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4)
) {
val nodeName = {
val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp))).getOrThrow()
val nodeName = nodeHandle.nodeInfo.singleIdentity().name
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
it.proxy.startFlow(::CreateMessage, message, defaultNotaryIdentity).returnValue.getOrThrow()
}
nodeHandle.stop()
nodeName
}()
var result = {
val nodeHandle = startNode(NodeParameters(providedName = nodeName, rpcUsers = listOf(user), additionalCordapps = listOf(newCordapp), regenerateCordappsOnStart = true)).getOrThrow()
val result = {
(baseDirectory(nodeName) / "cordapps").deleteRecursively()
val nodeHandle = startNode(NodeParameters(providedName = nodeName, rpcUsers = listOf(user), additionalCordapps = listOf(newCordapp))).getOrThrow()
var result: StateAndRef<MessageState>? = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
val page = it.proxy.vaultQuery(MessageState::class.java)
page.states.singleOrNull()
Expand Down Expand Up @@ -87,9 +92,9 @@ class SignatureConstraintVersioningTests {

val stateAndRef: StateAndRef<MessageState>? = internalDriver(inMemoryDB = false,
startNodesInProcess = isQuasarAgentSpecified(),
networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4), signCordapps = true) {
var nodeName = {
val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(newCordapp), regenerateCordappsOnStart = true),
networkParameters = testNetworkParameters(notaries = emptyList(), minimumPlatformVersion = 4)) {
val nodeName = {
val nodeHandle = startNode(NodeParameters(rpcUsers = listOf(user), additionalCordapps = listOf(newCordapp)),
customOverrides = mapOf("h2Settings.address" to "localhost:$port")).getOrThrow()
val nodeName = nodeHandle.nodeInfo.singleIdentity().name
CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
Expand All @@ -98,8 +103,9 @@ class SignatureConstraintVersioningTests {
nodeHandle.stop()
nodeName
}()
var result = {
val nodeHandle = startNode(NodeParameters(providedName = nodeName, rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp), regenerateCordappsOnStart = true),
val result = {
(baseDirectory(nodeName) / "cordapps").deleteRecursively()
val nodeHandle = startNode(NodeParameters(providedName = nodeName, rpcUsers = listOf(user), additionalCordapps = listOf(oldCordapp)),
customOverrides = mapOf("h2Settings.address" to "localhost:$port")).getOrThrow()

//set the attachment with newer version (3) as untrusted one so the node can use only the older attachment with version 2
Expand Down