You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by ld...@apache.org on 2024/08/06 15:04:50 UTC

(plc4x) 01/01: Switch opcua tests to test containers.

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

ldywicki pushed a commit to branch opcua-test-containers
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 4d8b6b1544a39c9e57281570104138792c9d596d
Author: Łukasz Dywicki <lu...@code-house.org>
AuthorDate: Tue Aug 6 17:04:29 2024 +0200

    Switch opcua tests to test containers.
    
    Checked in MiloTestContainer which creates on-the-fly container based on static configuration.
    
    Signed-off-by: Łukasz Dywicki <lu...@code-house.org>
---
 plc4j/drivers/opcua/pom.xml                        | 35 +++++++++++++
 .../apache/plc4x/java/opcua/MiloTestContainer.java | 49 +++++++++++++++++++
 .../plc4x/java/opcua/OpcuaPlcDriverTest.java       | 57 ++++++++++++++--------
 .../milo/examples/server/TestMiloServer.java       | 33 +++++++++++++
 4 files changed, 154 insertions(+), 20 deletions(-)

diff --git a/plc4j/drivers/opcua/pom.xml b/plc4j/drivers/opcua/pom.xml
index 85e3868183..79999ee96e 100644
--- a/plc4j/drivers/opcua/pom.xml
+++ b/plc4j/drivers/opcua/pom.xml
@@ -69,6 +69,23 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>copy-milo-dependencies</id>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <phase>test-compile</phase>
+            <configuration>
+              <includeArtifactIds>server-examples</includeArtifactIds>
+              <outputDirectory>${project.build.directory}/milo-testcontainer</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
       <plugin>
         <groupId>org.apache.felix</groupId>
         <artifactId>maven-bundle-plugin</artifactId>
@@ -186,6 +203,24 @@
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.testcontainers</groupId>
+      <artifactId>testcontainers</artifactId>
+      <version>1.20.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.testcontainers</groupId>
+      <artifactId>junit-jupiter</artifactId>
+      <version>1.20.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.cloud.tools</groupId>
+      <artifactId>jib-core</artifactId>
+      <version>0.22.0</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <dependencyManagement>
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java
new file mode 100644
index 0000000000..d22f448bf4
--- /dev/null
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/MiloTestContainer.java
@@ -0,0 +1,49 @@
+/*
+ * 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.java.opcua;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+
+public class MiloTestContainer extends GenericContainer<MiloTestContainer> {
+
+    private final static Logger logger = LoggerFactory.getLogger(MiloTestContainer.class);
+
+    public MiloTestContainer() {
+        super(inlineImage());
+
+        waitingFor(Wait.forLogMessage("Server started\\s*", 1));
+        addFixedExposedPort(12686, 12686);
+    }
+
+    private static ImageFromDockerfile inlineImage() {
+        Path absolutePath = Paths.get(".").toAbsolutePath();
+        logger.info("Building milo server image from {}", absolutePath);
+        return new ImageFromDockerfile("plc4x-milo-test", false)
+            .withBuildImageCmdModifier(cmd -> cmd.withNoCache(true))
+            .withDockerfile(absolutePath.resolve("Dockerfile.test"));
+    }
+
+}
diff --git a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
index 2b32e12cd6..78dc4b0dad 100644
--- a/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
+++ b/plc4j/drivers/opcua/src/test/java/org/apache/plc4x/java/opcua/OpcuaPlcDriverTest.java
@@ -62,17 +62,29 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.concurrent.ExecutionException;
 import java.util.stream.Stream;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.images.builder.ImageFromDockerfile;
+import org.testcontainers.jib.JibImage;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
 
 import static java.util.Map.entry;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 
+@Testcontainers
 @DisableOnJenkinsFlag
-@Disabled("This test regularly fails the build, it needs to be generally fixed.")
 public class OpcuaPlcDriverTest {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(OpcuaPlcDriverTest.class);
 
+    @Container
+    public static final GenericContainer milo = new MiloTestContainer()
+        //.withCreateContainerCmdModifier(cmd -> cmd.withHostName("test-opcua-server"))
+        .withReuse(true);
+
     // Read only variables of milo example server of version 3.6
     private static final String BOOL_IDENTIFIER_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Boolean";
     private static final String BYTE_IDENTIFIER_READ_WRITE = "ns=2;s=HelloWorld/ScalarTypes/Byte";
@@ -123,50 +135,55 @@ public class OpcuaPlcDriverTest {
     //Restricted
     public static final String STRING_IDENTIFIER_ONLY_ADMIN_READ_WRITE = "ns=2;s=HelloWorld/OnlyAdminCanRead/String";
 
-    // Address of local milo server
-    private final String miloLocalAddress = "127.0.0.1:12686/milo";
+    // Address of local milo server, since it comes from test container its hostname and port is not static
+    private final String miloLocalAddress = "%s:%d/milo";
     //Tcp pattern of OPC UA
     private final String opcPattern = "opcua:tcp://";
 
     private final String paramSectionDivider = "?";
     private final String paramDivider = "&";
 
-    private final String tcpConnectionAddress = opcPattern + miloLocalAddress;
-
-    private final List<String> connectionStringValidSet = List.of(tcpConnectionAddress);
-    private final List<String> connectionStringCorruptedSet = List.of();
-
     private final String discoveryValidParamTrue = "discovery=true";
     private final String discoveryValidParamFalse = "discovery=false";
     private final String discoveryCorruptedParamWrongValueNum = "discovery=1";
     private final String discoveryCorruptedParamWrongName = "diskovery=false";
 
+    private String tcpConnectionAddress;
+    private List<String> connectionStringValidSet;
+
     final List<String> discoveryParamValidSet = List.of(discoveryValidParamTrue, discoveryValidParamFalse);
     List<String> discoveryParamCorruptedSet = List.of(discoveryCorruptedParamWrongValueNum, discoveryCorruptedParamWrongName);
 
     private static TestMiloServer exampleServer;
 
+    @BeforeEach
+    public void startUp() {
+        //System.out.println(milo.getMappedPort(12686));
+        tcpConnectionAddress = String.format(opcPattern + miloLocalAddress, milo.getHost(), milo.getMappedPort(12686));
+        connectionStringValidSet = List.of(tcpConnectionAddress);
+    }
+
     @BeforeAll
     public static void setup() throws Exception {
         // When switching JDK versions from a newer to an older version,
         // this can cause the server to not start correctly.
         // Deleting the directory makes sure the key-store is initialized correctly.
-        Path securityBaseDir = Paths.get(System.getProperty("java.io.tmpdir"), "server", "security");
-        try {
-            Files.delete(securityBaseDir);
-        } catch (Exception e) {
-            // Ignore this ...
-        }
-
-        exampleServer = new TestMiloServer();
-        exampleServer.startup().get();
+//        Path securityBaseDir = Paths.get(System.getProperty("java.io.tmpdir"), "server", "security");
+//        try {
+//            Files.delete(securityBaseDir);
+//        } catch (Exception e) {
+//            // Ignore this ...
+//        }
+//
+//        exampleServer = new TestMiloServer();
+//        exampleServer.startup().get();
     }
 
     @AfterAll
     public static void tearDown() throws Exception {
-        if (exampleServer != null) {
-            exampleServer.shutdown().get();
-        }
+//        if (exampleServer != null) {
+//            exampleServer.shutdown().get();
+//        }
     }
 
     @Nested
diff --git a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java b/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java
index 3925866140..872afbfb0f 100644
--- a/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java
+++ b/plc4j/drivers/opcua/src/test/java/org/eclipse/milo/examples/server/TestMiloServer.java
@@ -28,12 +28,17 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.KeyPair;
+import java.security.Security;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
 import org.eclipse.milo.opcua.sdk.server.api.config.OpcUaServerConfig;
 import org.eclipse.milo.opcua.sdk.server.identity.CompositeValidator;
@@ -52,6 +57,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
 import org.eclipse.milo.opcua.stack.core.types.enumerated.MessageSecurityMode;
 import org.eclipse.milo.opcua.stack.core.types.structured.BuildInfo;
 import org.eclipse.milo.opcua.stack.core.util.CertificateUtil;
+import org.eclipse.milo.opcua.stack.core.util.NonceUtil;
 import org.eclipse.milo.opcua.stack.core.util.SelfSignedCertificateGenerator;
 import org.eclipse.milo.opcua.stack.core.util.SelfSignedHttpsCertificateBuilder;
 import org.eclipse.milo.opcua.stack.server.EndpointConfiguration;
@@ -69,6 +75,32 @@ public class TestMiloServer {
     private final OpcUaServer server;
     private final ExampleNamespace exampleNamespace;
 
+    static {
+        // Required for SecurityPolicy.Aes256_Sha256_RsaPss
+        Security.addProvider(new BouncyCastleProvider());
+
+        try {
+            NonceUtil.blockUntilSecureRandomSeeded(10, TimeUnit.SECONDS);
+        } catch (ExecutionException | InterruptedException | TimeoutException e) {
+            e.printStackTrace();
+            System.exit(-1);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        TestMiloServer server = new TestMiloServer();
+
+        server.startup().thenAccept(srv -> {
+            System.out.println("Server started");
+        }).get();
+
+        final CompletableFuture<Void> future = new CompletableFuture<>();
+
+        Runtime.getRuntime().addShutdownHook(new Thread(() -> future.complete(null)));
+
+        future.get();
+    }
+
     public TestMiloServer() throws Exception {
         Path securityTempDir = Paths.get(System.getProperty("java.io.tmpdir"), "server", "security");
         Files.createDirectories(securityTempDir);
@@ -168,6 +200,7 @@ public class TestMiloServer {
         bindAddresses.add("0.0.0.0");
 
         Set<String> hostnames = new LinkedHashSet<>();
+        hostnames.add("localhost");
         hostnames.add(HostnameUtil.getHostname());
         hostnames.addAll(HostnameUtil.getHostnames("0.0.0.0"));