<!-- If you edit this, then please make the same changes to layout_for_doc_website.html, as that is used for the web doc site generation which we put analytics tracking on to identify any potential problem pages --> <!DOCTYPE html> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Integration testing — R3 Corda latest documentation</title> <link rel="stylesheet" href="_static/css/custom.css" type="text/css" /> <link rel="top" title="R3 Corda latest documentation" href="index.html"/> <link rel="next" title="Client RPC API tutorial" href="tutorial-clientrpc-api.html"/> <link rel="prev" title="Writing a contract test" href="tutorial-test-dsl.html"/> <script src="_static/js/modernizr.min.js"></script> </head> <body class="wy-body-for-nav" role="document"> <div class="wy-grid-for-nav"> <nav data-toggle="wy-nav-shift" class="wy-nav-side"> <div class="wy-side-scroll"> <div class="wy-side-nav-search"> <a href="index.html" class="icon icon-home"> R3 Corda </a> <div class="version"> latest </div> <div role="search"> <form id="rtd-search-form" class="wy-form" action="search.html" method="get"> <input type="text" name="q" placeholder="Search docs" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> <br> API reference: <a href="api/kotlin/corda/index.html">Kotlin</a>/ <a href="api/javadoc/index.html">JavaDoc</a> <br> <a href="https://discourse.corda.net">Discourse Forums</a> <br> <a href="http://slack.corda.net">Slack</a> <br> </div> <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation"> <p class="caption"><span class="caption-text">Getting started</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="inthebox.html">What’s included?</a></li> <li class="toctree-l1"><a class="reference internal" href="getting-set-up.html">Getting set up</a></li> <li class="toctree-l1"><a class="reference internal" href="getting-set-up-fault-finding.html">Troubleshooting</a></li> <li class="toctree-l1"><a class="reference internal" href="running-the-demos.html">Running the demos</a></li> <li class="toctree-l1"><a class="reference internal" href="CLI-vs-IDE.html">CLI vs IDE</a></li> </ul> <p class="caption"><span class="caption-text">Key concepts</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="data-model.html">Data model</a></li> <li class="toctree-l1"><a class="reference internal" href="transaction-data-types.html">Data types</a></li> <li class="toctree-l1"><a class="reference internal" href="merkle-trees.html">Transaction tear-offs</a></li> <li class="toctree-l1"><a class="reference internal" href="consensus.html">Consensus model</a></li> <li class="toctree-l1"><a class="reference internal" href="clauses.html">Clauses</a></li> </ul> <p class="caption"><span class="caption-text">CorDapps</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="creating-a-cordapp.html">CorDapp basics</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-cordapp.html">The CorDapp template</a></li> </ul> <p class="caption"><span class="caption-text">The Corda node</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="clientrpc.html">Client RPC</a></li> <li class="toctree-l1"><a class="reference internal" href="messaging.html">Networking and messaging</a></li> <li class="toctree-l1"><a class="reference internal" href="persistence.html">Persistence</a></li> <li class="toctree-l1"><a class="reference internal" href="node-administration.html">Node administration</a></li> <li class="toctree-l1"><a class="reference internal" href="corda-configuration-file.html">Node configuration</a></li> <li class="toctree-l1"><a class="reference internal" href="corda-plugins.html">The Corda plugin framework</a></li> <li class="toctree-l1"><a class="reference internal" href="node-services.html">Brief introduction to the node services</a></li> <li class="toctree-l1"><a class="reference internal" href="node-explorer.html">Node Explorer</a></li> <li class="toctree-l1"><a class="reference internal" href="permissioning.html">Network permissioning</a></li> </ul> <p class="caption"><span class="caption-text">Tutorials</span></p> <ul class="current"> <li class="toctree-l1"><a class="reference internal" href="tutorial-contract.html">Writing a contract</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-contract-clauses.html">Writing a contract using clauses</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-test-dsl.html">Writing a contract test</a></li> <li class="toctree-l1 current"><a class="current reference internal" href="#">Integration testing</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-clientrpc-api.html">Client RPC API tutorial</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-building-transactions.html">Building transactions</a></li> <li class="toctree-l1"><a class="reference internal" href="flow-state-machines.html">Writing flows</a></li> <li class="toctree-l1"><a class="reference internal" href="flow-testing.html">Writing flow tests</a></li> <li class="toctree-l1"><a class="reference internal" href="running-a-notary.html">Running a notary service</a></li> <li class="toctree-l1"><a class="reference internal" href="using-a-notary.html">Using a notary service</a></li> <li class="toctree-l1"><a class="reference internal" href="oracles.html">Writing oracle services</a></li> <li class="toctree-l1"><a class="reference internal" href="tutorial-attachments.html">Using attachments</a></li> <li class="toctree-l1"><a class="reference internal" href="event-scheduling.html">Event scheduling</a></li> </ul> <p class="caption"><span class="caption-text">Other</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="network-simulator.html">Network Simulator</a></li> </ul> <p class="caption"><span class="caption-text">Component library</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="contract-catalogue.html">Contract catalogue</a></li> <li class="toctree-l1"><a class="reference internal" href="contract-irs.html">Interest rate swaps</a></li> </ul> <p class="caption"><span class="caption-text">Appendix</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="loadtesting.html">Load testing</a></li> <li class="toctree-l1"><a class="reference internal" href="setting-up-a-corda-network.html">What is a corda network?</a></li> <li class="toctree-l1"><a class="reference internal" href="secure-coding-guidelines.html">Secure coding guidelines</a></li> <li class="toctree-l1"><a class="reference internal" href="release-process.html">Release process</a></li> <li class="toctree-l1"><a class="reference internal" href="release-notes.html">Release notes</a></li> <li class="toctree-l1"><a class="reference internal" href="codestyle.html">Code style guide</a></li> <li class="toctree-l1"><a class="reference internal" href="building-the-docs.html">Building the documentation</a></li> <li class="toctree-l1"><a class="reference internal" href="publishing-corda.html">Publishing Corda</a></li> <li class="toctree-l1"><a class="reference internal" href="azure-vm.html">Working with the Corda Demo on Azure Marketplace</a></li> </ul> <p class="caption"><span class="caption-text">Glossary</span></p> <ul> <li class="toctree-l1"><a class="reference internal" href="glossary.html">Glossary</a></li> </ul> </div> </div> </nav> <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"> <nav class="wy-nav-top" role="navigation" aria-label="top navigation"> <i data-toggle="wy-nav-top" class="fa fa-bars"></i> <a href="index.html">R3 Corda</a> </nav> <div class="wy-nav-content"> <div class="rst-content"> <div role="navigation" aria-label="breadcrumbs navigation"> <ul class="wy-breadcrumbs"> <li><a href="index.html">Docs</a> »</li> <li>Integration testing</li> <li class="wy-breadcrumbs-aside"> <a href="_sources/tutorial-integration-testing.txt" rel="nofollow"> View page source</a> </li> </ul> <hr/> </div> <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article"> <div itemprop="articleBody"> <div class="section" id="integration-testing"> <h1>Integration testing<a class="headerlink" href="#integration-testing" title="Permalink to this headline">ΒΆ</a></h1> <p>Integration testing involves bringing up nodes locally and testing invariants about them by starting flows and inspecting their state.</p> <p>In this tutorial we will bring up three nodes Alice, Bob and a Notary. Alice will issue Cash to Bob, then Bob will send this Cash back to Alice. We will see how to test some simple deterministic and nondeterministic invariants in the meantime.</p> <p>(Note that this example where Alice is self-issuing Cash is purely for demonstration purposes, in reality Cash would be issued by a bank and subsequently passed around.)</p> <p>In order to spawn nodes we will use the Driver DSL. This DSL allows one to start up node processes from code. It manages a network map service and safe shutting down of nodes in the background.</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span> driver { val testUser = User("testUser", "testPassword", permissions = setOf(startFlowPermission<CashFlow>())) val (alice, bob, notary) = Futures.allAsList( startNode("Alice", rpcUsers = listOf(testUser)), startNode("Bob", rpcUsers = listOf(testUser)), startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))) ).getOrThrow() </pre></div> </div> <p>The above code creates a <code class="docutils literal"><span class="pre">User</span></code> permissioned to start the <code class="docutils literal"><span class="pre">CashFlow</span></code> protocol. It then starts up Alice and Bob with this user, allowing us to later connect to the nodes.</p> <p>Then the notary is started up. Note that we need to add <code class="docutils literal"><span class="pre">ValidatingNotaryService</span></code> as an advertised service in order for this node to serve notary functionality. This is also where flows added in plugins should be specified. Note also that we won’t connect to the notary directly, so there’s no need to pass in the test <code class="docutils literal"><span class="pre">User</span></code>.</p> <p>The <code class="docutils literal"><span class="pre">startNode</span></code> function returns a future that completes once the node is fully started. This allows starting of the nodes to be parallel. We wait on these futures as we need the information returned; their respective <code class="docutils literal"><span class="pre">NodeHandles</span></code> s.</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">val</span> <span class="py">aliceClient</span> <span class="p">=</span> <span class="n">alice</span><span class="p">.</span><span class="n">rpcClientToNode</span><span class="p">()</span> <span class="n">aliceClient</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="s">"testUser"</span><span class="p">,</span> <span class="s">"testPassword"</span><span class="p">)</span> <span class="k">val</span> <span class="py">aliceProxy</span> <span class="p">=</span> <span class="n">aliceClient</span><span class="p">.</span><span class="n">proxy</span><span class="p">()</span> <span class="k">val</span> <span class="py">bobClient</span> <span class="p">=</span> <span class="n">bob</span><span class="p">.</span><span class="n">rpcClientToNode</span><span class="p">()</span> <span class="n">bobClient</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="s">"testUser"</span><span class="p">,</span> <span class="s">"testPassword"</span><span class="p">)</span> <span class="k">val</span> <span class="py">bobProxy</span> <span class="p">=</span> <span class="n">bobClient</span><span class="p">.</span><span class="n">proxy</span><span class="p">()</span> </pre></div> </div> <p>Next we connect to Alice and Bob respectively from the test process using the test user we created. Then we establish RPC links that allow us to start flows and query state.</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">val</span> <span class="py">bobVaultUpdates</span> <span class="p">=</span> <span class="n">bobProxy</span><span class="p">.</span><span class="n">vaultAndUpdates</span><span class="p">().</span><span class="n">second</span> <span class="k">val</span> <span class="py">aliceVaultUpdates</span> <span class="p">=</span> <span class="n">aliceProxy</span><span class="p">.</span><span class="n">vaultAndUpdates</span><span class="p">().</span><span class="n">second</span> </pre></div> </div> <p>We will be interested in changes to Alice’s and Bob’s vault, so we query a stream of vault updates from each.</p> <p>Now that we’re all set up we can finally get some Cash action going!</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">val</span> <span class="py">issueRef</span> <span class="p">=</span> <span class="n">OpaqueBytes</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="m">0</span><span class="p">)</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="k">in</span> <span class="m">1</span> <span class="p">..</span> <span class="m">10</span><span class="p">)</span> <span class="p">{</span> <span class="n">thread</span> <span class="p">{</span> <span class="n">aliceProxy</span><span class="p">.</span><span class="n">startFlow</span><span class="p">(</span><span class="o">::</span><span class="n">CashFlow</span><span class="p">,</span> <span class="n">CashCommand</span><span class="p">.</span><span class="n">IssueCash</span><span class="p">(</span> <span class="n">amount</span> <span class="p">=</span> <span class="n">i</span><span class="p">.</span><span class="n">DOLLARS</span><span class="p">,</span> <span class="n">issueRef</span> <span class="p">=</span> <span class="n">issueRef</span><span class="p">,</span> <span class="n">recipient</span> <span class="p">=</span> <span class="n">bob</span><span class="p">.</span><span class="n">nodeInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">,</span> <span class="n">notary</span> <span class="p">=</span> <span class="n">notary</span><span class="p">.</span><span class="n">nodeInfo</span><span class="p">.</span><span class="n">notaryIdentity</span> <span class="p">))</span> <span class="p">}</span> <span class="p">}</span> <span class="n">bobVaultUpdates</span><span class="p">.</span><span class="n">expectEvents</span> <span class="p">{</span> <span class="n">parallel</span><span class="p">(</span> <span class="p">(</span><span class="m">1</span> <span class="p">..</span> <span class="m">10</span><span class="p">).</span><span class="n">map</span> <span class="p">{</span> <span class="n">i</span> <span class="p">-></span> <span class="n">expect</span><span class="p">(</span> <span class="n">match</span> <span class="p">=</span> <span class="p">{</span> <span class="n">update</span><span class="p">:</span> <span class="n">Vault</span><span class="p">.</span><span class="n">Update</span> <span class="p">-></span> <span class="p">(</span><span class="n">update</span><span class="p">.</span><span class="n">produced</span><span class="p">.</span><span class="n">first</span><span class="p">().</span><span class="n">state</span><span class="p">.</span><span class="k">data</span> <span class="k">as</span> <span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">).</span><span class="n">amount</span><span class="p">.</span><span class="n">quantity</span> <span class="p">==</span> <span class="n">i</span> <span class="p">*</span> <span class="m">100L</span> <span class="p">}</span> <span class="p">)</span> <span class="p">{</span> <span class="n">update</span> <span class="p">-></span> <span class="n">println</span><span class="p">(</span><span class="s">"Bob vault update of $update"</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="p">)</span> <span class="p">}</span> </pre></div> </div> <p>The first loop creates 10 threads, each starting a <code class="docutils literal"><span class="pre">CashFlow</span></code> flow on the Alice node. We specify that we want to issue <code class="docutils literal"><span class="pre">i</span></code> dollars to Bob, using the Notary as the notary responsible for notarising the created states. Note that no notarisation will occur yet as we’re not spending any states, only entering new ones to the ledger.</p> <p>We started the flows from different threads for the sake of the tutorial, to demonstrate how to test non-determinism, which is what the <code class="docutils literal"><span class="pre">expectEvents</span></code> block does.</p> <p>The Expect DSL allows ordering constraints to be checked on a stream of events. The above code specifies that we are expecting 10 updates to be emitted on the <code class="docutils literal"><span class="pre">bobVaultUpdates</span></code> stream in unspecified order (this is what the <code class="docutils literal"><span class="pre">parallel</span></code> construct does). We specify a (otherwise optional) <code class="docutils literal"><span class="pre">match</span></code> predicate to identify specific updates we are interested in, which we then print.</p> <p>If we run the code written so far we should see 4 nodes starting up (Alice,Bob,Notary + implicit Network Map service), then 10 logs of Bob receiving 1,2,...10 dollars from Alice in some unspecified order.</p> <p>Next we want Bob to send this Cash back to Alice.</p> <div class="highlight-kotlin"><div class="highlight"><pre><span></span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="k">in</span> <span class="m">1</span> <span class="p">..</span> <span class="m">10</span><span class="p">)</span> <span class="p">{</span> <span class="k">val</span> <span class="py">flowHandle</span> <span class="p">=</span> <span class="n">bobProxy</span><span class="p">.</span><span class="n">startFlow</span><span class="p">(</span><span class="o">::</span><span class="n">CashFlow</span><span class="p">,</span> <span class="n">CashCommand</span><span class="p">.</span><span class="n">PayCash</span><span class="p">(</span> <span class="n">amount</span> <span class="p">=</span> <span class="n">i</span><span class="p">.</span><span class="n">DOLLARS</span><span class="p">.</span><span class="n">issuedBy</span><span class="p">(</span><span class="n">alice</span><span class="p">.</span><span class="n">nodeInfo</span><span class="p">.</span><span class="n">legalIdentity</span><span class="p">.</span><span class="n">ref</span><span class="p">(</span><span class="n">issueRef</span><span class="p">)),</span> <span class="n">recipient</span> <span class="p">=</span> <span class="n">alice</span><span class="p">.</span><span class="n">nodeInfo</span><span class="p">.</span><span class="n">legalIdentity</span> <span class="p">))</span> <span class="n">assert</span><span class="p">(</span><span class="n">flowHandle</span><span class="p">.</span><span class="n">returnValue</span><span class="p">.</span><span class="n">toBlocking</span><span class="p">().</span><span class="n">first</span><span class="p">()</span> <span class="k">is</span> <span class="n">CashFlowResult</span><span class="p">.</span><span class="n">Success</span><span class="p">)</span> <span class="p">}</span> <span class="n">aliceVaultUpdates</span><span class="p">.</span><span class="n">expectEvents</span> <span class="p">{</span> <span class="n">sequence</span><span class="p">(</span> <span class="p">(</span><span class="m">1</span> <span class="p">..</span> <span class="m">10</span><span class="p">).</span><span class="n">map</span> <span class="p">{</span> <span class="n">i</span> <span class="p">-></span> <span class="n">expect</span> <span class="p">{</span> <span class="n">update</span><span class="p">:</span> <span class="n">Vault</span><span class="p">.</span><span class="n">Update</span> <span class="p">-></span> <span class="n">println</span><span class="p">(</span><span class="s">"Alice got vault update of $update"</span><span class="p">)</span> <span class="n">assertEquals</span><span class="p">((</span><span class="n">update</span><span class="p">.</span><span class="n">produced</span><span class="p">.</span><span class="n">first</span><span class="p">().</span><span class="n">state</span><span class="p">.</span><span class="k">data</span> <span class="k">as</span> <span class="n">Cash</span><span class="p">.</span><span class="n">State</span><span class="p">).</span><span class="n">amount</span><span class="p">.</span><span class="n">quantity</span><span class="p">,</span> <span class="n">i</span> <span class="p">*</span> <span class="m">100L</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </pre></div> </div> <p>This time we’ll do it sequentially. We make Bob pay 1,2,..10 dollars to Alice in order. We make sure that a the <code class="docutils literal"><span class="pre">CashFlow</span></code> has finished by waiting on <code class="docutils literal"><span class="pre">startFlow</span></code> ‘s <code class="docutils literal"><span class="pre">returnValue</span></code>.</p> <p>Then we use the Expect DSL again, this time using <code class="docutils literal"><span class="pre">sequence</span></code> to test for the updates arriving in the order we expect them to.</p> <p>Note that <code class="docutils literal"><span class="pre">parallel</span></code> and <code class="docutils literal"><span class="pre">sequence</span></code> may be nested into each other arbitrarily to test more complex scenarios.</p> <p>That’s it! We saw how to start up several corda nodes locally, how to connect to them, and how to test some simple invariants about <code class="docutils literal"><span class="pre">CashFlow</span></code>.</p> <p>To run the complete test you can open <code class="docutils literal"><span class="pre">example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt</span></code> from IntelliJ and run the test, or alternatively use gradle:</p> <div class="highlight-bash"><div class="highlight"><pre><span></span><span class="c1"># Run example-code integration tests</span> ./gradlew docs/source/example-code:integrationTest -i </pre></div> </div> </div> </div> </div> <footer> <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation"> <a href="tutorial-clientrpc-api.html" class="btn btn-neutral float-right" title="Client RPC API tutorial" accesskey="n">Next <span class="fa fa-arrow-circle-right"></span></a> <a href="tutorial-test-dsl.html" class="btn btn-neutral" title="Writing a contract test" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous</a> </div> <hr/> <div role="contentinfo"> <p> © Copyright 2016, R3 Limited. </p> </div> Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. </footer> </div> </div> </section> </div> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT:'./', VERSION:'latest', COLLAPSE_INDEX:false, FILE_SUFFIX:'.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="_static/jquery.js"></script> <script type="text/javascript" src="_static/underscore.js"></script> <script type="text/javascript" src="_static/doctools.js"></script> <script type="text/javascript" src="_static/js/theme.js"></script> <script type="text/javascript"> jQuery(function () { SphinxRtdTheme.StickyNav.enable(); }); </script> </body> </html>