mirror of
https://github.com/corda/corda.git
synced 2025-06-13 12:48:18 +00:00
Merge commit 'e879de7' into chrisr3-os-merge
This commit is contained in:
@ -34,6 +34,11 @@ sourceSets {
|
||||
runtimeClasspath += main.output + test.output
|
||||
srcDir file('src/integration-test/kotlin')
|
||||
}
|
||||
java {
|
||||
compileClasspath += main.output + test.output
|
||||
runtimeClasspath += main.output + test.output
|
||||
srcDir file('src/integration-test/java')
|
||||
}
|
||||
resources {
|
||||
srcDir file('../../testing/test-utils/src/main/resources')
|
||||
}
|
||||
|
@ -0,0 +1,124 @@
|
||||
package net.corda.docs;
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient;
|
||||
import net.corda.core.concurrent.CordaFuture;
|
||||
import net.corda.core.contracts.Amount;
|
||||
import net.corda.core.contracts.Issued;
|
||||
import net.corda.core.contracts.Structures;
|
||||
import net.corda.core.messaging.CordaRPCOps;
|
||||
import net.corda.core.node.services.Vault;
|
||||
import net.corda.core.utilities.OpaqueBytes;
|
||||
import net.corda.finance.contracts.asset.Cash;
|
||||
import net.corda.finance.flows.CashIssueAndPaymentFlow;
|
||||
import net.corda.finance.flows.CashPaymentFlow;
|
||||
import net.corda.testing.driver.DriverParameters;
|
||||
import net.corda.testing.driver.NodeHandle;
|
||||
import net.corda.testing.driver.NodeParameters;
|
||||
import net.corda.testing.node.User;
|
||||
import org.junit.Test;
|
||||
import rx.Observable;
|
||||
|
||||
import java.util.Currency;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static net.corda.finance.Currencies.DOLLARS;
|
||||
import static net.corda.node.services.Permissions.invokeRpc;
|
||||
import static net.corda.node.services.Permissions.startFlow;
|
||||
import static net.corda.testing.core.ExpectKt.expect;
|
||||
import static net.corda.testing.core.ExpectKt.expectEvents;
|
||||
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 org.junit.Assert.assertEquals;
|
||||
|
||||
public class JavaIntegrationTestingTutorial {
|
||||
@Test
|
||||
public void aliceBobCashExchangeExample() {
|
||||
// START 1
|
||||
driver(new DriverParameters()
|
||||
.withStartNodesInProcess(true)
|
||||
.withExtraCordappPackagesToScan(singletonList("net.corda.finance.contracts.asset")), dsl -> {
|
||||
|
||||
User aliceUser = new User("aliceUser", "testPassword1", new HashSet<>(asList(
|
||||
startFlow(CashIssueAndPaymentFlow.class),
|
||||
invokeRpc("vaultTrack")
|
||||
)));
|
||||
|
||||
User bobUser = new User("bobUser", "testPassword2", new HashSet<>(asList(
|
||||
startFlow(CashPaymentFlow.class),
|
||||
invokeRpc("vaultTrack")
|
||||
)));
|
||||
|
||||
try {
|
||||
List<CordaFuture<NodeHandle>> nodeHandleFutures = asList(
|
||||
dsl.startNode(new NodeParameters().withProvidedName(ALICE_NAME).withRpcUsers(singletonList(aliceUser))),
|
||||
dsl.startNode(new NodeParameters().withProvidedName(BOB_NAME).withRpcUsers(singletonList(bobUser)))
|
||||
);
|
||||
|
||||
NodeHandle alice = nodeHandleFutures.get(0).get();
|
||||
NodeHandle bob = nodeHandleFutures.get(1).get();
|
||||
// END 1
|
||||
|
||||
// START 2
|
||||
CordaRPCClient aliceClient = new CordaRPCClient(alice.getRpcAddress());
|
||||
CordaRPCOps aliceProxy = aliceClient.start("aliceUser", "testPassword1").getProxy();
|
||||
|
||||
CordaRPCClient bobClient = new CordaRPCClient(bob.getRpcAddress());
|
||||
CordaRPCOps bobProxy = bobClient.start("bobUser", "testPassword2").getProxy();
|
||||
// END 2
|
||||
|
||||
// START 3
|
||||
Observable<Vault.Update<Cash.State>> bobVaultUpdates = bobProxy.vaultTrack(Cash.State.class).getUpdates();
|
||||
Observable<Vault.Update<Cash.State>> aliceVaultUpdates = aliceProxy.vaultTrack(Cash.State.class).getUpdates();
|
||||
// END 3
|
||||
|
||||
// START 4
|
||||
OpaqueBytes issueRef = OpaqueBytes.of((byte)0);
|
||||
aliceProxy.startFlowDynamic(
|
||||
CashIssueAndPaymentFlow.class,
|
||||
DOLLARS(1000),
|
||||
issueRef,
|
||||
bob.getNodeInfo().getLegalIdentities().get(0),
|
||||
true,
|
||||
dsl.getDefaultNotaryIdentity()
|
||||
).getReturnValue().get();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Vault.Update<Cash.State>> cashVaultUpdateClass = (Class<Vault.Update<Cash.State>>)(Class<?>)Vault.Update.class;
|
||||
|
||||
expectEvents(bobVaultUpdates, true, () ->
|
||||
expect(cashVaultUpdateClass, update -> true, update -> {
|
||||
System.out.println("Bob got vault update of " + update);
|
||||
Amount<Issued<Currency>> amount = update.getProduced().iterator().next().getState().getData().getAmount();
|
||||
assertEquals(DOLLARS(1000), Structures.withoutIssuer(amount));
|
||||
return null;
|
||||
})
|
||||
);
|
||||
// END 4
|
||||
|
||||
// START 5
|
||||
bobProxy.startFlowDynamic(
|
||||
CashPaymentFlow.class,
|
||||
DOLLARS(1000),
|
||||
alice.getNodeInfo().getLegalIdentities().get(0)
|
||||
).getReturnValue().get();
|
||||
|
||||
expectEvents(aliceVaultUpdates, true, () ->
|
||||
expect(cashVaultUpdateClass, update -> true, update -> {
|
||||
System.out.println("Alice got vault update of " + update);
|
||||
Amount<Issued<Currency>> amount = update.getProduced().iterator().next().getState().getData().getAmount();
|
||||
assertEquals(DOLLARS(1000), Structures.withoutIssuer(amount));
|
||||
return null;
|
||||
})
|
||||
);
|
||||
// END 5
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Exception thrown in driver DSL", e);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package net.corda.docs.java;
|
||||
|
||||
import kotlin.Unit;
|
||||
import net.corda.client.rpc.CordaRPCClient;
|
||||
import net.corda.core.messaging.CordaRPCOps;
|
||||
import net.corda.core.utilities.KotlinUtilsKt;
|
||||
import net.corda.docs.java.tutorial.flowstatemachines.ExampleSummingFlow;
|
||||
import net.corda.node.services.Permissions;
|
||||
import net.corda.testing.driver.*;
|
||||
import net.corda.testing.node.User;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import static net.corda.testing.core.TestConstants.ALICE_NAME;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public final class TutorialFlowAsyncOperationTest {
|
||||
// DOCSTART summingWorks
|
||||
@Test
|
||||
public final void summingWorks() {
|
||||
Driver.driver(new DriverParameters(), (DriverDSL dsl) -> {
|
||||
User aliceUser = new User("aliceUser", "testPassword1",
|
||||
new HashSet<>(Collections.singletonList(Permissions.all()))
|
||||
);
|
||||
Future<NodeHandle> aliceFuture = dsl.startNode(new NodeParameters()
|
||||
.withProvidedName(ALICE_NAME)
|
||||
.withRpcUsers(Collections.singletonList(aliceUser))
|
||||
);
|
||||
NodeHandle alice = KotlinUtilsKt.getOrThrow(aliceFuture, null);
|
||||
CordaRPCClient aliceClient = new CordaRPCClient(alice.getRpcAddress());
|
||||
CordaRPCOps aliceProxy = aliceClient.start("aliceUser", "testPassword1").getProxy();
|
||||
Future<Integer> answerFuture = aliceProxy.startFlowDynamic(ExampleSummingFlow.class).getReturnValue();
|
||||
int answer = KotlinUtilsKt.getOrThrow(answerFuture, null);
|
||||
assertEquals(3, answer);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
// DOCEND summingWorks
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package net.corda.docs
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.Issued
|
||||
import net.corda.core.contracts.withoutIssuer
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.messaging.vaultTrackBy
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.finance.DOLLARS
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.finance.flows.CashIssueAndPaymentFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.node.services.Permissions.Companion.invokeRpc
|
||||
import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.User
|
||||
import org.junit.Test
|
||||
import rx.Observable
|
||||
import java.util.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class KotlinIntegrationTestingTutorial {
|
||||
@Test
|
||||
fun `alice bob cash exchange example`() {
|
||||
// START 1
|
||||
driver(DriverParameters(
|
||||
startNodesInProcess = true,
|
||||
extraCordappPackagesToScan = listOf("net.corda.finance.contracts.asset")
|
||||
)) {
|
||||
val aliceUser = User("aliceUser", "testPassword1", permissions = setOf(
|
||||
startFlow<CashIssueAndPaymentFlow>(),
|
||||
invokeRpc("vaultTrackBy")
|
||||
))
|
||||
|
||||
val bobUser = User("bobUser", "testPassword2", permissions = setOf(
|
||||
startFlow<CashPaymentFlow>(),
|
||||
invokeRpc("vaultTrackBy")
|
||||
))
|
||||
|
||||
val (alice, bob) = listOf(
|
||||
startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser)),
|
||||
startNode(providedName = BOB_NAME, rpcUsers = listOf(bobUser))
|
||||
).map { it.getOrThrow() }
|
||||
// END 1
|
||||
|
||||
// START 2
|
||||
val aliceClient = CordaRPCClient(alice.rpcAddress)
|
||||
val aliceProxy: CordaRPCOps = aliceClient.start("aliceUser", "testPassword1").proxy
|
||||
|
||||
val bobClient = CordaRPCClient(bob.rpcAddress)
|
||||
val bobProxy: CordaRPCOps = bobClient.start("bobUser", "testPassword2").proxy
|
||||
// END 2
|
||||
|
||||
// START 3
|
||||
val bobVaultUpdates: Observable<Vault.Update<Cash.State>> = bobProxy.vaultTrackBy<Cash.State>().updates
|
||||
val aliceVaultUpdates: Observable<Vault.Update<Cash.State>> = aliceProxy.vaultTrackBy<Cash.State>().updates
|
||||
// END 3
|
||||
|
||||
// START 4
|
||||
val issueRef = OpaqueBytes.of(0)
|
||||
aliceProxy.startFlow(::CashIssueAndPaymentFlow,
|
||||
1000.DOLLARS,
|
||||
issueRef,
|
||||
bob.nodeInfo.singleIdentity(),
|
||||
true,
|
||||
defaultNotaryIdentity
|
||||
).returnValue.getOrThrow()
|
||||
|
||||
bobVaultUpdates.expectEvents {
|
||||
expect { update ->
|
||||
println("Bob got vault update of $update")
|
||||
val amount: Amount<Issued<Currency>> = update.produced.first().state.data.amount
|
||||
assertEquals(1000.DOLLARS, amount.withoutIssuer())
|
||||
}
|
||||
}
|
||||
// END 4
|
||||
|
||||
// START 5
|
||||
bobProxy.startFlow(::CashPaymentFlow, 1000.DOLLARS, alice.nodeInfo.singleIdentity()).returnValue.getOrThrow()
|
||||
|
||||
aliceVaultUpdates.expectEvents {
|
||||
expect { update ->
|
||||
println("Alice got vault update of $update")
|
||||
val amount: Amount<Issued<Currency>> = update.produced.first().state.data.amount
|
||||
assertEquals(1000.DOLLARS, amount.withoutIssuer())
|
||||
}
|
||||
}
|
||||
// END 5
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package net.corda.docs
|
||||
|
||||
import net.corda.client.rpc.CordaRPCClient
|
||||
import net.corda.core.messaging.startFlow
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.docs.tutorial.flowstatemachines.ExampleSummingFlow
|
||||
import net.corda.node.services.Permissions
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.driver.DriverParameters
|
||||
import net.corda.testing.driver.driver
|
||||
import net.corda.testing.node.User
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class TutorialFlowAsyncOperationTest {
|
||||
// DOCSTART summingWorks
|
||||
@Test
|
||||
fun summingWorks() {
|
||||
driver(DriverParameters(startNodesInProcess = true)) {
|
||||
val aliceUser = User("aliceUser", "testPassword1", permissions = setOf(Permissions.all()))
|
||||
val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(aliceUser)).getOrThrow()
|
||||
val aliceClient = CordaRPCClient(alice.rpcAddress)
|
||||
val aliceProxy = aliceClient.start("aliceUser", "testPassword1").proxy
|
||||
val answer = aliceProxy.startFlow(::ExampleSummingFlow).returnValue.getOrThrow()
|
||||
assertEquals(3, answer)
|
||||
}
|
||||
}
|
||||
// DOCEND summingWorks
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package net.corda.docs.java.tutorial.flowstatemachines;
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable;
|
||||
import net.corda.core.flows.FlowLogic;
|
||||
import net.corda.core.flows.StartableByRPC;
|
||||
import net.corda.core.internal.FlowAsyncOperationKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// DOCSTART ExampleSummingFlow
|
||||
@StartableByRPC
|
||||
public final class ExampleSummingFlow extends FlowLogic<Integer> {
|
||||
@Suspendable
|
||||
@NotNull
|
||||
@Override
|
||||
public Integer call() {
|
||||
return FlowAsyncOperationKt.executeAsync(this, new SummingOperation(1, 2), false);
|
||||
}
|
||||
}
|
||||
// DOCEND ExampleSummingFlow
|
@ -0,0 +1,32 @@
|
||||
package net.corda.docs.java.tutorial.flowstatemachines;
|
||||
|
||||
import net.corda.core.concurrent.CordaFuture;
|
||||
import net.corda.core.internal.FlowAsyncOperation;
|
||||
import net.corda.core.internal.concurrent.CordaFutureImplKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// DOCSTART SummingOperation
|
||||
public final class SummingOperation implements FlowAsyncOperation<Integer> {
|
||||
private final int a;
|
||||
private final int b;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CordaFuture<Integer> execute() {
|
||||
return CordaFutureImplKt.doneFuture(this.a + this.b);
|
||||
}
|
||||
|
||||
public final int getA() {
|
||||
return this.a;
|
||||
}
|
||||
|
||||
public final int getB() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
public SummingOperation(int a, int b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
// DOCEND SummingOperation
|
@ -0,0 +1,31 @@
|
||||
package net.corda.docs.java.tutorial.flowstatemachines;
|
||||
|
||||
import net.corda.core.concurrent.CordaFuture;
|
||||
import net.corda.core.internal.FlowAsyncOperation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// DOCSTART SummingOperationThrowing
|
||||
public final class SummingOperationThrowing implements FlowAsyncOperation<Integer> {
|
||||
private final int a;
|
||||
private final int b;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CordaFuture<Integer> execute() {
|
||||
throw new IllegalStateException("You shouldn't be calling me");
|
||||
}
|
||||
|
||||
public final int getA() {
|
||||
return this.a;
|
||||
}
|
||||
|
||||
public final int getB() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
public SummingOperationThrowing(int a, int b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
// DOCEND SummingOperationThrowing
|
@ -0,0 +1,38 @@
|
||||
package net.corda.docs.tutorial.flowstatemachines
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import net.corda.core.concurrent.CordaFuture
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.internal.FlowAsyncOperation
|
||||
import net.corda.core.internal.concurrent.doneFuture
|
||||
import net.corda.core.internal.concurrent.openFuture
|
||||
import net.corda.core.internal.executeAsync
|
||||
|
||||
// DOCSTART SummingOperation
|
||||
class SummingOperation(val a: Int, val b: Int) : FlowAsyncOperation<Int> {
|
||||
override fun execute(): CordaFuture<Int> {
|
||||
return doneFuture(a + b)
|
||||
}
|
||||
}
|
||||
// DOCEND SummingOperation
|
||||
|
||||
// DOCSTART SummingOperationThrowing
|
||||
class SummingOperationThrowing(val a: Int, val b: Int) : FlowAsyncOperation<Int> {
|
||||
override fun execute(): CordaFuture<Int> {
|
||||
throw IllegalStateException("You shouldn't be calling me")
|
||||
}
|
||||
}
|
||||
// DOCEND SummingOperationThrowing
|
||||
|
||||
// DOCSTART ExampleSummingFlow
|
||||
@StartableByRPC
|
||||
class ExampleSummingFlow : FlowLogic<Int>() {
|
||||
@Suspendable
|
||||
override fun call(): Int {
|
||||
val answer = executeAsync(SummingOperation(1, 2))
|
||||
return answer // hopefully 3
|
||||
}
|
||||
}
|
||||
// DOCEND ExampleSummingFlow
|
||||
|
Reference in New Issue
Block a user