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/27 07:34:27 UTC

[plc4x] branch feature/driver-testsuite updated: - Some further updates on the driver feature/driver-testsuite -- Renamed the xml constants (hopefully more intuitive) -- Streamlined the DriverTestsuiteRunner code

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


The following commit(s) were added to refs/heads/feature/driver-testsuite by this push:
     new f821ccb  - Some further updates on the driver feature/driver-testsuite -- Renamed the xml constants (hopefully more intuitive) -- Streamlined the DriverTestsuiteRunner code
f821ccb is described below

commit f821ccb279ddbb9bd43b76cc3a6c56ea0c588cc3
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Thu Feb 27 08:34:18 2020 +0100

    - Some further updates on the driver feature/driver-testsuite
    -- Renamed the xml constants (hopefully more intuitive)
    -- Streamlined the DriverTestsuiteRunner code
---
 .../test/resources/testsuite/S7DriverTestsuite.xml |  50 +++---
 .../plc4x/test/driver/DriverTestsuiteRunner.java   | 190 ++++++++++++---------
 .../apache/plc4x/test/driver/model/StepType.java   |   8 +-
 .../main/resources/schemas/driver-testsuite.xsd    |  24 +--
 4 files changed, 159 insertions(+), 113 deletions(-)

diff --git a/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml b/plc4j/drivers/s7/src/test/resources/testsuite/S7DriverTestsuite.xml
index 015d5cd..28bd370 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 name="Send COTP Connection Request">
+    <outgoing-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>
@@ -46,9 +46,9 @@
           <protocolClass>CLASS_0</protocolClass>
         </payload>
       </TPKTPacket>
-    </send-plc-message>
+    </outgoing-plc-message>
     <!-- The PLC will send a COTP connection response -->
-    <receive-plc-message name="Receive COTP Connection Response">
+    <incoming-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>
@@ -68,9 +68,9 @@
           <protocolClass>CLASS_0</protocolClass>
         </payload>
       </TPKTPacket>
-    </receive-plc-message>
+    </incoming-plc-message>
     <!-- After that the driver will send a S7 connection request -->
-    <send-plc-message name="Send S7 Connection Request">
+    <outgoing-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/>
@@ -87,9 +87,9 @@
           <tpduRef>1</tpduRef>
         </payload>
       </TPKTPacket>
-    </send-plc-message>
+    </outgoing-plc-message>
     <!-- The PLC will send a S7 connection response -->
-    <receive-plc-message name="Receive S7 Connection Response">
+    <incoming-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/>
@@ -108,9 +108,9 @@
           <tpduRef>0</tpduRef>
         </payload>
       </TPKTPacket>
-    </receive-plc-message>
+    </incoming-plc-message>
     <!-- Next we'll query some type information -->
-    <send-plc-message name="Send S7 Identification Request">
+    <outgoing-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/>
@@ -149,9 +149,9 @@
           <tpduRef>2</tpduRef>
         </payload>
       </TPKTPacket>
-    </send-plc-message>
+    </outgoing-plc-message>
     <!-- Which the PLC will gladly provide to us -->
-    <receive-plc-message name="Receive S7 Identification Response">
+    <incoming-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/>
@@ -213,13 +213,13 @@
           <tpduRef>0</tpduRef>
         </payload>
       </TPKTPacket>
-    </receive-plc-message>
+    </incoming-plc-message>
   </setup>
 
   <testcase>
     <name>Single element read request</name>
     <steps>
-      <api-request name="Send Read Request">
+      <api-request name="Receive Read Request from application">
         <TestReadRequest className="org.apache.plc4x.test.driver.model.api.TestReadRequest">
           <fields>
             <field className="org.apache.plc4x.test.driver.model.api.TestField">
@@ -227,8 +227,9 @@
               <address>%Q0.0:BOOL</address>
             </field>
           </fields>
-        </TestReadRequest>      </api-request>
-      <send-plc-message name="Send S7 Read Request">
+        </TestReadRequest>
+      </api-request>
+      <outgoing-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/>
@@ -254,8 +255,8 @@
             <tpduRef>10</tpduRef>
           </payload>
         </TPKTPacket>
-      </send-plc-message>
-      <receive-plc-message name="Receive S7 Read Response">
+      </outgoing-plc-message>
+      <incoming-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/>
@@ -281,10 +282,17 @@
             <tpduRef>0</tpduRef>
           </payload>
         </TPKTPacket>
-      </receive-plc-message>
-      <!--api-response-message>
-
-      </api-response-message-->
+      </incoming-plc-message>
+      <api-response name="Report Read Response to application">
+        <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-response>
       <delay>1000</delay>
     </steps>
   </testcase>
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 ab378ad..85d872c 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
@@ -18,6 +18,7 @@ under the License.
 */
 package org.apache.plc4x.test.driver;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import io.netty.buffer.ByteBuf;
@@ -29,6 +30,7 @@ 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.api.messages.PlcResponse;
 import org.apache.plc4x.java.spi.connection.ChannelExposingConnection;
 import org.apache.plc4x.java.spi.connection.GeneratedDriverBase;
 import org.apache.plc4x.java.spi.generation.*;
@@ -56,6 +58,7 @@ import org.xmlunit.diff.Diff;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
 public class DriverTestsuiteRunner {
@@ -64,6 +67,8 @@ public class DriverTestsuiteRunner {
 
     private final String testsuiteDocument;
 
+    private CompletableFuture<? extends PlcResponse> responseFuture;
+
     public DriverTestsuiteRunner(String testsuiteDocument) {
         this.testsuiteDocument = testsuiteDocument;
     }
@@ -196,72 +201,35 @@ public class DriverTestsuiteRunner {
     }
 
     private void executeStep(TestStep testStep, PlcConnection plcConnection, Plc4xEmbeddedChannel embeddedChannel, boolean bigEndian) throws DriverTestsuiteException {
-        LOGGER.info("  - Running step: '" + testStep.getName() + "' - " + testStep.getType());
+        LOGGER.info(String.format("  - Running step: '%s' - %s", testStep.getName(), testStep.getType()));
         final ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
         final Element payload = testStep.getPayload();
         try {
             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.
-
+                case OUTGOING_PLC_BYTES: {
+                    // As we're in the asynchronous world, give the driver some time to respond.
+                    shortDelay();
+                    // Prepare a ByteBuf that contains the data which would have been sent to the PLC.
+                    final byte[] data = getOutboundBytes(embeddedChannel);
+                    // Validate the data actually matches the expected message.
+                    validateBytes(payload, data, bigEndian);
                     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();
-                    if(byteBuf == null) {
-                        throw new DriverTestsuiteException("No outbound message available");
-                    }
-                    final byte[] data = new byte[byteBuf.readableBytes()];
-                    byteBuf.readBytes(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);
-                        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());
-                        }
-                    } catch (ParseException e) {
-                        throw new DriverTestsuiteException("Error parsing message", e);
-                    }
+                case OUTGOING_PLC_MESSAGE: {
+                    // As we're in the asynchronous world, give the driver some time to respond.
+                    shortDelay();
+                    // Prepare a ByteBuf that contains the data which would have been sent to the PLC.
+                    final byte[] data = getOutboundBytes(embeddedChannel);
+                    // Validate the data actually matches the expected message.
+                    validateMessage(payload, data, bigEndian);
                     break;
                 }
-                case RECEIVE_PLC_BYTES: {
-                    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));
-                    final WriteBuffer writeBuffer = new WriteBuffer(1024, !bigEndian);
-                    try {
-                        messageIO.serialize(writeBuffer, message);
-                        final byte[] data = new byte[writeBuffer.getPos()];
-                        System.arraycopy(writeBuffer.getData(), 0, data, 0, writeBuffer.getPos());
-                        embeddedChannel.writeInbound(Unpooled.wrappedBuffer(data));
-                    } catch (ParseException e) {
-                        throw new DriverTestsuiteException("Error serializing message", e);
-                    }
+                case INCOMING_PLC_BYTES:
+                case INCOMING_PLC_MESSAGE: {
+                    // Get a byte representation of the incoming message.
+                    final byte[] data = getBytesFromXml(payload, bigEndian);
+                    // Send the bytes to the channel.
+                    embeddedChannel.writeInbound(Unpooled.wrappedBuffer(data));
                     break;
                 }
                 case API_REQUEST: {
@@ -274,30 +242,34 @@ public class DriverTestsuiteRunner {
                             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());
-                            }
-                        });
+                        // Currently we can only process one response at at time, throw an error if more
+                        // are submitted.
+                        if(responseFuture != null) {
+                            throw new DriverTestsuiteException("Previous response not handled.");
+                        }
+                        // Save the response for being used later on.
+                        responseFuture = plc4xRequest.execute();
                     } else if(request instanceof TestWriteRequest) {
-
+                        // TODO: Implement ...
                     }
                     break;
                 }
                 case API_RESPONSE: {
+                    if(responseFuture == null) {
+                        throw new DriverTestsuiteException("No response expected.");
+                    }
+                    try {
+                        final PlcResponse plcResponse = responseFuture.get(1000, TimeUnit.MILLISECONDS);
+                        // TODO: Implement ...
+                        final String serializedResponse = mapper.writeValueAsString(plcResponse);
+                        System.out.println(serializedResponse);
+                    } catch(Exception e) {
+                        throw new DriverTestsuiteException("Got no response within 1000ms.");
+                    }
                     break;
                 }
                 case DELAY: {
-                    try {
-                        TimeUnit.MILLISECONDS.sleep(1000);
-                    } catch (InterruptedException e) {
-                        Thread.currentThread().interrupt();
-                        throw new DriverTestsuiteException("Interrupted during delay.");
-                    }
+                    delay(1000);
                     break;
                 }
                 case TERMINATE: {
@@ -306,8 +278,6 @@ public class DriverTestsuiteRunner {
             }
         } catch (IOException e) {
             throw new DriverTestsuiteException("Error processing the xml", e);
-        } catch (IllegalAccessException | InstantiationException e) {
-            throw new DriverTestsuiteException("Error instantiating MessageIO class", e);
         }
         LOGGER.info("    Done");
     }
@@ -335,6 +305,7 @@ public class DriverTestsuiteRunner {
         throw new PlcRuntimeException("Expecting ChannelExposingConnection");
     }
 
+    @SuppressWarnings("unchecked")
     private Class<? extends Message> getMessageType(String messageClassName) throws DriverTestsuiteException {
         try {
             final Class<?> messageClass = Class.forName(messageClassName);
@@ -362,4 +333,71 @@ public class DriverTestsuiteRunner {
         }
     }
 
+    private byte[] getOutboundBytes(Plc4xEmbeddedChannel embeddedChannel) throws DriverTestsuiteException {
+        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);
+        return data;
+    }
+
+    private byte[] getBytesFromXml(Element referenceXml, boolean bigEndian) throws DriverTestsuiteException {
+        final String className = referenceXml.attributeValue(new QName("className"));
+        final WriteBuffer writeBuffer = new WriteBuffer(1024, !bigEndian);
+        try {
+            final MessageIO messageIO = getMessageIOType(className).newInstance();
+            final String referenceXmlString = referenceXml.asXML();
+            final ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+            final Message message = mapper.readValue(referenceXmlString, getMessageType(className));
+            try {
+                messageIO.serialize(writeBuffer, message);
+                final byte[] data = new byte[message.getLengthInBytes()];
+                System.arraycopy(writeBuffer.getData(), 0, data, 0, writeBuffer.getPos());
+                return data;
+            } catch (ParseException e) {
+                throw new DriverTestsuiteException("Error serializing message", e);
+            }
+        } catch (IllegalAccessException | JsonProcessingException | InstantiationException e) {
+            throw new DriverTestsuiteException("Error parsing message", e);
+        }
+    }
+
+    private void validateBytes(Element referenceXml, byte[] data, boolean bigEndian) throws DriverTestsuiteException {
+        // TODO: Implement this ...
+    }
+
+    private void validateMessage(Element referenceXml, byte[] data, boolean bigEndian) throws DriverTestsuiteException {
+        final ObjectMapper mapper = new XmlMapper().enableDefaultTyping();
+        final ReadBuffer readBuffer = new ReadBuffer(data, !bigEndian);
+        try {
+            final String className = referenceXml.attributeValue(new QName("className"));
+            final MessageIO<?,?> messageIO = getMessageIOType(className).newInstance();
+            final Object parsedOutput = messageIO.parse(readBuffer);
+            final String xmlString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(parsedOutput);
+            final String referenceXmlString = referenceXml.asXML();
+            final Diff diff = DiffBuilder.compare(referenceXmlString).withTest(xmlString).ignoreComments().ignoreWhitespace().build();
+            if (diff.hasDifferences()) {
+                LOGGER.warn(xmlString);
+                throw new DriverTestsuiteException("Differences were found after parsing.\n" + diff.toString());
+            }
+        } catch (ParseException | IllegalAccessException | JsonProcessingException | InstantiationException e) {
+            throw new DriverTestsuiteException("Error parsing message", e);
+        }
+    }
+
+    private void shortDelay() throws DriverTestsuiteException {
+        delay(23);
+    }
+
+    private void delay(int milliseconds) throws DriverTestsuiteException {
+        try {
+            TimeUnit.MILLISECONDS.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new DriverTestsuiteException("Interrupted during delay.");
+        }
+    }
+
 }
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 c371331..374a2f8 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
@@ -30,10 +30,10 @@ public enum StepType {
         API_RESPONSE:                               -------->
      */
 
-    SEND_PLC_MESSAGE,
-    SEND_PLC_BYTES,
-    RECEIVE_PLC_MESSAGE,
-    RECEIVE_PLC_BYTES,
+    OUTGOING_PLC_MESSAGE,
+    OUTGOING_PLC_BYTES,
+    INCOMING_PLC_MESSAGE,
+    INCOMING_PLC_BYTES,
     API_REQUEST,
     API_RESPONSE,
     DELAY,
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 7008c34..a9576ae 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,10 +49,10 @@
                     <xs:complexType>
                         <xs:sequence minOccurs="1" maxOccurs="unbounded">
                             <xs:choice>
-                                <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="outgoing-plc-message" type="messageStep"/>
+                                <xs:element name="outgoing-plc-bytes" type="bytesStep"/>
+                                <xs:element name="incoming-plc-message" type="messageStep"/>
+                                <xs:element name="incoming-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"/>
@@ -67,10 +67,10 @@
                     <xs:complexType>
                         <xs:sequence minOccurs="1" maxOccurs="unbounded">
                             <xs:choice>
-                                <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="outgoing-plc-message" type="messageStep"/>
+                                <xs:element name="outgoing-plc-bytes" type="bytesStep"/>
+                                <xs:element name="incoming-plc-message" type="messageStep"/>
+                                <xs:element name="incoming-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"/>
@@ -92,10 +92,10 @@
                                 <xs:complexType>
                                     <xs:sequence minOccurs="1" maxOccurs="unbounded">
                                         <xs:choice>
-                                            <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="outgoing-plc-message" type="messageStep"/>
+                                            <xs:element name="outgoing-plc-bytes" type="bytesStep"/>
+                                            <xs:element name="incoming-plc-message" type="messageStep"/>
+                                            <xs:element name="incoming-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"/>