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); } - }