Skip to content

Commit 33c6528

Browse files
cadonnamanoj-mathivanan
authored andcommitted
KAFKA-18546: Use mocks instead of a real DNS lookup to the outside (apache#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 <[email protected]>, Chia-Ping Tsai <[email protected]>, Lianet Magrans <[email protected]>
1 parent c7bf7be commit 33c6528

File tree

1 file changed

+61
-29
lines changed

1 file changed

+61
-29
lines changed

clients/src/test/java/org/apache/kafka/clients/ClientUtilsTest.java

+61-29
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,27 @@
1919
import org.apache.kafka.common.config.ConfigException;
2020

2121
import org.junit.jupiter.api.Test;
22+
import org.mockito.MockedConstruction;
23+
import org.mockito.MockedStatic;
2224

2325
import java.net.InetAddress;
2426
import java.net.InetSocketAddress;
2527
import java.net.UnknownHostException;
2628
import java.util.Collections;
2729
import java.util.List;
28-
import java.util.stream.Collectors;
2930

3031
import static java.util.Arrays.asList;
3132
import static org.junit.jupiter.api.Assertions.assertEquals;
3233
import static org.junit.jupiter.api.Assertions.assertFalse;
3334
import static org.junit.jupiter.api.Assertions.assertThrows;
3435
import static org.junit.jupiter.api.Assertions.assertTrue;
36+
import static org.mockito.Mockito.mock;
37+
import static org.mockito.Mockito.mockConstruction;
38+
import static org.mockito.Mockito.mockStatic;
39+
import static org.mockito.Mockito.when;
3540

3641
public class ClientUtilsTest {
3742

38-
private final HostResolver hostResolver = new DefaultHostResolver();
39-
4043
@Test
4144
public void testParseAndValidateAddresses() {
4245
checkWithoutLookup("127.0.0.1:8000");
@@ -57,28 +60,39 @@ public void testParseAndValidateAddressesWithReverseLookup() {
5760
checkWithoutLookup("[::1]:8000");
5861
checkWithoutLookup("[2001:db8:85a3:8d3:1319:8a2e:370:7348]:1234", "localhost:10000");
5962

60-
// With lookup of example.com, either one or two addresses are expected depending on
61-
// whether ipv4 and ipv6 are enabled
62-
List<InetSocketAddress> validatedAddresses = checkWithLookup(Collections.singletonList("example.com:10000"));
63-
assertFalse(validatedAddresses.isEmpty(), "Unexpected addresses " + validatedAddresses);
64-
List<String> validatedHostNames = validatedAddresses.stream().map(InetSocketAddress::getHostName)
65-
.collect(Collectors.toList());
66-
List<String> expectedHostNames = List.of(
67-
"a23-215-0-136.deploy.static.akamaitechnologies.com",
68-
"a23-192-228-84.deploy.static.akamaitechnologies.com",
69-
"a23-215-0-138.deploy.static.akamaitechnologies.com",
70-
"a96-7-128-175.deploy.static.akamaitechnologies.com",
71-
"a23-192-228-80.deploy.static.akamaitechnologies.com",
72-
"a96-7-128-198.deploy.static.akamaitechnologies.com",
73-
"2600:1406:3a00:21:0:0:173e:2e66",
74-
"2600:1408:ec00:36:0:0:1736:7f31",
75-
"2600:1406:3a00:21:0:0:173e:2e65",
76-
"2600:1408:ec00:36:0:0:1736:7f24",
77-
"2600:1406:bc00:53:0:0:b81e:94ce",
78-
"2600:1406:bc00:53:0:0:b81e:94c8"
79-
);
80-
assertTrue(expectedHostNames.containsAll(validatedHostNames), "Unexpected addresses " + validatedHostNames);
81-
validatedAddresses.forEach(address -> assertEquals(10000, address.getPort()));
63+
String hostname = "example.com";
64+
Integer port = 10000;
65+
String canonicalHostname1 = "canonical_hostname1";
66+
String canonicalHostname2 = "canonical_hostname2";
67+
try (final MockedStatic<InetAddress> inetAddress = mockStatic(InetAddress.class)) {
68+
InetAddress inetAddress1 = mock(InetAddress.class);
69+
when(inetAddress1.getCanonicalHostName()).thenReturn(canonicalHostname1);
70+
InetAddress inetAddress2 = mock(InetAddress.class);
71+
when(inetAddress2.getCanonicalHostName()).thenReturn(canonicalHostname2);
72+
inetAddress.when(() -> InetAddress.getAllByName(hostname))
73+
.thenReturn(new InetAddress[]{inetAddress1, inetAddress2});
74+
try (MockedConstruction<InetSocketAddress> inetSocketAddress =
75+
mockConstruction(
76+
InetSocketAddress.class,
77+
(mock, context) -> {
78+
when(mock.isUnresolved()).thenReturn(false);
79+
when(mock.getHostName()).thenReturn((String) context.arguments().get(0));
80+
when(mock.getPort()).thenReturn((Integer) context.arguments().get(1));
81+
})
82+
) {
83+
List<InetSocketAddress> validatedAddresses = checkWithLookup(Collections.singletonList(hostname + ":" + port));
84+
assertEquals(2, inetSocketAddress.constructed().size());
85+
assertEquals(2, validatedAddresses.size());
86+
assertTrue(validatedAddresses.containsAll(List.of(
87+
inetSocketAddress.constructed().get(0),
88+
inetSocketAddress.constructed().get(1)))
89+
);
90+
validatedAddresses.forEach(address -> assertEquals(port, address.getPort()));
91+
validatedAddresses.stream().map(InetSocketAddress::getHostName).forEach(
92+
hostName -> assertTrue(List.of(canonicalHostname1, canonicalHostname2).contains(hostName))
93+
);
94+
}
95+
}
8296
}
8397

8498
@Test
@@ -99,7 +113,21 @@ public void testInvalidPort() {
99113

100114
@Test
101115
public void testOnlyBadHostname() {
102-
assertThrows(ConfigException.class, () -> checkWithoutLookup("some.invalid.hostname.foo.bar.local:9999"));
116+
try (MockedConstruction<InetSocketAddress> inetSocketAddress =
117+
mockConstruction(
118+
InetSocketAddress.class,
119+
(mock, context) -> when(mock.isUnresolved()).thenReturn(true)
120+
)
121+
) {
122+
Exception exception = assertThrows(
123+
ConfigException.class,
124+
() -> checkWithoutLookup("some.invalid.hostname.foo.bar.local:9999")
125+
);
126+
assertEquals(
127+
"No resolvable bootstrap urls given in " + CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG,
128+
exception.getMessage()
129+
);
130+
}
103131
}
104132

105133
@Test
@@ -122,8 +150,13 @@ public void testFilterPreferredAddresses() throws UnknownHostException {
122150

123151
@Test
124152
public void testResolveUnknownHostException() {
125-
assertThrows(UnknownHostException.class,
126-
() -> ClientUtils.resolve("some.invalid.hostname.foo.bar.local", hostResolver));
153+
HostResolver throwingHostResolver = host -> {
154+
throw new UnknownHostException();
155+
};
156+
assertThrows(
157+
UnknownHostException.class,
158+
() -> ClientUtils.resolve("some.invalid.hostname.foo.bar.local", throwingHostResolver)
159+
);
127160
}
128161

129162
@Test
@@ -142,5 +175,4 @@ private List<InetSocketAddress> checkWithoutLookup(String... url) {
142175
private List<InetSocketAddress> checkWithLookup(List<String> url) {
143176
return ClientUtils.parseAndValidateAddresses(url, ClientDnsLookup.RESOLVE_CANONICAL_BOOTSTRAP_SERVERS_ONLY);
144177
}
145-
146178
}

0 commit comments

Comments
 (0)