1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.nio;
29
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
32 import static org.junit.jupiter.api.Assertions.assertNotNull;
33 import static org.junit.jupiter.api.Assertions.assertTrue;
34 import static org.junit.jupiter.api.Assertions.fail;
35 import static org.mockito.ArgumentMatchers.any;
36
37 import java.io.IOException;
38 import java.net.InetAddress;
39 import java.net.InetSocketAddress;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.concurrent.CompletableFuture;
43 import java.util.concurrent.ExecutionException;
44 import java.util.concurrent.Future;
45
46 import org.apache.hc.client5.http.DnsResolver;
47 import org.apache.hc.core5.concurrent.FutureCallback;
48 import org.apache.hc.core5.net.NamedEndpoint;
49 import org.apache.hc.core5.reactor.ConnectionInitiator;
50 import org.apache.hc.core5.reactor.IOSession;
51 import org.apache.hc.core5.util.Timeout;
52 import org.junit.jupiter.api.BeforeEach;
53 import org.junit.jupiter.api.Test;
54 import org.mockito.Mockito;
55
56 class MultihomeIOSessionRequesterTest {
57
58 private DnsResolver dnsResolver;
59 private ConnectionInitiator connectionInitiator;
60 private MultihomeIOSessionRequester sessionRequester;
61 private NamedEndpoint namedEndpoint;
62
63 @BeforeEach
64 void setUp() {
65 dnsResolver = Mockito.mock(DnsResolver.class);
66 connectionInitiator = Mockito.mock(ConnectionInitiator.class);
67 namedEndpoint = Mockito.mock(NamedEndpoint.class);
68 sessionRequester = new MultihomeIOSessionRequester(dnsResolver);
69 }
70
71 @Test
72 void testConnectWithMultipleAddresses() throws Exception {
73 final InetAddress address1 = InetAddress.getByAddress(new byte[]{10, 0, 0, 1});
74 final InetAddress address2 = InetAddress.getByAddress(new byte[]{10, 0, 0, 2});
75 final List<InetSocketAddress> remoteAddresses = Arrays.asList(
76 new InetSocketAddress(address1, 8080),
77 new InetSocketAddress(address2, 8080)
78 );
79
80 Mockito.when(namedEndpoint.getHostName()).thenReturn("somehost");
81 Mockito.when(namedEndpoint.getPort()).thenReturn(8080);
82 Mockito.when(dnsResolver.resolve("somehost", 8080)).thenReturn(remoteAddresses);
83
84 Mockito.when(connectionInitiator.connect(any(), any(), any(), any(), any(), any()))
85 .thenAnswer(invocation -> {
86 final FutureCallback<IOSession> callback = invocation.getArgument(5);
87
88 final CompletableFuture<IOSession> future = new CompletableFuture<>();
89 callback.failed(new IOException("Simulated connection failure"));
90 future.completeExceptionally(new IOException("Simulated connection failure"));
91 return future;
92 });
93
94 final Future<IOSession> future = sessionRequester.connect(
95 connectionInitiator,
96 namedEndpoint,
97 null,
98 Timeout.ofMilliseconds(500),
99 null,
100 null
101 );
102
103 assertTrue(future.isDone());
104 try {
105 future.get();
106 fail("Expected ExecutionException");
107 } catch (final ExecutionException ex) {
108 assertInstanceOf(IOException.class, ex.getCause());
109 assertEquals("Simulated connection failure", ex.getCause().getMessage());
110 }
111 }
112
113 @Test
114 void testConnectSuccessfulAfterRetries() throws Exception {
115 final InetAddress address1 = InetAddress.getByAddress(new byte[]{10, 0, 0, 1});
116 final InetAddress address2 = InetAddress.getByAddress(new byte[]{10, 0, 0, 2});
117 final List<InetSocketAddress> remoteAddresses = Arrays.asList(
118 new InetSocketAddress(address1, 8080),
119 new InetSocketAddress(address2, 8080)
120 );
121
122 Mockito.when(namedEndpoint.getHostName()).thenReturn("somehost");
123 Mockito.when(namedEndpoint.getPort()).thenReturn(8080);
124 Mockito.when(dnsResolver.resolve("somehost", 8080)).thenReturn(remoteAddresses);
125
126 Mockito.when(connectionInitiator.connect(any(), any(), any(), any(), any(), any()))
127 .thenAnswer(invocation -> {
128 final FutureCallback<IOSession> callback = invocation.getArgument(5);
129 final InetSocketAddress remoteAddress = invocation.getArgument(1);
130 final CompletableFuture<IOSession> future = new CompletableFuture<>();
131 if (remoteAddress.getAddress().equals(address1)) {
132
133 callback.failed(new IOException("Simulated connection failure"));
134 future.completeExceptionally(new IOException("Simulated connection failure"));
135 } else {
136
137 final IOSession mockSession = Mockito.mock(IOSession.class);
138 callback.completed(mockSession);
139 future.complete(mockSession);
140 }
141 return future;
142 });
143
144 final Future<IOSession> future = sessionRequester.connect(
145 connectionInitiator,
146 namedEndpoint,
147 null,
148 Timeout.ofMilliseconds(500),
149 null,
150 null
151 );
152
153 assertTrue(future.isDone());
154 try {
155 final IOSession session = future.get();
156 assertNotNull(session);
157 } catch (final ExecutionException ex) {
158 fail("Did not expect an ExecutionException", ex);
159 }
160 }
161 }