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

chrisdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new aaeb887e3e fix: Refactored the handling of PCAP on windows differently 
as it was multiple modules affected.
aaeb887e3e is described below

commit aaeb887e3ea685532e5f10c9d1a43875a97b1147
Author: Christofer Dutz <[email protected]>
AuthorDate: Fri Jun 12 17:58:56 2026 +0200

    fix: Refactored the handling of PCAP on windows differently as it was 
multiple modules affected.
---
 plc4j/transports/pcap-replay/pom.xml               |  7 ++
 .../transport/pcapreplay/PcapFilePlayerTest.java   | 23 ++----
 .../PcapReplayTransportInstanceTest.java           | 26 +++----
 .../pcapreplay/PcapReplayTransportTest.java        | 21 ++----
 plc4j/transports/raw-socket/pom.xml                |  7 ++
 .../java/transport/rawsocket/PcapTestSupport.java  | 84 ----------------------
 .../rawsocket/RawSocketTransportInstanceTest.java  | 13 ++--
 .../rawsocket/RawSocketTransportTest.java          | 32 ++++++---
 .../rawsocket/SharedRawSocketManagerTest.java      | 13 +++-
 .../java/utils/testutils/RequirePcapCondition.java | 30 ++++++--
 10 files changed, 98 insertions(+), 158 deletions(-)

diff --git a/plc4j/transports/pcap-replay/pom.xml 
b/plc4j/transports/pcap-replay/pom.xml
index 537fa3a984..5ec8982f8b 100644
--- a/plc4j/transports/pcap-replay/pom.xml
+++ b/plc4j/transports/pcap-replay/pom.xml
@@ -74,6 +74,13 @@
     </dependency>
 
     <!-- Test Dependencies -->
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-test-utils</artifactId>
+      <version>0.14.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
diff --git 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapFilePlayerTest.java
 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapFilePlayerTest.java
index c4397eed63..7dbbfc239d 100644
--- 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapFilePlayerTest.java
+++ 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapFilePlayerTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.plc4x.java.transport.pcapreplay;
 
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
@@ -26,14 +27,17 @@ import org.pcap4j.packet.factory.PacketFactories;
 import org.pcap4j.packet.namednumber.DataLinkType;
 import org.pcap4j.util.MacAddress;
 
-import java.io.File;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * Tests for PcapFilePlayer.
+ * <p>
+ * Every test here drives real pcap playback, so the whole class is skipped 
when the pcap
+ * native library can't be loaded (e.g. on Windows CI without Npcap installed).
  */
+@RequirePcap
 class PcapFilePlayerTest {
 
     private PcapFilePlayer player;
@@ -50,23 +54,6 @@ class PcapFilePlayerTest {
 
     @BeforeEach
     void setUp() {
-        try {
-            // For some reason it doesn't work if we pass this in from the 
outside.
-            //if (os == "mac") {
-            // On my Intel Mac I found the libs in: 
"/usr/local/Cellar/libpcap/1.10.1/lib"
-            // On my M1 Mac I found the libs in: 
"/opt/homebrew/Cellar/libpcap/1.10.1/lib"
-            if (new File("/usr/local/Cellar/libpcap/1.10.1/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.1/lib");
-            } else if (new 
File("/usr/local/Cellar/libpcap/1.10.5/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.5/lib");
-            } else if (new File("/opt/homebrew/opt/libpcap/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/opt/homebrew/opt/libpcap/lib");
-            }
-            //}
-        } catch (Error e) {
-            e.printStackTrace();
-        }
-
         localMac = MacAddress.getByName("00:11:22:33:44:55");
         remoteMac = MacAddress.getByName("AA:BB:CC:DD:EE:FF");
     }
diff --git 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportInstanceTest.java
 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportInstanceTest.java
index b3310f01bb..dda491fae3 100644
--- 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportInstanceTest.java
+++ 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportInstanceTest.java
@@ -21,12 +21,12 @@ package org.apache.plc4x.java.transport.pcapreplay;
 import org.apache.plc4x.java.spi.transports.api.exceptions.TransportException;
 import 
org.apache.plc4x.java.transport.pcapreplay.config.PcapReplayTransportConfiguration;
 import org.apache.plc4x.java.utils.auditlog.api.AuditLog;
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.pcap4j.util.MacAddress;
 
-import java.io.File;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.jupiter.api.Assertions.*;
@@ -45,23 +45,6 @@ class PcapReplayTransportInstanceTest {
 
     @BeforeEach
     void setUp() throws TransportException {
-        try {
-            // For some reason it doesn't work if we pass this in from the 
outside.
-            //if (os == "mac") {
-            // On my Intel Mac I found the libs in: 
"/usr/local/Cellar/libpcap/1.10.1/lib"
-            // On my M1 Mac I found the libs in: 
"/opt/homebrew/Cellar/libpcap/1.10.1/lib"
-            if (new File("/usr/local/Cellar/libpcap/1.10.1/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.1/lib");
-            } else if (new 
File("/usr/local/Cellar/libpcap/1.10.5/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.5/lib");
-            } else if (new File("/opt/homebrew/opt/libpcap/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/opt/homebrew/opt/libpcap/lib");
-            }
-            //}
-        } catch (Error e) {
-            e.printStackTrace();
-        }
-
         // Create a mock player
         mockPlayer = mock(PcapFilePlayer.class);
         when(mockPlayer.isPlaying()).thenReturn(true);
@@ -423,6 +406,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testRead_withActualPcapPlayback() throws Exception {
         // Create a real player instance that uses test.pcap
         config.mockPlayer = null; // Use real player
@@ -448,6 +432,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testPeekReadableBytes_withActualData() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
@@ -469,6 +454,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testGetNumBytesAvailable_withRealPlayer() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
@@ -485,6 +471,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testStartStopReplay_withRealPlayer() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
@@ -507,6 +494,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testGetPacketsReplayed_withRealPlayer() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
@@ -546,6 +534,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testMultipleReadsInSequence() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
@@ -569,6 +558,7 @@ class PcapReplayTransportInstanceTest {
     }
 
     @Test
+    @RequirePcap
     void testRead_afterStoppingReplay() throws Exception {
         config.mockPlayer = null;
         config.pcapFile = "/test.pcap";
diff --git 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportTest.java
 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportTest.java
index 84e85eb90c..11438a1354 100644
--- 
a/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportTest.java
+++ 
b/plc4j/transports/pcap-replay/src/test/java/org/apache/plc4x/java/transport/pcapreplay/PcapReplayTransportTest.java
@@ -22,6 +22,7 @@ import 
org.apache.plc4x.java.spi.transports.api.TransportInstance;
 import org.apache.plc4x.java.spi.transports.api.exceptions.TransportException;
 import 
org.apache.plc4x.java.transport.pcapreplay.config.PcapReplayTransportConfiguration;
 import org.apache.plc4x.java.utils.auditlog.api.AuditLog;
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
@@ -49,23 +50,6 @@ class PcapReplayTransportTest {
 
     @BeforeEach
     void setUp() throws IOException {
-        try {
-            // For some reason it doesn't work if we pass this in from the 
outside.
-            //if (os == "mac") {
-            // On my Intel Mac I found the libs in: 
"/usr/local/Cellar/libpcap/1.10.1/lib"
-            // On my M1 Mac I found the libs in: 
"/opt/homebrew/Cellar/libpcap/1.10.1/lib"
-            if (new File("/usr/local/Cellar/libpcap/1.10.1/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.1/lib");
-            } else if (new 
File("/usr/local/Cellar/libpcap/1.10.5/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.5/lib");
-            } else if (new File("/opt/homebrew/opt/libpcap/lib").exists()) {
-                System.getProperties().setProperty("jna.library.path", 
"/opt/homebrew/opt/libpcap/lib");
-            }
-            //}
-        } catch (Error e) {
-            e.printStackTrace();
-        }
-
         transport = new PcapReplayTransport();
 
         // Create a minimal test PCAP file
@@ -145,6 +129,7 @@ class PcapReplayTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_withValidPcap() throws Exception {
         PcapReplayTransportConfiguration config = new 
PcapReplayTransportConfiguration();
         config.pcapFile = "/test.pcap";
@@ -166,6 +151,7 @@ class PcapReplayTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_withLoop() throws Exception {
         PcapReplayTransportConfiguration config = new 
PcapReplayTransportConfiguration();
         config.pcapFile = "/test.pcap";
@@ -187,6 +173,7 @@ class PcapReplayTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_onlyIncoming() throws Exception {
         PcapReplayTransportConfiguration config = new 
PcapReplayTransportConfiguration();
         config.pcapFile = "/test.pcap";
diff --git a/plc4j/transports/raw-socket/pom.xml 
b/plc4j/transports/raw-socket/pom.xml
index 924355f1dd..0f315cd4fd 100644
--- a/plc4j/transports/raw-socket/pom.xml
+++ b/plc4j/transports/raw-socket/pom.xml
@@ -70,6 +70,13 @@
     </dependency>
 
     <!-- Test Dependencies -->
+    <dependency>
+      <groupId>org.apache.plc4x</groupId>
+      <artifactId>plc4j-utils-test-utils</artifactId>
+      <version>0.14.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+
     <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
diff --git 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/PcapTestSupport.java
 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/PcapTestSupport.java
deleted file mode 100644
index ca7a8987bd..0000000000
--- 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/PcapTestSupport.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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
- *
- *   https://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.transport.rawsocket;
-
-import org.pcap4j.core.PcapNetworkInterface;
-import org.pcap4j.core.Pcaps;
-
-import java.io.File;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
-
-/**
- * Helper for the pcap-based tests.
- * <p>
- * The pcap4j native library (libpcap on *nix/macOS, wpcap.dll on Windows) is 
not
- * available on all CI nodes - notably Windows runners without WinPcap/Npcap 
installed.
- * When the native library can't be loaded, pcap4j fails by throwing {@link 
Error}s
- * (e.g. {@link NoClassDefFoundError} / {@link UnsatisfiedLinkError} /
- * {@link ExceptionInInitializerError}) rather than checked exceptions, so a 
plain
- * {@code catch (Exception ...)} doesn't skip the affected tests and the build 
fails.
- * These helpers translate any {@link Throwable} into a JUnit assumption so 
the tests
- * are skipped instead.
- */
-final class PcapTestSupport {
-
-    private PcapTestSupport() {
-    }
-
-    /**
-     * Points JNA at a libpcap installation in the well-known Homebrew 
locations on macOS.
-     * On other platforms this is a no-op and the default library resolution 
is used.
-     */
-    static void configureNativeLibraryPath() {
-        // For some reason it doesn't work if we pass this in from the outside.
-        // On an Intel Mac the libs are in: 
"/usr/local/Cellar/libpcap/<version>/lib"
-        // On an M1 Mac the libs are in: "/opt/homebrew/opt/libpcap/lib"
-        if (new File("/usr/local/Cellar/libpcap/1.10.1/lib").exists()) {
-            System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.1/lib");
-        } else if (new File("/usr/local/Cellar/libpcap/1.10.5/lib").exists()) {
-            System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.5/lib");
-        } else if (new File("/opt/homebrew/opt/libpcap/lib").exists()) {
-            System.getProperties().setProperty("jna.library.path", 
"/opt/homebrew/opt/libpcap/lib");
-        }
-    }
-
-    /**
-     * Returns the available pcap network interfaces, or aborts the current 
test (via a
-     * JUnit assumption) if pcap is unavailable - either because the native 
library could
-     * not be loaded or because no interfaces were found.
-     *
-     * @return the (non-empty) list of network interfaces
-     */
-    static List<PcapNetworkInterface> findAllDevsOrSkip() {
-        configureNativeLibraryPath();
-        List<PcapNetworkInterface> devs;
-        try {
-            devs = Pcaps.findAllDevs();
-        } catch (Throwable t) {
-            // Native library missing/unloadable (NoClassDefFoundError, 
UnsatisfiedLinkError, ...)
-            // or pcap permission issues - skip rather than fail.
-            assumeTrue(false, "pcap native library not available, skipping 
test: " + t);
-            throw new AssertionError("unreachable");
-        }
-        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
-        return devs;
-    }
-}
diff --git 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportInstanceTest.java
 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportInstanceTest.java
index df4a925966..6ec59f99e6 100644
--- 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportInstanceTest.java
+++ 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportInstanceTest.java
@@ -21,12 +21,14 @@ package org.apache.plc4x.java.transport.rawsocket;
 import org.apache.plc4x.java.spi.transports.api.exceptions.TransportException;
 import 
org.apache.plc4x.java.transport.rawsocket.config.RawSocketTransportConfiguration;
 import org.apache.plc4x.java.utils.auditlog.api.AuditLog;
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.pcap4j.core.PcapHandle;
 import org.pcap4j.core.PcapNetworkInterface;
+import org.pcap4j.core.Pcaps;
 import org.pcap4j.util.MacAddress;
 
 import java.util.List;
@@ -36,9 +38,11 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 /**
  * Tests for RawSocketTransportInstance.
- * Note: These tests require pcap permissions (root/admin) to run.
- * They use assumptions to skip when permissions are not enough.
+ * Note: These tests require the pcap native library (skipped via {@link 
RequirePcap} when
+ * absent, e.g. on Windows CI without Npcap) plus pcap permissions 
(root/admin); assumptions
+ * skip individual tests when permissions are not enough.
  */
+@RequirePcap
 class RawSocketTransportInstanceTest {
 
     private PcapHandle handle;
@@ -51,8 +55,9 @@ class RawSocketTransportInstanceTest {
     @BeforeEach
     void setUp() {
         try {
-            // Find available network interface (skips the test if pcap native 
libs are unavailable)
-            List<PcapNetworkInterface> devs = 
PcapTestSupport.findAllDevsOrSkip();
+            // Find available network interface
+            List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+            assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
             // Find an Ethernet-capable interface (not loopback, not tunnel)
             PcapNetworkInterface selectedNif = null;
diff --git 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportTest.java
 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportTest.java
index 6bc1d91f42..ef476d32a0 100644
--- 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportTest.java
+++ 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/RawSocketTransportTest.java
@@ -23,15 +23,18 @@ import 
org.apache.plc4x.java.spi.transports.api.config.TransportConfiguration;
 import org.apache.plc4x.java.spi.transports.api.exceptions.TransportException;
 import 
org.apache.plc4x.java.transport.rawsocket.config.RawSocketTransportConfiguration;
 import org.apache.plc4x.java.utils.auditlog.api.AuditLog;
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
 import org.pcap4j.core.PcapNetworkInterface;
+import org.pcap4j.core.Pcaps;
 
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 // Timeout prevents pcap operations from hanging the entire test suite
 @Timeout(value = 30, unit = TimeUnit.SECONDS)
@@ -41,7 +44,6 @@ class RawSocketTransportTest {
 
     @BeforeEach
     void setUp() {
-        PcapTestSupport.configureNativeLibraryPath();
         transport = new RawSocketTransport();
     }
 
@@ -61,9 +63,11 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_dedicated() throws Exception {
         // Skip if no network interfaces or no pcap permissions
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -89,8 +93,10 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_shared() throws Exception {
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -114,9 +120,11 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     //@Disabled("All of a sudden this test hangs ... investigate")
     void testCreateTransportInstance_multipleShared() throws Exception {
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -156,8 +164,10 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_withVLAN() throws Exception {
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -183,8 +193,10 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_withCustomBPF() throws Exception {
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -209,8 +221,10 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_promiscuousMode() throws Exception {
-        List<PcapNetworkInterface> devs = PcapTestSupport.findAllDevsOrSkip();
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
 
         PcapNetworkInterface nif = devs.get(0);
 
@@ -235,10 +249,8 @@ class RawSocketTransportTest {
     }
 
     @Test
+    @RequirePcap
     void testCreateTransportInstance_invalidInterface() {
-        // Constructing the instance reaches pcap's native layer, so skip when 
it's unavailable.
-        PcapTestSupport.findAllDevsOrSkip();
-
         RawSocketTransportConfiguration config = new 
RawSocketTransportConfiguration();
         config.interfaceName = "INVALID_INTERFACE_THAT_DOES_NOT_EXIST";
         config.remoteAddress = "00:00:00:00:00:01";
diff --git 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/SharedRawSocketManagerTest.java
 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/SharedRawSocketManagerTest.java
index e708ad382f..68ffd9fe43 100644
--- 
a/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/SharedRawSocketManagerTest.java
+++ 
b/plc4j/transports/raw-socket/src/test/java/org/apache/plc4x/java/transport/rawsocket/SharedRawSocketManagerTest.java
@@ -18,27 +18,34 @@
  */
 package org.apache.plc4x.java.transport.rawsocket;
 
+import org.apache.plc4x.java.utils.testutils.RequirePcap;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.pcap4j.core.PcapNetworkInterface;
+import org.pcap4j.core.Pcaps;
 
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
 /**
  * Tests for SharedRawSocketManager.
- * Note: These tests require pcap permissions to run.
+ * Note: These tests require the pcap native library (skipped via {@link 
RequirePcap} when
+ * absent, e.g. on Windows CI without Npcap) plus pcap permissions to run.
  */
+@RequirePcap
 class SharedRawSocketManagerTest {
 
     private SharedRawSocketManager manager;
     private PcapNetworkInterface testInterface;
 
     @BeforeEach
-    void setUp() {
+    void setUp() throws Exception {
         manager = new SharedRawSocketManager();
-        testInterface = PcapTestSupport.findAllDevsOrSkip().get(0);
+        List<PcapNetworkInterface> devs = Pcaps.findAllDevs();
+        assumeTrue(devs != null && !devs.isEmpty(), "No network interfaces 
found");
+        testInterface = devs.get(0);
     }
 
     @Test
diff --git 
a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/RequirePcapCondition.java
 
b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/RequirePcapCondition.java
index 21f12047ee..e3612ffef1 100644
--- 
a/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/RequirePcapCondition.java
+++ 
b/plc4j/utils/test-utils/src/main/java/org/apache/plc4x/java/utils/testutils/RequirePcapCondition.java
@@ -26,6 +26,7 @@ import org.pcap4j.core.Pcaps;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.File;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -35,6 +36,9 @@ public class RequirePcapCondition implements 
ExecutionCondition {
 
     @Override
     public ConditionEvaluationResult 
evaluateExecutionCondition(ExtensionContext extensionContext) {
+        // On macOS the bundled libpcap is too old, so point JNA at a 
Homebrew-installed one
+        // before the native bindings are first loaded.
+        configureMacOsLibraryPath();
         try {
             String libVersion = Pcaps.libVersion();
             Pattern pattern = Pattern.compile("^.*libpcap version 
(?<version>\\d+\\.\\d+(?:\\.\\d+)?)[^\\d]?.*$");
@@ -43,16 +47,34 @@ public class RequirePcapCondition implements 
ExecutionCondition {
                 String versionString = matcher.group("version");
                 return ConditionEvaluationResult.enabled("Found libpcap 
version " + versionString);
             }
-        } catch (Exception e) {
-            logger.info("Error detecting libpcap version.", e);
+            logger.info("Could not parse a libpcap version from '{}'", 
libVersion);
+        } catch (Throwable t) {
+            // A missing native library surfaces as an Error (e.g. 
NoClassDefFoundError /
+            // UnsatisfiedLinkError), not an Exception - so catch Throwable 
here, otherwise the
+            // whole annotated test class errors out instead of being cleanly 
disabled
+            // (e.g. on Windows CI without Npcap installed).
+            logger.info("Error detecting libpcap version.", t);
         }
         if (SystemUtils.IS_OS_WINDOWS) {
-            System.out.println("DISABLED-RequirePcapCondition");
             return ConditionEvaluationResult.disabled("Test disabled due to 
missing or invalid Npcap version. Please install from here: https://npcap.com/ 
as this version supports all needed features.");
         } else {
-            System.out.println("DISABLED-RequirePcapCondition");
             return ConditionEvaluationResult.disabled("Test disabled due to 
missing or invalid libpcap version. Please install at least version 1.1.0 to 
support all features.");
         }
     }
 
+    private static void configureMacOsLibraryPath() {
+        if (!SystemUtils.IS_OS_MAC) {
+            return;
+        }
+        // On an Intel Mac the libs are in: 
"/usr/local/Cellar/libpcap/<version>/lib"
+        // On an M1 Mac the libs are in: "/opt/homebrew/opt/libpcap/lib"
+        if (new File("/usr/local/Cellar/libpcap/1.10.1/lib").exists()) {
+            System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.1/lib");
+        } else if (new File("/usr/local/Cellar/libpcap/1.10.5/lib").exists()) {
+            System.getProperties().setProperty("jna.library.path", 
"/usr/local/Cellar/libpcap/1.10.5/lib");
+        } else if (new File("/opt/homebrew/opt/libpcap/lib").exists()) {
+            System.getProperties().setProperty("jna.library.path", 
"/opt/homebrew/opt/libpcap/lib");
+        }
+    }
+
 }

Reply via email to