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