View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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          final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
93          Assert.assertThat(future1, CoreMatchers.notNullValue());
94          Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
95          Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
96  
97          Mockito.verify(impl).connectSession(
98                  ArgumentMatchers.eq("somehost"),
99                  ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
100                 ArgumentMatchers.<FutureCallback<IOSession>>any());
101 
102         final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
103         Assert.assertThat(future2, CoreMatchers.notNullValue());
104         Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
105         Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
106 
107         Mockito.verify(impl, Mockito.times(1)).connectSession(
108                 ArgumentMatchers.eq("somehost"),
109                 ArgumentMatchers.<Timeout>any(),
110                 ArgumentMatchers.argThat(new ArgumentMatcher<FutureCallback<IOSession>>() {
111 
112                     @Override
113                     public boolean matches(final FutureCallback<IOSession> callback) {
114                         callback.completed(ioSession1);
115                         return true;
116                     }
117 
118                 }));
119 
120         Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
121         Assert.assertThat(future1.get(), CoreMatchers.sameInstance(ioSession1));
122 
123         Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(true));
124         Assert.assertThat(future2.get(), CoreMatchers.sameInstance(ioSession1));
125 
126         Mockito.verify(impl, Mockito.times(2)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
127 
128         final Future<IOSession> future3 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
129 
130         Mockito.verify(impl, Mockito.times(1)).connectSession(
131                 ArgumentMatchers.eq("somehost"),
132                 ArgumentMatchers.<Timeout>any(),
133                 ArgumentMatchers.<FutureCallback<IOSession>>any());
134 
135         Mockito.verify(impl, Mockito.times(3)).validateSession(ArgumentMatchers.<IOSession>any(), ArgumentMatchers.<Callback<Boolean>>any());
136 
137         Assert.assertThat(future3.isDone(), CoreMatchers.equalTo(true));
138         Assert.assertThat(future3.get(), CoreMatchers.sameInstance(ioSession1));
139     }
140 
141     @Test
142     public void testGetSessionFailure() throws Exception {
143 
144         Mockito.when(impl.connectSession(
145                 ArgumentMatchers.anyString(),
146                 ArgumentMatchers.<Timeout>any(),
147                 ArgumentMatchers.<FutureCallback<IOSession>>any())).thenReturn(connectFuture);
148 
149         final Future<IOSession> future1 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
150         Assert.assertThat(future1, CoreMatchers.notNullValue());
151         Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(false));
152         Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
153 
154         Mockito.verify(impl).connectSession(
155                 ArgumentMatchers.eq("somehost"),
156                 ArgumentMatchers.eq(Timeout.ofSeconds(123L)),
157                 ArgumentMatchers.<FutureCallback<IOSession>>any());
158 
159         final Future<IOSession> future2 = impl.getSession("somehost", Timeout.ofSeconds(123L), null);
160         Assert.assertThat(future2, CoreMatchers.notNullValue());
161         Assert.assertThat(future2.isDone(), CoreMatchers.equalTo(false));
162         Assert.assertThat(impl.getRoutes(), CoreMatchers.hasItem("somehost"));
163 
164         Mockito.verify(impl, Mockito.times(1)).connectSession(
165                 ArgumentMatchers.eq("somehost"),
166                 ArgumentMatchers.<Timeout>any(),
167                 ArgumentMatchers.argThat(new ArgumentMatcher<FutureCallback<IOSession>>() {
168 
169                     @Override
170                     public boolean matches(final FutureCallback<IOSession> callback) {
171                         callback.failed(new Exception("Boom"));
172                         return true;
173                     }
174 
175                 }));
176 
177         Assert.assertThat(future1.isDone(), CoreMatchers.equalTo(true));
178         Assert.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         Assert.assertThat(entry1, CoreMatchers.notNullValue());
185         entry1.session = ioSession1;
186 
187         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
188         Assert.assertThat(entry2, CoreMatchers.notNullValue());
189         entry2.session = ioSession2;
190 
191         final AbstractIOSessionPool.PoolEntry entry3 = impl.getPoolEntry("host3");
192         Assert.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         Assert.assertThat(entry1, CoreMatchers.notNullValue());
210         entry1.session = ioSession1;
211 
212         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
213         Assert.assertThat(entry2, CoreMatchers.notNullValue());
214         entry2.session = ioSession2;
215 
216         impl.closeIdle(TimeValue.ofMillis(0L));
217 
218         Mockito.verify(impl).closeSession(ioSession1, CloseMode.GRACEFUL);
219         Mockito.verify(impl).closeSession(ioSession2, CloseMode.GRACEFUL);
220 
221         Assert.assertThat(entry1.session, CoreMatchers.nullValue());
222         Assert.assertThat(entry2.session, CoreMatchers.nullValue());
223     }
224 
225     @Test
226     public void testEnumSessions() throws Exception {
227         final AbstractIOSessionPool.PoolEntry entry1 = impl.getPoolEntry("host1");
228         Assert.assertThat(entry1, CoreMatchers.notNullValue());
229         entry1.session = ioSession1;
230 
231         final AbstractIOSessionPool.PoolEntry entry2 = impl.getPoolEntry("host2");
232         Assert.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         Assert.assertThat(entry1, CoreMatchers.notNullValue());
251         entry1.session = ioSession1;
252 
253         Mockito.when(ioSession1.isClosed()).thenReturn(false);
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         Assert.assertThat(entry1, CoreMatchers.notNullValue());
277         entry1.session = ioSession1;
278 
279         Mockito.when(ioSession1.isClosed()).thenReturn(true);
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 }