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 package org.apache.hc.core5.reactor;
28
29 import java.net.UnknownHostException;
30 import java.util.concurrent.Future;
31
32 import org.apache.hc.core5.concurrent.FutureCallback;
33 import org.apache.hc.core5.function.Callback;
34 import org.apache.hc.core5.io.CloseMode;
35 import org.apache.hc.core5.util.TimeValue;
36 import org.apache.hc.core5.util.Timeout;
37 import org.hamcrest.CoreMatchers;
38 import org.hamcrest.MatcherAssert;
39 import org.junit.Assert;
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.mockito.Answers;
44 import org.mockito.ArgumentCaptor;
45 import org.mockito.ArgumentMatcher;
46 import org.mockito.ArgumentMatchers;
47 import org.mockito.Captor;
48 import org.mockito.Mock;
49 import org.mockito.Mockito;
50 import org.mockito.invocation.InvocationOnMock;
51 import org.mockito.junit.MockitoJUnitRunner;
52 import org.mockito.stubbing.Answer;
53
54 @RunWith(MockitoJUnitRunner.class)
55 public class TestAbstractIOSessionPool {
56
57 @Mock
58 private Future<IOSession> connectFuture;
59 @Mock
60 private FutureCallback<IOSession> callback1;
61 @Mock
62 private FutureCallback<IOSession> callback2;
63 @Mock
64 private IOSession ioSession1;
65 @Mock
66 private IOSession ioSession2;
67 @Captor
68 ArgumentCaptor<FutureCallback<IOSession>> connectCallbackCaptor;
69
70 private AbstractIOSessionPool<String> impl;
71
72 @Before
73 public void setup() {
74 impl = Mockito.mock(AbstractIOSessionPool.class, Mockito.withSettings()
75 .defaultAnswer(Answers.CALLS_REAL_METHODS)
76 .useConstructor());
77 }
78
79 @Test
80 public void testGetSessions() throws Exception {
81
82 Mockito.when(impl.connectSession(
83 ArgumentMatchers.anyString(),
84 ArgumentMatchers.<Timeout>any(),
85 ArgumentMatchers.<FutureCallback<IOSession>>any())).thenReturn(connectFuture);
86
87 Mockito.doAnswer(new Answer() {
88
89 @Override
90 public Object answer(final InvocationOnMock invocation) throws Throwable {
91 final Callback<Boolean> callback = invocation.getArgument(1);
92 callback.execute(true);
93 return null;
94 }
95
96 }).when(impl).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
97
98 Mockito.when(ioSession1.isOpen()).thenReturn(true);
99
100 final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
101 MatcherAssert.assertThat(future1, CoreMatchers.notNullValue());
102 MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
103 MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
104
105 Mockito.verify(impl).connectSession(
106 ArgumentMatchers.eq("somehost"),
107 ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
108 ArgumentMatchers.<FutureCallback<IOSession>>any());
109
110 final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
111 MatcherAssert.assertThat(future2, CoreMatchers.notNullValue());
112 MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
113 MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
114
115 Mockito.verify(impl, Mockito.times(1)).connectSession(
116 ArgumentMatchers.eq("somehost"),
117 ArgumentMatchers.<Timeout>any(),
118 ArgumentMatchers.argThat(new ArgumentMatcher<FutureCallback<IOSession>>() {
119
120 @Override
121 public boolean matches(final FutureCallback<IOSession> callback) {
122 callback.completed(ioSession1);
123 return true;
124 }
125
126 }));
127
128 MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
129 MatcherAssert.assertThat(future1.get(), CoreMatchers.sameInstance(ioSession1));
130
131 MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
132 MatcherAssert.assertThat(future2.get(), CoreMatchers.sameInstance(ioSession1));
133
134 Mockito.verify(impl, Mockito.times(2)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
135
136 final Future<IOSession> future3 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
137
138 Mockito.verify(impl, Mockito.times(1)).connectSession(
139 ArgumentMatchers.eq("somehost"),
140 ArgumentMatchers.<Timeout>any(),
141 ArgumentMatchers.<FutureCallback<IOSession>>any());
142
143 Mockito.verify(impl, Mockito.times(3)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
144
145 MatcherAssert.assertThat(future3.isDone(), CoreMatchers.equalTo(true));
146 MatcherAssert.assertThat(future3.get(), CoreMatchers.sameInstance(ioSession1));
147 }
148
149 @Test
150 public void testGetSessionConnectFailure() throws Exception {
151
152 Mockito.when(impl.connectSession(
153 ArgumentMatchers.anyString(),
154 ArgumentMatchers.<Timeout>any(),
155 ArgumentMatchers.<FutureCallback<IOSession>>any())).thenReturn(connectFuture);
156
157 final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
158 MatcherAssert.assertThat(future1, CoreMatchers.notNullValue());
159 MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
160 MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
161
162 Mockito.verify(impl).connectSession(
163 ArgumentMatchers.eq("somehost"),
164 ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
165 connectCallbackCaptor.capture());
166
167 final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
168 MatcherAssert.assertThat(future2, CoreMatchers.notNullValue());
169 MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
170 MatcherAssert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
171
172 final FutureCallback<IOSession> connectCallback = connectCallbackCaptor.getValue();
173 Assert.assertNotNull(connectCallback);
174 connectCallback.failed(new Exception("Boom"));
175
176
177 MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
178 MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
179 }
180
181 @Test
182 public void testShutdownPool() throws Exception {
183 final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
184 MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
185 entry1.session = ioSession1;
186
187 final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
188 MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
189 entry2.session = ioSession2;
190
191 final AbstractIOSessionPool.PoolEntry entry3 = impl.getPoolEntry("host3");
192 MatcherAssert.assertThat(entry3, CoreMatchers.notNullValue());
193 entry3.sessionFuture = connectFuture;
194 entry3.requestQueue.add(callback1);
195 entry3.requestQueue.add(callback2);
196
197 impl.close(CloseMode.GRACEFUL);
198
199 Mockito.verify(impl).closeSession(ioSession1, CloseMode.GRACEFUL);
200 Mockito.verify(impl).closeSession(ioSession2, CloseMode.GRACEFUL);
201 Mockito.verify(connectFuture).cancel(ArgumentMatchers.anyBoolean());
202 Mockito.verify(callback1).cancelled();
203 Mockito.verify(callback2).cancelled();
204 }
205
206 @Test
207 public void testCloseIdleSessions() throws Exception {
208 final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
209 MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
210 entry1.session = ioSession1;
211
212 final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
213 MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
214 entry2.session = ioSession2;
215
216 impl.closeIdle(TimeValue.ZERO_MILLISECONDS);
217
218 Mockito.verify(impl).closeSession(ioSession1, CloseMode.GRACEFUL);
219 Mockito.verify(impl).closeSession(ioSession2, CloseMode.GRACEFUL);
220
221 MatcherAssert.assertThat(entry1.session, CoreMatchers.nullValue());
222 MatcherAssert.assertThat(entry2.session, CoreMatchers.nullValue());
223 }
224
225 @Test
226 public void testEnumSessions() throws Exception {
227 final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
228 MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
229 entry1.session = ioSession1;
230
231 final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
232 MatcherAssert.assertThat(entry2, CoreMatchers.notNullValue());
233 entry2.session = ioSession2;
234
235 impl.enumAvailable(new Callback<IOSession>() {
236
237 @Override
238 public void execute(final IOSession ioSession) {
239 ioSession.close(CloseMode.GRACEFUL);
240 }
241
242 });
243 Mockito.verify(ioSession1).close(CloseMode.GRACEFUL);
244 Mockito.verify(ioSession2).close(CloseMode.GRACEFUL);
245 }
246
247 @Test
248 public void testGetSessionReconnectAfterValidate() throws Exception {
249 final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("somehost");
250 MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
251 entry1.session = ioSession1;
252
253 Mockito.when(ioSession1.isOpen()).thenReturn(true);
254 Mockito.doAnswer(new Answer() {
255
256 @Override
257 public Object answer(final InvocationOnMock invocation) throws Throwable {
258 final Callback<Boolean> callback = invocation.getArgument(1);
259 callback.execute(false);
260 return null;
261 }
262
263 }).when(impl).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
264
265 impl.getSession("somehost", Timeout.ofSeconds(123L), null);
266
267 Mockito.verify(impl, Mockito.times(1)).connectSession(
268 ArgumentMatchers.eq("somehost"),
269 ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
270 ArgumentMatchers.<FutureCallback<IOSession>>any());
271 }
272
273 @Test
274 public void testGetSessionReconnectIfClosed() throws Exception {
275 final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("somehost");
276 MatcherAssert.assertThat(entry1, CoreMatchers.notNullValue());
277 entry1.session = ioSession1;
278
279 Mockito.when(ioSession1.isOpen()).thenReturn(false);
280
281 impl.getSession("somehost", Timeout.ofSeconds(123L), null);
282
283 Mockito.verify(impl).connectSession(
284 ArgumentMatchers.eq("somehost"),
285 ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
286 ArgumentMatchers.<FutureCallback<IOSession>>any());
287 }
288
289 @Test
290 public void testGetSessionConnectUnknownHost() throws Exception {
291
292 Mockito.when(connectFuture.isDone()).thenReturn(true);
293 Mockito.when(impl.connectSession(
294 ArgumentMatchers.anyString(),
295 ArgumentMatchers.<Timeout>any(),
296 ArgumentMatchers.argThat(new ArgumentMatcher<FutureCallback<IOSession>>() {
297
298 @Override
299 public boolean matches(final FutureCallback<IOSession> callback) {
300 callback.failed(new UnknownHostException("Boom"));
301 return true;
302 }
303
304 }))).thenReturn(connectFuture);
305
306 final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
307 MatcherAssert.assertThat(future1, CoreMatchers.notNullValue());
308 MatcherAssert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
309
310 final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
311 MatcherAssert.assertThat(future2, CoreMatchers.notNullValue());
312 MatcherAssert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
313 }
314
315 }