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

cadonna pushed a commit to branch 4.0
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/4.0 by this push:
     new 743a2a3fc2e KAFKA-18546: Use mocks instead of a real DNS lookup to the 
outside (#18565)
743a2a3fc2e is described below

commit 743a2a3fc2e3e17f7b41b7733e0c26c58b726be2
Author: Bruno Cadonna <cado...@apache.org>
AuthorDate: Thu Jan 16 16:18:44 2025 +0100

    KAFKA-18546: Use mocks instead of a real DNS lookup to the outside (#18565)
    
    Since the example.com DNS lookup changed the second time within one
    year, we rewrote the unit tests for ClientUtils so that they do
    not make a real DNS lookup to the outside but use mocks.
    
    Reviewers: PoAn Yang <pay...@apache.org>, Chia-Ping Tsai 
<chia7...@gmail.com>, Lianet Magrans <lmagr...@confluent.io>
---
 .../org/apache/kafka/clients/ClientUtilsTest.java  | 90 +++++++++++++++-------
 1 file changed, 61 insertions(+), 29 deletions(-)

diff --git 
a/clients/src/test/java/org/apache/kafka/clients/ClientUtilsTest.java 
b/clients/src/test/java/org/apache/kafka/clients/ClientUtilsTest.java
index 08e2a429085..2368a91137f 100644
--- a/clients/src/test/java/org/apache/kafka/clients/ClientUtilsTest.java
+++ b/clients/src/test/java/org/apache/kafka/clients/ClientUtilsTest.java
@@ -19,24 +19,27 @@ package org.apache.kafka.clients;
 import org.apache.kafka.common.config.ConfigException;
 
 import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+import org.mockito.MockedStatic;
 
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.Collections;
 import java.util.List;
-import java.util.stream.Collectors;
 
 import static java.util.Arrays.asList;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
 
 public class ClientUtilsTest {
 
-    private final HostResolver hostResolver = new DefaultHostResolver();
-
     @Test
     public void testParseAndValidateAddresses() {
         checkWithoutLookup("127.0.0.1:8000");
@@ -57,28 +60,39 @@ public class ClientUtilsTest {
         checkWithoutLookup("[::1]:8000");
         checkWithoutLookup("[2001:db8:85a3:8d3:1319:8a2e:370:7348]:1234", 
"localhost:10000");
 
-        // With lookup of example.com, either one or two addresses are 
expected depending on
-        // whether ipv4 and ipv6 are enabled
-        List<InetSocketAddress> validatedAddresses = 
checkWithLookup(Collections.singletonList("example.com:10000"));
-        assertFalse(validatedAddresses.isEmpty(), "Unexpected addresses " + 
validatedAddresses);
-        List<String> validatedHostNames = 
validatedAddresses.stream().map(InetSocketAddress::getHostName)
-                .collect(Collectors.toList());
-        List<String> expectedHostNames = List.of(
-            "a23-215-0-136.deploy.static.akamaitechnologies.com",
-            "a23-192-228-84.deploy.static.akamaitechnologies.com",
-            "a23-215-0-138.deploy.static.akamaitechnologies.com",
-            "a96-7-128-175.deploy.static.akamaitechnologies.com",
-            "a23-192-228-80.deploy.static.akamaitechnologies.com",
-            "a96-7-128-198.deploy.static.akamaitechnologies.com",
-            "2600:1406:3a00:21:0:0:173e:2e66",
-            "2600:1408:ec00:36:0:0:1736:7f31",
-            "2600:1406:3a00:21:0:0:173e:2e65",
-            "2600:1408:ec00:36:0:0:1736:7f24",
-            "2600:1406:bc00:53:0:0:b81e:94ce",
-            "2600:1406:bc00:53:0:0:b81e:94c8"
-        );
-        assertTrue(expectedHostNames.containsAll(validatedHostNames), 
"Unexpected addresses " + validatedHostNames);
-        validatedAddresses.forEach(address -> assertEquals(10000, 
address.getPort()));
+        String hostname = "example.com";
+        Integer port = 10000;
+        String canonicalHostname1 = "canonical_hostname1";
+        String canonicalHostname2 = "canonical_hostname2";
+        try (final MockedStatic<InetAddress> inetAddress = 
mockStatic(InetAddress.class)) {
+            InetAddress inetAddress1 = mock(InetAddress.class);
+            
when(inetAddress1.getCanonicalHostName()).thenReturn(canonicalHostname1);
+            InetAddress inetAddress2 = mock(InetAddress.class);
+            
when(inetAddress2.getCanonicalHostName()).thenReturn(canonicalHostname2);
+            inetAddress.when(() -> InetAddress.getAllByName(hostname))
+                .thenReturn(new InetAddress[]{inetAddress1, inetAddress2});
+            try (MockedConstruction<InetSocketAddress> inetSocketAddress =
+                     mockConstruction(
+                         InetSocketAddress.class,
+                         (mock, context) -> {
+                             when(mock.isUnresolved()).thenReturn(false);
+                             when(mock.getHostName()).thenReturn((String) 
context.arguments().get(0));
+                             when(mock.getPort()).thenReturn((Integer) 
context.arguments().get(1));
+                         })
+            ) {
+                List<InetSocketAddress> validatedAddresses = 
checkWithLookup(Collections.singletonList(hostname + ":" + port));
+                assertEquals(2, inetSocketAddress.constructed().size());
+                assertEquals(2, validatedAddresses.size());
+                assertTrue(validatedAddresses.containsAll(List.of(
+                    inetSocketAddress.constructed().get(0),
+                    inetSocketAddress.constructed().get(1)))
+                );
+                validatedAddresses.forEach(address -> assertEquals(port, 
address.getPort()));
+                
validatedAddresses.stream().map(InetSocketAddress::getHostName).forEach(
+                    hostName -> assertTrue(List.of(canonicalHostname1, 
canonicalHostname2).contains(hostName))
+                );
+            }
+        }
     }
 
     @Test
@@ -99,7 +113,21 @@ public class ClientUtilsTest {
 
     @Test
     public void testOnlyBadHostname() {
-        assertThrows(ConfigException.class, () -> 
checkWithoutLookup("some.invalid.hostname.foo.bar.local:9999"));
+        try (MockedConstruction<InetSocketAddress> inetSocketAddress =
+                 mockConstruction(
+                     InetSocketAddress.class,
+                     (mock, context) -> 
when(mock.isUnresolved()).thenReturn(true)
+                 )
+        ) {
+            Exception exception = assertThrows(
+                ConfigException.class,
+                () -> 
checkWithoutLookup("some.invalid.hostname.foo.bar.local:9999")
+            );
+            assertEquals(
+                "No resolvable bootstrap urls given in " + 
CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,
+                exception.getMessage()
+            );
+        }
     }
 
     @Test
@@ -122,8 +150,13 @@ public class ClientUtilsTest {
 
     @Test
     public void testResolveUnknownHostException() {
-        assertThrows(UnknownHostException.class,
-            () -> ClientUtils.resolve("some.invalid.hostname.foo.bar.local", 
hostResolver));
+        HostResolver throwingHostResolver = host -> {
+            throw new UnknownHostException();
+        };
+        assertThrows(
+            UnknownHostException.class,
+            () -> ClientUtils.resolve("some.invalid.hostname.foo.bar.local", 
throwingHostResolver)
+        );
     }
 
     @Test
@@ -142,5 +175,4 @@ public class ClientUtilsTest {
     private List<InetSocketAddress> checkWithLookup(List<String> url) {
         return ClientUtils.parseAndValidateAddresses(url, 
ClientDnsLookup.RESOLVE_CANONICAL_BOOTSTRAP_SERVERS_ONLY);
     }
-
 }

Reply via email to