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

apolovtsev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 4f16d3f39d0 IGNITE-27806 Fix network tests on Mac (#7574)
4f16d3f39d0 is described below

commit 4f16d3f39d0929e2b83dab2511ec398dda362e59
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Wed Feb 11 12:48:11 2026 +0200

    IGNITE-27806 Fix network tests on Mac (#7574)
---
 .../scalecube/ItMulticastNodeFinderTest.java       |  8 ++-
 .../internal/network/MulticastNodeFinder.java      | 75 ++++++++++++++--------
 .../internal/network/netty/NettyServerTest.java    |  3 +
 3 files changed, 55 insertions(+), 31 deletions(-)

diff --git 
a/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/scalecube/ItMulticastNodeFinderTest.java
 
b/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/scalecube/ItMulticastNodeFinderTest.java
index f4d2aa7afe6..e314eeb3a87 100644
--- 
a/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/scalecube/ItMulticastNodeFinderTest.java
+++ 
b/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/scalecube/ItMulticastNodeFinderTest.java
@@ -19,6 +19,7 @@ package org.apache.ignite.internal.network.scalecube;
 
 import static org.apache.ignite.internal.network.MulticastNodeFinder.MAX_TTL;
 import static 
org.apache.ignite.internal.network.MulticastNodeFinder.UNSPECIFIED_TTL;
+import static 
org.apache.ignite.internal.network.MulticastNodeFinder.isReservedMacOsInterface;
 import static 
org.apache.ignite.internal.network.utils.ClusterServiceTestUtils.clusterService;
 import static 
org.apache.ignite.internal.network.utils.ClusterServiceTestUtils.findLocalAddresses;
 import static 
org.apache.ignite.internal.testframework.matchers.CompletableFutureMatcher.willCompleteSuccessfully;
@@ -85,10 +86,10 @@ class ItMulticastNodeFinderTest extends IgniteAbstractTest {
         int nodeCount = 5;
         List<NetworkAddress> addresses = findLocalAddresses(INIT_PORT, 
INIT_PORT + nodeCount);
 
-        for (int i = 0; i < addresses.size(); i++) {
-            NodeFinder finder = startMulticastNodeFinder(addresses.get(i), 
ttl);
+        for (NetworkAddress address : addresses) {
+            NodeFinder finder = startMulticastNodeFinder(address, ttl);
             finders.add(finder);
-            services.add(startNetwork(addresses.get(i), finder));
+            services.add(startNetwork(address, finder));
         }
 
         for (ClusterService service : services) {
@@ -123,6 +124,7 @@ class ItMulticastNodeFinderTest extends IgniteAbstractTest {
 
     private static NodeFinder startMulticastNodeFinder(NetworkAddress addr, 
int ttl) throws SocketException {
         Set<NetworkAddress> addressesToAdvertise = 
NetworkInterface.networkInterfaces()
+                .filter(itf -> !isReservedMacOsInterface(itf))
                 .flatMap(NetworkInterface::inetAddresses)
                 .map(address -> new NetworkAddress(address.getHostName(), 
addr.port()))
                 .collect(Collectors.toUnmodifiableSet());
diff --git 
a/modules/network/src/main/java/org/apache/ignite/internal/network/MulticastNodeFinder.java
 
b/modules/network/src/main/java/org/apache/ignite/internal/network/MulticastNodeFinder.java
index 50bd8693e81..7cf4eee7969 100644
--- 
a/modules/network/src/main/java/org/apache/ignite/internal/network/MulticastNodeFinder.java
+++ 
b/modules/network/src/main/java/org/apache/ignite/internal/network/MulticastNodeFinder.java
@@ -131,7 +131,7 @@ public class MulticastNodeFinder implements NodeFinder {
     public Collection<NetworkAddress> findNodes() {
         Set<NetworkAddress> result = new HashSet<>();
 
-        // Creates multicast sockets for all eligible interfaces and an 
unbound socket. Will throw an exception if no sockets were created.
+        // Create sockets for sending discovery requests.
         List<MulticastSocket> sockets = createSockets(0, resultWaitMillis, 
false);
 
         ExecutorService executor = Executors.newFixedThreadPool(
@@ -140,12 +140,10 @@ public class MulticastNodeFinder implements NodeFinder {
         );
 
         try {
-            // Will contain nodes, found on all eligible interfaces and an 
unbound socket.
             List<CompletableFuture<Collection<NetworkAddress>>> futures = 
sockets.stream()
                     .map(socket -> supplyAsync(() -> findOnSocket(socket), 
executor))
                     .collect(toList());
 
-            // Collect results.
             for (CompletableFuture<Collection<NetworkAddress>> future : 
futures) {
                 try {
                     result.addAll(future.get(resultWaitMillis * REQ_ATTEMPTS * 
2L, TimeUnit.MILLISECONDS));
@@ -226,7 +224,9 @@ public class MulticastNodeFinder implements NodeFinder {
 
                             return false;
                         }
-                    }).collect(toSet());
+                    })
+                    .filter(itf -> !isReservedMacOsInterface(itf))
+                    .collect(toSet());
         } catch (SocketException e) {
             LOG.error("Error getting network interfaces for multicast node 
finder", e);
 
@@ -234,6 +234,17 @@ public class MulticastNodeFinder implements NodeFinder {
         }
     }
 
+    /**
+     * Returns {@code true} if the given network interface is a macOS-specfic 
interface.
+     *
+     * <p>These interfaces may support multicast but third-party applications 
may not be able to bind to them.
+     */
+    public static boolean isReservedMacOsInterface(NetworkInterface 
networkInterface) {
+        String name = networkInterface.getName();
+
+        return name.startsWith("llw") || name.startsWith("awdl") || 
name.startsWith("utun");
+    }
+
     @Override
     public void close() {
         stopped = true;
@@ -243,14 +254,10 @@ public class MulticastNodeFinder implements NodeFinder {
 
     @Override
     public void start() {
-        // Create multicast sockets for all eligible interfaces and an unbound 
socket. Will throw an exception if no sockets were created.
+        // Create sockets for listening to multicast requests.
         List<MulticastSocket> sockets = createSockets(multicastPort, 
POLLING_TIMEOUT_MILLIS, true);
 
-        if (sockets.isEmpty()) {
-            throw new IgniteInternalException(INTERNAL_ERR, "No sockets for 
multicast listener were created.");
-        }
-
-        listenerThreadPool.submit(() -> {
+        listenerThreadPool.execute(() -> {
             byte[] responseData = 
NetworkAddressesSerializer.serialize(addressesToAdvertise);
             byte[] requestBuffer = new byte[REQUEST_MESSAGE.length];
 
@@ -267,7 +274,7 @@ public class MulticastNodeFinder implements NodeFinder {
                         byte[] received = receiveDatagramData(socket, 
requestPacket);
 
                         if (!Arrays.equals(received, REQUEST_MESSAGE)) {
-                            LOG.error("Received unexpected request on 
multicast socket");
+                            LOG.error("Received unexpected request on 
multicast socket {}", socket.getLocalSocketAddress());
                             continue;
                         }
 
@@ -306,27 +313,29 @@ public class MulticastNodeFinder implements NodeFinder {
         List<MulticastSocket> sockets = new ArrayList<>();
 
         for (NetworkInterface networkInterface : 
getEligibleNetworkInterfaces()) {
-            addSocket(sockets, port, networkInterface, soTimeout, joinGroup);
+            MulticastSocket socket = createSocket(port, networkInterface, 
soTimeout, joinGroup);
 
-            if (joinGroup) {
-                LOG.info("Multicast listener socket created for interface: 
{}", networkInterface.getDisplayName());
-            } else {
-                LOG.info("Multicast node finder socket created for interface: 
{}", networkInterface.getDisplayName());
+            if (socket != null) {
+                sockets.add(socket);
             }
         }
 
-        addSocket(sockets, multicastPort, null, soTimeout, joinGroup);
-
+        // Use the unbound socket as a fallback.
         if (sockets.isEmpty()) {
-            throw new IgniteInternalException(INTERNAL_ERR, "No multicast 
sockets were created.");
+            MulticastSocket unboundSocket = createSocket(port, null, 
soTimeout, joinGroup);
+
+            if (unboundSocket == null) {
+                throw new IgniteInternalException(INTERNAL_ERR, "No multicast 
sockets were created.");
+            }
+
+            sockets.add(unboundSocket);
         }
 
         return sockets;
     }
 
-    /** Create socket, configure it with given parameters and add it to the 
given collection. */
-    private void addSocket(
-            Collection<MulticastSocket> sockets,
+    /** Creates a multicast socket and configures it with the given 
parameters. Returns {@code null} if a socket could not be created. */
+    private @Nullable MulticastSocket createSocket(
             int port,
             @Nullable NetworkInterface networkInterface,
             int soTimeout,
@@ -357,13 +366,19 @@ public class MulticastNodeFinder implements NodeFinder {
                 socket.joinGroup(multicastSocketAddress, networkInterface);
             }
 
-            sockets.add(socket);
-        } catch (IOException e) {
-            if (networkInterface != null) {
-                LOG.error("Failed to create multicast socket for interface 
{}", e, networkInterface.getName());
-            } else {
-                LOG.error("Failed to create multicast socket for an unbound 
interface", e);
+            if (LOG.isInfoEnabled()) {
+                if (joinGroup) {
+                    LOG.info("Multicast listener socket created: {}/{}", 
displayName(networkInterface), port);
+                } else {
+                    LOG.info("Multicast node finder socket created: {}", 
displayName(networkInterface));
+                }
             }
+
+            return socket;
+        } catch (IOException e) {
+            LOG.error("Failed to create multicast socket: {}/{}", e, 
displayName(networkInterface), port);
+
+            return null;
         }
     }
 
@@ -384,4 +399,8 @@ public class MulticastNodeFinder implements NodeFinder {
             LOG.error("Could not close multicast listeners", e);
         }
     }
+
+    private static String displayName(@Nullable NetworkInterface 
networkInterface) {
+        return networkInterface != null ? networkInterface.getDisplayName() : 
"unbound";
+    }
 }
diff --git 
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyServerTest.java
 
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyServerTest.java
index 6e3beff664c..91aa32d05c4 100644
--- 
a/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyServerTest.java
+++ 
b/modules/network/src/test/java/org/apache/ignite/internal/network/netty/NettyServerTest.java
@@ -72,6 +72,8 @@ import 
org.apache.ignite.internal.network.serialization.UserObjectSerializationC
 import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
@@ -162,6 +164,7 @@ public class NettyServerTest extends BaseIgniteAbstractTest 
{
     /**
      * Tests that bootstrap tries to bind to address specified in 
configuration.
      */
+    @DisabledOnOs(value = OS.MAC, disabledReason = "On MAC the target address 
is not a loopback address.")
     @Test
     public void testBindWithAddress() {
         String host = "127.0.0.7";

Reply via email to