You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2020/02/26 12:52:42 UTC

[plc4x] 02/02: - Continued working on the driver testsuite - Got the PLC io side working - Got the sending of requests side working - TODO: Finish the processing and validation of responses

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch feature/driver-testsuite
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 39056526f207d42dec8e5f47748d2c8dd1811acc
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Feb 26 13:52:33 2020 +0100

    - Continued working on the driver testsuite
       - Got the PLC io side working
       - Got the sending of requests side working
       - TODO: Finish the processing and validation of responses
---
 .../test/resources/testsuite/S7DriverTestsuite.xml |  35 +++---
 .../java/io/netty/bootstrap/Plc4xBootstrap.java    |  17 ---
 .../java/spi/connection/NettyChannelFactory.java   |  23 ++--
 .../plc4x/test/driver/DriverTestsuiteRunner.java   | 122 +++++++++++++++------
 .../java/org/apache/plc4x/test/driver/Lalala.java  |  44 ++++++++
 .../plc4x/test/driver/model/DriverTestsuite.java   |  10 +-
 .../apache/plc4x/test/driver/model/StepType.java   |   3 +-
 .../apache/plc4x/test/driver/model/TestStep.java   |   8 +-
 .../model/{TestStep.java => api/TestField.java}    |  28 +++--
 .../{TestStep.java => api/TestFieldRequest.java}   |  22 ++--
 .../{TestStep.java => api/TestReadRequest.java}    |  26 ++---
 .../model/{TestStep.java => api/TestRequest.java}  |  24 +---
 .../{TestStep.java => api/TestWriteRequest.java}   |  26 ++---
 .../main/resources/schemas/driver-testsuite.xsd    |  57 ++++++----
 14 files changed, 274 insertions(+), 171 deletions(-)

diff --git a/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml b/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml
index 518c651..015d5cd 100644
--- a/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml
+++ b/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml
@@ -26,7 +26,7 @@
 
   <setup>
     <!-- First the driver is expected to send a COTP connection request -->
-    <send-plc-message>
+    <send-plc-message name="Send COTP Connection Request">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketConnectionRequest">
           <parameters>
@@ -48,7 +48,7 @@
       </TPKTPacket>
     </send-plc-message>
     <!-- The PLC will send a COTP connection response -->
-    <receive-plc-message>
+    <receive-plc-message name="Receive COTP Connection Response">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketConnectionResponse">
           <parameters>
@@ -70,7 +70,7 @@
       </TPKTPacket>
     </receive-plc-message>
     <!-- After that the driver will send a S7 connection request -->
-    <send-plc-message>
+    <send-plc-message name="Send S7 Connection Request">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
           <parameters/>
@@ -89,7 +89,7 @@
       </TPKTPacket>
     </send-plc-message>
     <!-- The PLC will send a S7 connection response -->
-    <receive-plc-message>
+    <receive-plc-message name="Receive S7 Connection Response">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
           <parameters/>
@@ -110,7 +110,7 @@
       </TPKTPacket>
     </receive-plc-message>
     <!-- Next we'll query some type information -->
-    <send-plc-message>
+    <send-plc-message name="Send S7 Identification Request">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
           <parameters/>
@@ -151,7 +151,7 @@
       </TPKTPacket>
     </send-plc-message>
     <!-- Which the PLC will gladly provide to us -->
-    <receive-plc-message>
+    <receive-plc-message name="Receive S7 Identification Response">
       <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
         <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
           <parameters/>
@@ -219,15 +219,21 @@
   <testcase>
     <name>Single element read request</name>
     <steps>
-      <!--api-request-message>
-
-      </api-request-message-->
-      <send-plc-message>
+      <api-request name="Send Read Request">
+        <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
+          <fields>
+            <field className="org.apache.plc4x.test.driver.model.api.TestField">
+              <name>hurz</name>
+              <address>%Q0.0:BOOL</address>
+            </field>
+          </fields>
+        </TestReadRequest>      </api-request>
+      <send-plc-message name="Send S7 Read Request">
         <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
           <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
             <parameters/>
             <payload className="org.apache.plc4x.java.s7.readwrite.S7MessageRequest">
-              <tpduReference>11</tpduReference>
+              <tpduReference>10</tpduReference>
               <parameter className="org.apache.plc4x.java.s7.readwrite.S7ParameterReadVarRequest">
                 <items>
                   <items className="org.apache.plc4x.java.s7.readwrite.S7VarRequestParameterItemAddress">
@@ -245,16 +251,16 @@
               <payload/>
             </payload>
             <eot>true</eot>
-            <tpduRef>11</tpduRef>
+            <tpduRef>10</tpduRef>
           </payload>
         </TPKTPacket>
       </send-plc-message>
-      <receive-plc-message>
+      <receive-plc-message name="Receive S7 Read Response">
         <TPKTPacket className="org.apache.plc4x.java.s7.readwrite.TPKTPacket">
           <payload className="org.apache.plc4x.java.s7.readwrite.COTPPacketData">
             <parameters/>
             <payload className="org.apache.plc4x.java.s7.readwrite.S7MessageResponseData">
-              <tpduReference>11</tpduReference>
+              <tpduReference>10</tpduReference>
               <parameter className="org.apache.plc4x.java.s7.readwrite.S7ParameterReadVarResponse">
                 <numItems>1</numItems>
               </parameter>
@@ -279,6 +285,7 @@
       <!--api-response-message>
 
       </api-response-message-->
+      <delay>1000</delay>
     </steps>
   </testcase>
 
diff --git a/plc4j/spi/src/main/java/io/netty/bootstrap/Plc4xBootstrap.java b/plc4j/spi/src/main/java/io/netty/bootstrap/Plc4xBootstrap.java
index 133f2cb..621439e 100644
--- a/plc4j/spi/src/main/java/io/netty/bootstrap/Plc4xBootstrap.java
+++ b/plc4j/spi/src/main/java/io/netty/bootstrap/Plc4xBootstrap.java
@@ -19,10 +19,6 @@ under the License.
 package io.netty.bootstrap;
 
 import io.netty.channel.Channel;
-import io.netty.channel.ChannelFuture;
-import io.netty.channel.ChannelPromise;
-
-import java.net.SocketAddress;
 
 public class Plc4xBootstrap extends Bootstrap {
 
@@ -50,17 +46,4 @@ public class Plc4xBootstrap extends Bootstrap {
         super.init(channel);
     }
 
-    @Override
-    public ChannelFuture connect(SocketAddress remoteAddress) {
-        final ChannelFuture connectFuture = super.connect(remoteAddress);
-
-        if("Plc4xEmbeddedEventLoop".equals(group.getClass().getSimpleName())) {
-            if (connectFuture instanceof ChannelPromise) {
-                ChannelPromise connectPromise = (ChannelPromise) connectFuture;
-                connectPromise.setSuccess();
-            }
-        }
-        return connectFuture;
-    }
-
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
index 8bfc55a..c42a845 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/connection/NettyChannelFactory.java
@@ -105,14 +105,23 @@ public abstract class NettyChannelFactory implements ChannelFactory {
                     workerGroup.shutdownGracefully();
                 }
             });
-            // Wait for sync
-            f.sync();
-            f.awaitUninterruptibly(); // jf: unsure if we need that
-            // Wait till the session is finished initializing.
-            return f.channel();
-        } catch (InterruptedException e) {
+
+            final Channel channel = f.channel();
+
+            // It seems the embedded channel operates differently.
+            // Intentionally using the class name as we don't want to require a
+            // hard dependency on the test-channel.
+            if(!"Plc4xEmbeddedChannel".equals(channel.getClass().getSimpleName())) {
+                // Wait for sync
+                f.sync();
+                // Wait till the session is finished initializing.
+                f.awaitUninterruptibly(); // jf: unsure if we need that
+            }
+
+            return channel;
+/*        } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            throw new PlcConnectionException("Error creating channel.", e);
+            throw new PlcConnectionException("Error creating channel.", e);*/
         } catch (Exception e) {
             throw new PlcConnectionException("Error creating channel.", e);
         }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
index 5468ba1..ab378ad 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/DriverTestsuiteRunner.java
@@ -21,12 +21,14 @@ package org.apache.plc4x.test.driver;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
 import io.netty.channel.Channel;
 import io.netty.channel.embedded.Plc4xEmbeddedChannel;
 import org.apache.plc4x.java.PlcDriverManager;
 import org.apache.plc4x.java.api.PlcConnection;
 import org.apache.plc4x.java.api.exceptions.PlcConnectionException;
 import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+import org.apache.plc4x.java.api.messages.PlcReadRequest;
 import org.apache.plc4x.java.spi.connection.ChannelExposingConnection;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.generation.*;
@@ -35,6 +37,10 @@ import org.apache.plc4x.test.driver.model.DriverTestsuite;
 import org.apache.plc4x.test.driver.model.StepType;
 import org.apache.plc4x.test.driver.model.TestStep;
 import org.apache.plc4x.test.driver.model.Testcase;
+import org.apache.plc4x.test.driver.model.api.TestField;
+import org.apache.plc4x.test.driver.model.api.TestReadRequest;
+import org.apache.plc4x.test.driver.model.api.TestRequest;
+import org.apache.plc4x.test.driver.model.api.TestWriteRequest;
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
 import org.dom4j.Element;
@@ -82,7 +88,7 @@ public class DriverTestsuiteRunner {
             SAXReader reader = new SAXReader();
             Document document = reader.read(testsuiteDocumentXml);
             Element testsuiteXml = document.getRootElement();
-            boolean littleEndian = !"true".equals(testsuiteXml.attributeValue("bigEndian"));
+            boolean bigEndian = !"false".equals(testsuiteXml.attributeValue("bigEndian"));
             String testsuiteName = testsuiteXml.element(new QName("name")).getTextTrim();
             String driverName = testsuiteXml.element(new QName("driver-name")).getTextTrim();
             Element driverParametersElement = testsuiteXml.element(new QName("driver-parameters"));
@@ -137,7 +143,7 @@ public class DriverTestsuiteRunner {
 
             TimeUnit.MILLISECONDS.sleep(200);
 
-            return new DriverTestsuite(testsuiteName, connection, setupSteps, teardownSteps, testcases);
+            return new DriverTestsuite(testsuiteName, connection, setupSteps, teardownSteps, testcases, bigEndian);
         } catch (DocumentException e) {
             throw new DriverTestsuiteException("Error parsing testsuite xml", e);
         } catch (InterruptedException e) {
@@ -164,50 +170,72 @@ public class DriverTestsuiteRunner {
         }
     }
 
-    private void run(DriverTestsuite testSuite, Testcase testcase) throws DriverTestsuiteException {
-        final Plc4xEmbeddedChannel embeddedChannel = getEmbeddedChannel(testSuite);
-        if(!testSuite.getSetupSteps().isEmpty()) {
+    private void run(DriverTestsuite testsuite, Testcase testcase) throws DriverTestsuiteException {
+        final PlcConnection plcConnection = testsuite.getConnection();
+        final Plc4xEmbeddedChannel embeddedChannel = getEmbeddedChannel(testsuite);
+        final boolean bigEndian = testsuite.isBigEndian();
+        if(!testsuite.getSetupSteps().isEmpty()) {
             LOGGER.info("Running setup steps");
-            for (TestStep setupStep : testSuite.getSetupSteps()) {
-                executeStep(setupStep, embeddedChannel);
+            for (TestStep setupStep : testsuite.getSetupSteps()) {
+                executeStep(setupStep, plcConnection, embeddedChannel, bigEndian);
             }
             LOGGER.info("Finished setup steps");
         }
         LOGGER.info("Running test steps");
         for (TestStep step : testcase.getSteps()) {
-            executeStep(step, embeddedChannel);
+            executeStep(step, plcConnection, embeddedChannel, bigEndian);
         }
         LOGGER.info("Finished test steps");
-        if(!testSuite.getTeardownSteps().isEmpty()) {
+        if(!testsuite.getTeardownSteps().isEmpty()) {
             LOGGER.info("Running teardown steps");
-            for (TestStep teardownStep : testSuite.getTeardownSteps()) {
-                executeStep(teardownStep, embeddedChannel);
+            for (TestStep teardownStep : testsuite.getTeardownSteps()) {
+                executeStep(teardownStep, plcConnection, embeddedChannel, bigEndian);
             }
             LOGGER.info("Finished teardown steps");
         }
     }
 
-    private void executeStep(TestStep testStep, Plc4xEmbeddedChannel embeddedChannel) throws DriverTestsuiteException {
-        LOGGER.info("  - Running step " + testStep.getType());
-        ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+    private void executeStep(TestStep testStep, PlcConnection plcConnection, Plc4xEmbeddedChannel embeddedChannel, boolean bigEndian) throws DriverTestsuiteException {
+        LOGGER.info("  - Running step: '" + testStep.getName() + "' - " + testStep.getType());
+        final ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
         final Element payload = testStep.getPayload();
-        final String className = payload.attributeValue(new QName("className"));
-        String referenceXml = payload.asXML();
         try {
-            final MessageIO messageIO = getMessageIOType(className).newInstance();
             switch (testStep.getType()) {
                 case SEND_PLC_BYTES: {
+                    final ByteBuf byteBuf = embeddedChannel.readOutbound();
+                    if(byteBuf == null) {
+                        throw new DriverTestsuiteException("No outbound message available");
+                    }
+                    final byte[] data = new byte[byteBuf.readableBytes()];
+                    byteBuf.readBytes(data);
+
+                    // TODO: Compare the read bytes with the expected byte array.
+
                     break;
                 }
                 case SEND_PLC_MESSAGE: {
+                    try {
+                        TimeUnit.MILLISECONDS.sleep(200);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                        throw new DriverTestsuiteException("Interrupted during delay.");
+                    }
+
                     final ByteBuf byteBuf = embeddedChannel.readOutbound();
-                    byte[] data = new byte[byteBuf.readableBytes()];
+                    if(byteBuf == null) {
+                        throw new DriverTestsuiteException("No outbound message available");
+                    }
+                    final byte[] data = new byte[byteBuf.readableBytes()];
                     byteBuf.readBytes(data);
-                    ReadBuffer readBuffer = new ReadBuffer(data);
+
+                    final ReadBuffer readBuffer = new ReadBuffer(data, !bigEndian);
                     try {
+                        final String className = payload.attributeValue(new QName("className"));
+                        final MessageIO messageIO = getMessageIOType(className).newInstance();
                         final Object parsedOutput = messageIO.parse(readBuffer);
-                        String xmlString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(parsedOutput);
-                        Diff diff = DiffBuilder.compare(referenceXml).withTest(xmlString).ignoreComments().ignoreWhitespace().build();
+                        final String xmlString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(parsedOutput);
+                        final String referenceXml = payload.asXML();
+                        final Diff diff = DiffBuilder.compare(referenceXml).withTest(xmlString).ignoreComments().ignoreWhitespace().build();
                         if (diff.hasDifferences()) {
                             System.out.println(xmlString);
                             throw new DriverTestsuiteException("Differences were found after parsing.\n" + diff.toString());
@@ -221,19 +249,43 @@ public class DriverTestsuiteRunner {
                     break;
                 }
                 case RECEIVE_PLC_MESSAGE: {
+                    final String className = payload.attributeValue(new QName("className"));
+                    final MessageIO messageIO = getMessageIOType(className).newInstance();
+                    final String referenceXml = payload.asXML();
                     final Message message = mapper.readValue(referenceXml, getMessageType(className));
-                    WriteBuffer writeBuffer = new WriteBuffer(1024);
+                    final WriteBuffer writeBuffer = new WriteBuffer(1024, !bigEndian);
                     try {
                         messageIO.serialize(writeBuffer, message);
-                        byte[] data = new byte[writeBuffer.getPos()];
+                        final byte[] data = new byte[writeBuffer.getPos()];
                         System.arraycopy(writeBuffer.getData(), 0, data, 0, writeBuffer.getPos());
-                        embeddedChannel.writeOutbound(data);
+                        embeddedChannel.writeInbound(Unpooled.wrappedBuffer(data));
                     } catch (ParseException e) {
                         throw new DriverTestsuiteException("Error serializing message", e);
                     }
                     break;
                 }
                 case API_REQUEST: {
+                    final String referenceXml = payload.asXML();
+                    final TestRequest request = mapper.readValue(referenceXml, TestRequest.class);
+                    if(request instanceof TestReadRequest) {
+                        final TestReadRequest readRequest = (TestReadRequest) request;
+                        final PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
+                        for (TestField testField : readRequest.getFields()) {
+                            builder.addItem(testField.getName(), testField.getAddress());
+                        }
+                        final PlcReadRequest plc4xRequest = builder.build();
+                        // Don't block here or the test will not be able to process the rest.
+                        plc4xRequest.execute().whenComplete((result, throwable) -> {
+                            // TODO: Do something in here ...
+                            if(result != null) {
+                                System.out.println("Success");
+                            } else {
+                                System.out.println("Failure " + throwable.getMessage());
+                            }
+                        });
+                    } else if(request instanceof TestWriteRequest) {
+
+                    }
                     break;
                 }
                 case API_RESPONSE: {
@@ -241,13 +293,16 @@ public class DriverTestsuiteRunner {
                 }
                 case DELAY: {
                     try {
-                        TimeUnit.MILLISECONDS.sleep(200);
+                        TimeUnit.MILLISECONDS.sleep(1000);
                     } catch (InterruptedException e) {
                         Thread.currentThread().interrupt();
                         throw new DriverTestsuiteException("Interrupted during delay.");
                     }
+                    break;
+                }
+                case TERMINATE: {
+                    embeddedChannel.close();
                 }
-
             }
         } catch (IOException e) {
             throw new DriverTestsuiteException("Error processing the xml", e);
@@ -260,8 +315,12 @@ public class DriverTestsuiteRunner {
     private TestStep parseTestStep(Element curElement) {
         final String elementName = curElement.getName();
         final StepType stepType = StepType.valueOf(elementName.toUpperCase().replace("-", "_"));
-        final Element definition = curElement.elementIterator().next();
-        return new TestStep(stepType, definition);
+        final String stepName = curElement.attributeValue(new QName("name"));
+        Element definition = null;
+        if(curElement.hasMixedContent()) {
+            definition = curElement.elementIterator().next();
+        }
+        return new TestStep(stepType, stepName, definition);
     }
 
     private Plc4xEmbeddedChannel getEmbeddedChannel(DriverTestsuite testSuite) {
@@ -282,19 +341,20 @@ public class DriverTestsuiteRunner {
             if(Message.class.isAssignableFrom(messageClass)) {
                 return (Class<? extends Message>) messageClass;
             }
-            throw new DriverTestsuiteException("IO class muss implement Message interface");
+            throw new DriverTestsuiteException("IO class must implement Message interface");
         } catch (ClassNotFoundException e) {
             throw new DriverTestsuiteException("Error loading message class", e);
         }
     }
 
-    private Class<? extends MessageIO> getMessageIOType(String messageClassName) throws DriverTestsuiteException {
+    @SuppressWarnings("unchecked")
+    private Class<? extends MessageIO<?,?>> getMessageIOType(String messageClassName) throws DriverTestsuiteException {
         String ioClassName = messageClassName.substring(0, messageClassName.lastIndexOf('.')) + ".io." +
             messageClassName.substring(messageClassName.lastIndexOf('.') + 1) + "IO";
         try {
             final Class<?> ioClass = Class.forName(ioClassName);
             if(MessageIO.class.isAssignableFrom(ioClass)) {
-                return (Class<? extends MessageIO>) ioClass;
+                return (Class<? extends MessageIO<?,?>>) ioClass;
             }
             throw new DriverTestsuiteException("IO class muss implement MessageIO interface");
         } catch (ClassNotFoundException e) {
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/Lalala.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/Lalala.java
new file mode 100644
index 0000000..d79a1d3
--- /dev/null
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/Lalala.java
@@ -0,0 +1,44 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+*/
+package org.apache.plc4x.test.driver;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import org.apache.plc4x.test.driver.model.api.TestField;
+import org.apache.plc4x.test.driver.model.api.TestReadRequest;
+import org.apache.plc4x.test.driver.model.api.TestRequest;
+
+public class Lalala {
+    public static void main(String[] args) throws Exception {
+        ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+
+        TestField[] testFields = new TestField[1];
+        testFields[0] = new TestField("hurz", "%Q0.0:BOOL");
+        TestRequest request = new TestReadRequest(testFields);
+
+        String xmlString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(request);
+
+        System.out.println(xmlString);
+
+        TestRequest newRequest = mapper.readValue(xmlString, TestRequest.class);
+
+        System.out.println(newRequest);
+    }
+
+}
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/DriverTestsuite.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/DriverTestsuite.java
index 8ee9dab..9c8d4a1 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/DriverTestsuite.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/DriverTestsuite.java
@@ -20,6 +20,7 @@ package org.apache.plc4x.test.driver.model;
 
 import org.apache.plc4x.java.api.PlcConnection;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 public class DriverTestsuite {
@@ -29,13 +30,16 @@ public class DriverTestsuite {
     private final List<TestStep> setupSteps;
     private final List<TestStep> teardownSteps;
     private final List<Testcase> testcases;
+    private final boolean bigEndian;
 
-    public DriverTestsuite(String name, PlcConnection connection, List<TestStep> setupSteps, List<TestStep> teardownSteps, List<Testcase> testcases) {
+    public DriverTestsuite(String name, PlcConnection connection, List<TestStep> setupSteps,
+                           List<TestStep> teardownSteps, List<Testcase> testcases, boolean bigEndian) {
         this.name = name;
         this.connection = connection;
         this.setupSteps = setupSteps;
         this.teardownSteps = teardownSteps;
         this.testcases = testcases;
+        this.bigEndian = bigEndian;
     }
 
     public String getName() {
@@ -58,4 +62,8 @@ public class DriverTestsuite {
         return testcases;
     }
 
+    public boolean isBigEndian() {
+        return bigEndian;
+    }
+
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/StepType.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/StepType.java
index 93d9f3f..c371331 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/StepType.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/StepType.java
@@ -36,6 +36,7 @@ public enum StepType {
     RECEIVE_PLC_BYTES,
     API_REQUEST,
     API_RESPONSE,
-    DELAY
+    DELAY,
+    TERMINATE
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
index 1e9e37d..0a44522 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
@@ -23,10 +23,12 @@ import org.dom4j.Element;
 public class TestStep {
 
     private final StepType type;
+    private final String name;
     private final Element payload;
 
-    public TestStep(StepType type, Element payload) {
+    public TestStep(StepType type, String name, Element payload) {
         this.type = type;
+        this.name = name;
         this.payload = payload;
     }
 
@@ -34,6 +36,10 @@ public class TestStep {
         return type;
     }
 
+    public String getName() {
+        return name;
+    }
+
     public Element getPayload() {
         return payload;
     }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestField.java
similarity index 52%
copy from plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
copy to plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestField.java
index 1e9e37d..03708ec 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestField.java
@@ -16,26 +16,30 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.test.driver.model;
+package org.apache.plc4x.test.driver.model.api;
 
-import org.dom4j.Element;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-public class TestStep {
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
+public class TestField {
 
-    private final StepType type;
-    private final Element payload;
+    private final String name;
+    private final String address;
 
-    public TestStep(StepType type, Element payload) {
-        this.type = type;
-        this.payload = payload;
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public TestField(@JsonProperty("name") String name, @JsonProperty("address") String address) {
+        this.name = name;
+        this.address = address;
     }
 
-    public StepType getType() {
-        return type;
+    public String getName() {
+        return name;
     }
 
-    public Element getPayload() {
-        return payload;
+    public String getAddress() {
+        return address;
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestFieldRequest.java
similarity index 66%
copy from plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
copy to plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestFieldRequest.java
index 1e9e37d..cf3dbf8 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestFieldRequest.java
@@ -16,26 +16,20 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.test.driver.model;
+package org.apache.plc4x.test.driver.model.api;
 
-import org.dom4j.Element;
+import com.fasterxml.jackson.annotation.JsonProperty;
 
-public class TestStep {
+public abstract class TestFieldRequest implements TestRequest {
 
-    private final StepType type;
-    private final Element payload;
+    private final TestField[] fields;
 
-    public TestStep(StepType type, Element payload) {
-        this.type = type;
-        this.payload = payload;
+    public TestFieldRequest(@JsonProperty("fields") TestField[] fields) {
+        this.fields = fields;
     }
 
-    public StepType getType() {
-        return type;
-    }
-
-    public Element getPayload() {
-        return payload;
+    public TestField[] getFields() {
+        return fields;
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestReadRequest.java
similarity index 59%
copy from plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
copy to plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestReadRequest.java
index 1e9e37d..f94c8fb 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestReadRequest.java
@@ -16,26 +16,18 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.test.driver.model;
+package org.apache.plc4x.test.driver.model.api;
 
-import org.dom4j.Element;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-public class TestStep {
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
+public class TestReadRequest extends TestFieldRequest {
 
-    private final StepType type;
-    private final Element payload;
-
-    public TestStep(StepType type, Element payload) {
-        this.type = type;
-        this.payload = payload;
-    }
-
-    public StepType getType() {
-        return type;
-    }
-
-    public Element getPayload() {
-        return payload;
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public TestReadRequest(@JsonProperty("fields") TestField[] fields) {
+        super(fields);
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestRequest.java
similarity index 65%
copy from plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
copy to plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestRequest.java
index 1e9e37d..c442d68 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestRequest.java
@@ -16,26 +16,10 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.test.driver.model;
+package org.apache.plc4x.test.driver.model.api;
 
-import org.dom4j.Element;
-
-public class TestStep {
-
-    private final StepType type;
-    private final Element payload;
-
-    public TestStep(StepType type, Element payload) {
-        this.type = type;
-        this.payload = payload;
-    }
-
-    public StepType getType() {
-        return type;
-    }
-
-    public Element getPayload() {
-        return payload;
-    }
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
+public interface TestRequest {
 }
diff --git a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestWriteRequest.java
similarity index 59%
copy from plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
copy to plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestWriteRequest.java
index 1e9e37d..bc3d217 100644
--- a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/TestStep.java
+++ b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/test/driver/model/api/TestWriteRequest.java
@@ -16,26 +16,18 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */
-package org.apache.plc4x.test.driver.model;
+package org.apache.plc4x.test.driver.model.api;
 
-import org.dom4j.Element;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
 
-public class TestStep {
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
+public class TestWriteRequest extends TestFieldRequest {
 
-    private final StepType type;
-    private final Element payload;
-
-    public TestStep(StepType type, Element payload) {
-        this.type = type;
-        this.payload = payload;
-    }
-
-    public StepType getType() {
-        return type;
-    }
-
-    public Element getPayload() {
-        return payload;
+    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
+    public TestWriteRequest(@JsonProperty("fields") TestField[] fields) {
+        super(fields);
     }
 
 }
diff --git a/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd b/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
index a97399d..7008c34 100644
--- a/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
+++ b/plc4j/utils/test-utils/src/main/resources/schemas/driver-testsuite.xsd
@@ -49,13 +49,14 @@
                     <xs:complexType>
                         <xs:sequence minOccurs="1" maxOccurs="unbounded">
                             <xs:choice>
-                                <xs:element name="send-plc-message" type="xs:anyType"/>
-                                <xs:element name="send-plc-bytes" type="xs:hexBinary"/>
-                                <xs:element name="receive-plc-message" type="xs:anyType"/>
-                                <xs:element name="receive-plc-bytes" type="xs:hexBinary"/>
-                                <xs:element name="api-request" type="xs:anyType"/>
-                                <xs:element name="api-response" type="xs:anyType"/>
+                                <xs:element name="send-plc-message" type="messageStep"/>
+                                <xs:element name="send-plc-bytes" type="bytesStep"/>
+                                <xs:element name="receive-plc-message" type="messageStep"/>
+                                <xs:element name="receive-plc-bytes" type="bytesStep"/>
+                                <xs:element name="api-request" type="messageStep"/>
+                                <xs:element name="api-response" type="messageStep"/>
                                 <xs:element name="delay" type="xs:integer"/>
+                                <xs:element name="terminate"/>
                             </xs:choice>
                         </xs:sequence>
                     </xs:complexType>
@@ -66,14 +67,15 @@
                     <xs:complexType>
                         <xs:sequence minOccurs="1" maxOccurs="unbounded">
                             <xs:choice>
-                                <xs:element name="send-plc-message" type="xs:anyType"/>
-                                <xs:element name="send-plc-bytes" type="xs:hexBinary"/>
-                                <xs:element name="receive-plc-message" type="xs:anyType"/>
-                                <xs:element name="receive-plc-bytes" type="xs:hexBinary"/>
-                                <xs:element name="api-request" type="xs:anyType"/>
-                                <xs:element name="api-response" type="xs:anyType"/>
+                                <xs:element name="send-plc-message" type="messageStep"/>
+                                <xs:element name="send-plc-bytes" type="bytesStep"/>
+                                <xs:element name="receive-plc-message" type="messageStep"/>
+                                <xs:element name="receive-plc-bytes" type="bytesStep"/>
+                                <xs:element name="api-request" type="messageStep"/>
+                                <xs:element name="api-response" type="messageStep"/>
                                 <xs:element name="delay" type="xs:integer"/>
-                            </xs:choice>
+                                <xs:element name="terminate"/>
+                           </xs:choice>
                         </xs:sequence>
                     </xs:complexType>
                 </xs:element>
@@ -90,13 +92,14 @@
                                 <xs:complexType>
                                     <xs:sequence minOccurs="1" maxOccurs="unbounded">
                                         <xs:choice>
-                                            <xs:element name="send-plc-message" type="xs:anyType"/>
-                                            <xs:element name="send-plc-bytes" type="xs:hexBinary"/>
-                                            <xs:element name="receive-plc-message" type="xs:anyType"/>
-                                            <xs:element name="receive-plc-bytes" type="xs:hexBinary"/>
-                                            <xs:element name="api-request" type="xs:anyType"/>
-                                            <xs:element name="api-response" type="xs:anyType"/>
+                                            <xs:element name="send-plc-message" type="messageStep"/>
+                                            <xs:element name="send-plc-bytes" type="bytesStep"/>
+                                            <xs:element name="receive-plc-message" type="messageStep"/>
+                                            <xs:element name="receive-plc-bytes" type="bytesStep"/>
+                                            <xs:element name="api-request" type="messageStep"/>
+                                            <xs:element name="api-response" type="messageStep"/>
                                             <xs:element name="delay" type="xs:integer"/>
+                                            <xs:element name="terminate"/>
                                         </xs:choice>
                                     </xs:sequence>
                                 </xs:complexType>
@@ -110,4 +113,20 @@
         </xs:complexType>
     </xs:element>
 
+    <xs:complexType name="messageStep">
+        <xs:simpleContent>
+            <xs:extension base="xs:anyType">
+                <xs:attribute name="name" type="xs:string"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="bytesStep">
+        <xs:simpleContent>
+            <xs:extension base="xs:hexBinary">
+                <xs:attribute name="name" type="xs:string"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
 </xs:schema>
\ No newline at end of file