blob: 46aee7e8cf40089da8b5c6bfec69d0c85d56bbf6 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>PLC4X &#x2013; </title>
<script src="../../js/jquery.slim.min.js" type="text/javascript"></script>
<!--script src="../../js/popper.min.js" type="javascript"></script-->
<script src="../../js/bootstrap.bundle.min.js" type="text/javascript"></script>
<!-- The tooling for adding images and links to Apache events -->
<script src="https://www.apachecon.com/event-images/snippet.js" type="text/javascript"></script>
<!-- FontAwesome -->
<link rel="stylesheet" href="../../css/all.min.css" type="text/css"/>
<!-- Bootstrap -->
<link rel="stylesheet" href="../../css/bootstrap.min.css" type="text/css"/>
<!-- Some Maven Site defaults -->
<link rel="stylesheet" href="../../css/maven-base.css" type="text/css"/>
<link rel="stylesheet" href="../../css/maven-theme.css" type="text/css"/>
<!-- The PLC4X version of a bootstrap theme -->
<link rel="stylesheet" href="../../css/themes/plc4x.css" type="text/css" id="pagestyle"/>
<!-- A custom style for printing content -->
<link rel="stylesheet" href="../../css/print.css" type="text/css" media="print"/>
<meta http-equiv="Content-Language" content="en"/>
</head>
<body class="composite">
<nav class="navbar navbar-light navbar-expand-md bg-faded justify-content-center border-bottom">
<!--a href="/" class="navbar-brand d-flex w-50 mr-auto">Navbar 3</a-->
<a href="https://plc4x.apache.org/" id="bannerLeft"><img src="../../images/apache_plc4x_logo_small.png" alt="Apache PLC4X"/></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsingNavbar3">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse w-100" id="collapsingNavbar3">
<ul class="navbar-nav w-100 justify-content-center">
<li class="nav-item">
<a class="nav-link" href="../../index.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../users/index.html">Users</a>
</li>
<li class="nav-item active">
<a class="nav-link" href="../../developers/index.html">Developers</a>
</li>
<li class="nav-item">
<a class="nav-link" href="../../apache/index.html">Apache</a>
</li>
</ul>
<ul class="nav navbar-nav ml-auto justify-content-end">
<li class="nav-item row valign-middle">
<a class="acevent" data-format="wide" data-mode="light" data-event="random" style="width:240px;height:60px;"></a>
</li>
</ul>
</div>
</nav>
<div class="container-fluid">
<div class="row h-100">
<nav class="col-sm-push col-md-2 pt-3 sidebar">
<div class="sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a href="../../developers/infrastructure/issues.html" class="nav-link">Bug & Issue Tracker</a>
</li>
<li class="nav-item">
<a href="../../developers/index.html" class="nav-link">Section Home</a>
</li>
<li class="nav-item">
<a href="../../developers/preparing/index.html" class="nav-link">Preparing your Computer</a>
<ul class="flex-column pl-4 nav">
<li class="nav-item">
<a href="../../developers/preparing/linux.html" class="nav-link">Linux</a>
</li>
<li class="nav-item">
<a href="../../developers/preparing/macos.html" class="nav-link">Mac OS</a>
</li>
<li class="nav-item">
<a href="../../developers/preparing/windows.html" class="nav-link">Windows</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="../../developers/building.html" class="nav-link">Building</a>
</li>
<li class="nav-item">
<a href="../../developers/contributing.html" class="nav-link">Contributing</a>
</li>
<li class="nav-item">
<a href="../../developers/tutorials/index.html" class="nav-link">Tutorials</a>
<ul class="flex-column pl-4 nav">
<li class="nav-item">
<a href="../../developers/tutorials/writing-driver.html" class="nav-link">Writing Drivers</a>
</li>
<li class="nav-item">
<strong class="nav-link">Testing Drivers</strong>
</li>
</ul>
</li>
<li class="nav-item">
<a href="../../developers/code-gen/index.html" class="nav-link">Code Generation</a>
<ul class="flex-column pl-4 nav">
<li class="nav-item">
<a href="../../developers/code-gen/protocol/mspec.html" class="nav-link">Protocol: MSpec Format</a>
</li>
<li class="nav-item">
<a href="../../developers/code-gen/language/freemarker.html" class="nav-link">Language: Apache Freemarker</a>
</li>
<li class="nav-item">
<a href="../../developers/code-gen/protocol/df1.html" class="nav-link">Example: DF1 MSpec</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/index.html" class="nav-link">Infrastructure</a>
<ul class="flex-column pl-4 nav">
<li class="nav-item">
<a href="../../developers/infrastructure/ci.html" class="nav-link">Continuous Integration</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/issues.html" class="nav-link">Bug & Issue Tracker</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/sonar.html" class="nav-link">Code Analysis</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/wiki.html" class="nav-link">Wiki</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/vm.html" class="nav-link">Build VM</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/website.html" class="nav-link">Website</a>
</li>
<li class="nav-item">
<a href="../../developers/infrastructure/vpn.html" class="nav-link">IoT VPN</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="../../developers/release/index.html" class="nav-link">Releasing</a>
<ul class="flex-column pl-4 nav">
<li class="nav-item">
<a href="../../developers/release/release.html" class="nav-link">Releasing</a>
</li>
<li class="nav-item">
<a href="../../developers/release/validation.html" class="nav-link">Validating</a>
</li>
<li class="nav-item">
<a href="../../developers/release/build-tools.html" class="nav-link">Releasing Build-Tools</a>
</li>
</ul>
</li>
<li class="nav-item">
<a href="../../developers/team.html" class="nav-link">Team</a>
</li>
<li class="nav-item">
<a href="../../developers/decisions.html" class="nav-link">Decision Making</a>
</li>
<li class="nav-item">
<a href="../../developers/maturity.html" class="nav-link">Maturity</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="ml-sm-auto px-4 col-sm-pull col-md-9 col-lg-10 h-100">
<h1>Testing Serializers and Parsers</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Currently the build generates the serializers and parsers from a provided <code>mspec</code> specification.</p>
</div>
<div class="paragraph">
<p>A typical full round-trip test for the model, parsers and serializers would look as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Starting from a byte array</p>
</li>
<li>
<p>The parser is used to parse the byte array</p>
</li>
<li>
<p>The parsed model instance is compared with an expected model</p>
</li>
<li>
<p>If the expected model matched the expected one the model is serialized back to a byte array</p>
</li>
<li>
<p>The resulting byte array is compared to the original byte array</p>
</li>
<li>
<p>If the byte arrays are identical, the round-trip is regarded ok</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Doing this manually would require a lot of manual object construction and validation, so we created a framework for creating such tests.</p>
</div>
<div class="paragraph">
<p>As XML, no matter what you think about it, allows simple and easy readable descriptions these tests are provided as <code>XML files</code>.</p>
</div>
<div class="paragraph">
<p>All generated model classes allow parsing and serializing to XML via <code>Jackson</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="structure_of_a_test">Structure of a test</h2>
<div class="sectionbody">
<div class="paragraph">
<p>A typical test looks like this:</p>
</div>
<div class="listingblock">
<div class="content">
<pre> &lt;testcase&gt;
&lt;name&gt;Read Input Registers Request&lt;/name&gt;
&lt;raw&gt;000000000006ff0408d20002&lt;/raw&gt;
&lt;root-type&gt;ModbusTcpADU&lt;/root-type&gt;
&lt;parser-arguments&gt;
&lt;response&gt;false&lt;/response&gt;
&lt;/parser-arguments&gt;
&lt;xml&gt;
&lt;ModbusTcpADU className="org.apache.plc4x.java.modbus.readwrite.ModbusTcpADU"&gt;
&lt;transactionIdentifier&gt;0&lt;/transactionIdentifier&gt;
&lt;unitIdentifier&gt;255&lt;/unitIdentifier&gt;
&lt;pdu className="org.apache.plc4x.java.modbus.readwrite.ModbusPDUReadInputRegistersRequest"&gt;
&lt;startingAddress&gt;2258&lt;/startingAddress&gt;
&lt;quantity&gt;2&lt;/quantity&gt;
&lt;/pdu&gt;
&lt;/ModbusTcpADU&gt;
&lt;/xml&gt;
&lt;/testcase&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>As you can see, the <code>name</code> provides a simple human readable name for the test which is used for reporting success and failure.</p>
</div>
<div class="paragraph">
<p>The <code>raw</code> element contains the <code>hex-representation</code> of the <code>binary input</code>.</p>
</div>
<div class="paragraph">
<p>After that the <code>root-type</code> specifies the base type used for parsing this data. In above example the test will use the <code>ModbusTcpADUIO.serialize</code> and <code>ModbusTcpADUIO.parse</code> methods for serializing and parsing.</p>
</div>
<div class="paragraph">
<p>Some parsers require additional parameters for parsing. In above example the Modbus protocol can&#8217;t decide if something is a request or response from the data itself, so we have to pass that information in using a <code>parser-arguments</code> argument.</p>
</div>
<div class="paragraph">
<p>The final element is the <code>xml</code> element, which contains the XML representation of the parsed object.</p>
</div>
<div class="paragraph">
<p>Each test implements exactly the test-strategy sketched above, however for comparing the parsed and the expected model, we use <code>XMLUint</code> to serialize the parsed model to XML and compare that to the given XML in the test-case declaration.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="structure_of_a_testsuite">Structure of a testsuite</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Multiple tests are usually wrapped into a testsuite document.</p>
</div>
<div class="paragraph">
<p>In general this is just a container with a given testsuite <code>name</code> and a number of <code>testcase</code> elements.</p>
</div>
<div class="paragraph">
<p>One important setting however controls the endianness of the protocol in general.</p>
</div>
<div class="paragraph">
<p>This is controlled with a <code>bigEndian</code> attribute in the testsuite root element.</p>
</div>
<div class="paragraph">
<p>An example testsuite document looks as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;test:testsuite xmlns:test="https://plc4x.apache.org/schemas/parser-serializer-testsuite.xsd"
bigEndian="true"&gt;
&lt;name&gt;Allen-Bradley DF1&lt;/name&gt;
&lt;testcase&gt;
...
&lt;/testcase&gt;
&lt;testcase&gt;
...
&lt;/testcase&gt;
&lt;testcase&gt;
...
&lt;/testcase&gt;
&lt;testcase&gt;
...
&lt;/testcase&gt;
&lt;/test:testsuite&gt;</pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the_junit_runner">The Junit runner</h2>
<div class="sectionbody">
<div class="paragraph">
<p>All logic is implemented in the <code>plc4j-utils-test-utils</code> module, so make sure to add the following test-dependency:</p>
</div>
<div class="listingblock">
<div class="content">
<pre> &lt;dependency&gt;
&lt;groupId&gt;org.apache.plc4x&lt;/groupId&gt;
&lt;artifactId&gt;plc4j-utils-test-utils&lt;/artifactId&gt;
&lt;version&gt;{project.version}&lt;/version&gt;
&lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</pre>
</div>
</div>
<div class="paragraph">
<p>In order to run these tests as part of the build, as a last step we need to create a test-runner class.</p>
</div>
<div class="paragraph">
<p>This is generally just a hand-full of boilerplate code, telling the test which document to use for testing.</p>
</div>
<div class="paragraph">
<p>Following code snippet sort of looks the same for every testsuite:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>package org.apache.plc4x.java.modbus;
import org.apache.plc4x.test.parserserializer.ParserSerializerTestsuiteRunner;
public class ModbusIOTest extends ParserSerializerTestsuiteRunner {
public ModbusIOTest() {
super("/testsuite/ModbusTestsuite.xml");
}
}</pre>
</div>
</div>
<div class="paragraph">
<p>Here the document <code>ModbusTestsuite.xml</code> is located in the directory: <code>src/test/resources/testsuite/</code>.</p>
</div>
</div>
</div>
</main>
<footer class="pt-4 my-md-5 pt-md-5 w-100 border-top">
<div class="row justify-content-md-center" style="font-size: 13px">
<div class="col col-6 text-center">
Copyright &#169; 2017&#x2013;2022 <a href="https://www.apache.org/">The Apache Software Foundation</a>.
All rights reserved.<br/>
Apache PLC4X, PLC4X, Apache, the Apache feather logo, and the Apache PLC4X project logo are either registered trademarks or trademarks of The Apache Software Foundation in the United States and other countries. All other marks mentioned may be trademarks or registered trademarks of their respective owners.
<br/><div style="text-align:center;">Home screen image taken from <a
href="https://flic.kr/p/chEftd">Flickr</a>, "Tesla Robot Dance" by Steve Jurvetson, licensed
under <a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0 Generic</a>, image cropped
and blur effect added.</div>
</div>
</div>
</footer>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="../../js/jquery.slim.min.js"></script>
<script src="../../js/popper.min.js"></script>
<script src="../../js/bootstrap.min.js"></script>
<script type="text/javascript">
$('.carousel .carousel-item').each(function(){
var next = $(this).next();
if (!next.length) {
next = $(this).siblings(':first');
}
next.children(':first-child').clone().appendTo($(this));
for (let i = 0; i < 3; i++) {
next=next.next();
if (!next.length) {
next = $(this).siblings(':first');
}
next.children(':first-child').clone().appendTo($(this));
}
});
</script>
</body>
</html>