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.client5.http.impl.classic;
28  
29  import java.util.concurrent.ExecutionException;
30  import java.util.concurrent.TimeUnit;
31  import java.util.concurrent.TimeoutException;
32  
33  import org.apache.hc.client5.http.HttpRoute;
34  import org.apache.hc.client5.http.config.RequestConfig;
35  import org.apache.hc.client5.http.io.ConnectionEndpoint;
36  import org.apache.hc.client5.http.io.HttpClientConnectionManager;
37  import org.apache.hc.client5.http.io.LeaseRequest;
38  import org.apache.hc.client5.http.protocol.HttpClientContext;
39  import org.apache.hc.core5.concurrent.Cancellable;
40  import org.apache.hc.core5.concurrent.CancellableDependency;
41  import org.apache.hc.core5.http.ConnectionRequestTimeoutException;
42  import org.apache.hc.core5.http.HttpHost;
43  import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
44  import org.apache.hc.core5.io.CloseMode;
45  import org.apache.hc.core5.util.TimeValue;
46  import org.apache.hc.core5.util.Timeout;
47  import org.junit.Assert;
48  import org.junit.Before;
49  import org.junit.Test;
50  import org.mockito.Mock;
51  import org.mockito.Mockito;
52  import org.mockito.MockitoAnnotations;
53  import org.slf4j.Logger;
54  
55  @SuppressWarnings({"static-access"}) // test code
56  public class TestInternalExecRuntime {
57  
58      @Mock
59      private Logger log;
60      @Mock
61      private HttpClientConnectionManager mgr;
62      @Mock
63      private LeaseRequest leaseRequest;
64      @Mock
65      private HttpRequestExecutor requestExecutor;
66      @Mock
67      private CancellableDependency cancellableDependency;
68      @Mock
69      private ConnectionEndpoint connectionEndpoint;
70  
71      private HttpRoute route;
72      private InternalExecRuntime execRuntime;
73  
74      @Before
75      public void setup() {
76          MockitoAnnotations.initMocks(this);
77          route = new HttpRoute(new HttpHost("host", 80));
78          execRuntime = new InternalExecRuntime(log, mgr, requestExecutor, cancellableDependency);
79      }
80  
81      @Test
82      public void testAcquireEndpoint() throws Exception {
83          final HttpClientContext context = HttpClientContext.create();
84          final RequestConfig config = RequestConfig.custom()
85                  .setConnectionRequestTimeout(345, TimeUnit.MILLISECONDS)
86                  .setConnectTimeout(123, TimeUnit.MILLISECONDS)
87                  .build();
88          context.setRequestConfig(config);
89          final HttpRoute route = new HttpRoute(new HttpHost("host", 80));
90  
91          Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
92                  .thenReturn(leaseRequest);
93          Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
94  
95          execRuntime.acquireEndpoint("some-id", route, null, context);
96  
97          Assert.assertTrue(execRuntime.isEndpointAcquired());
98          Assert.assertSame(connectionEndpoint, execRuntime.ensureValid());
99          Assert.assertFalse(execRuntime.isEndpointConnected());
100         Assert.assertFalse(execRuntime.isConnectionReusable());
101 
102         Mockito.verify(leaseRequest).get(Timeout.ofMilliseconds(345));
103         Mockito.verify(cancellableDependency, Mockito.times(1)).setDependency(leaseRequest);
104         Mockito.verify(cancellableDependency, Mockito.times(1)).setDependency(execRuntime);
105         Mockito.verify(cancellableDependency, Mockito.times(2)).setDependency(Mockito.<Cancellable>any());
106     }
107 
108     @Test(expected = IllegalStateException.class)
109     public void testAcquireEndpointAlreadyAcquired() throws Exception {
110         final HttpClientContext context = HttpClientContext.create();
111 
112         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
113                 .thenReturn(leaseRequest);
114         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
115 
116         execRuntime.acquireEndpoint("some-id", route, null, context);
117 
118         Assert.assertTrue(execRuntime.isEndpointAcquired());
119         Assert.assertSame(connectionEndpoint, execRuntime.ensureValid());
120 
121         execRuntime.acquireEndpoint("some-id", route, null, context);
122     }
123 
124     @Test(expected = ConnectionRequestTimeoutException.class)
125     public void testAcquireEndpointLeaseRequestTimeout() throws Exception {
126         final HttpClientContext context = HttpClientContext.create();
127 
128         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
129                 .thenReturn(leaseRequest);
130         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenThrow(new TimeoutException("timeout"));
131 
132         execRuntime.acquireEndpoint("some-id", route, null, context);
133     }
134 
135     @Test(expected = RequestFailedException.class)
136     public void testAcquireEndpointLeaseRequestFailure() throws Exception {
137         final HttpClientContext context = HttpClientContext.create();
138 
139         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
140                 .thenReturn(leaseRequest);
141         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenThrow(new ExecutionException(new IllegalStateException()));
142 
143         execRuntime.acquireEndpoint("some-id", route, null, context);
144     }
145 
146     @Test
147     public void testAbortEndpoint() throws Exception {
148         final HttpClientContext context = HttpClientContext.create();
149         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
150                 .thenReturn(leaseRequest);
151         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
152 
153         execRuntime.acquireEndpoint("some-id", new HttpRoute(new HttpHost("host", 80)), null, context);
154         Assert.assertTrue(execRuntime.isEndpointAcquired());
155         execRuntime.discardEndpoint();
156 
157         Assert.assertFalse(execRuntime.isEndpointAcquired());
158 
159         Mockito.verify(connectionEndpoint).close(CloseMode.IMMEDIATE);
160         Mockito.verify(mgr).release(connectionEndpoint, null, TimeValue.ZERO_MILLISECONDS);
161 
162         execRuntime.discardEndpoint();
163 
164         Mockito.verify(connectionEndpoint, Mockito.times(1)).close(CloseMode.IMMEDIATE);
165         Mockito.verify(mgr, Mockito.times(1)).release(
166                 Mockito.<ConnectionEndpoint>any(),
167                 Mockito.any(),
168                 Mockito.<TimeValue>any());
169     }
170 
171     @Test
172     public void testCancell() throws Exception {
173         final HttpClientContext context = HttpClientContext.create();
174 
175         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
176                 .thenReturn(leaseRequest);
177         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
178 
179         execRuntime.acquireEndpoint("some-id", route, null, context);
180         Assert.assertTrue(execRuntime.isEndpointAcquired());
181 
182         Assert.assertTrue(execRuntime.cancel());
183 
184         Assert.assertFalse(execRuntime.isEndpointAcquired());
185 
186         Mockito.verify(connectionEndpoint).close(CloseMode.IMMEDIATE);
187         Mockito.verify(mgr).release(connectionEndpoint, null, TimeValue.ZERO_MILLISECONDS);
188 
189         Assert.assertFalse(execRuntime.cancel());
190 
191         Mockito.verify(connectionEndpoint, Mockito.times(1)).close(CloseMode.IMMEDIATE);
192         Mockito.verify(mgr, Mockito.times(1)).release(
193                 Mockito.<ConnectionEndpoint>any(),
194                 Mockito.any(),
195                 Mockito.<TimeValue>any());
196     }
197 
198     @Test
199     public void testReleaseEndpointReusable() throws Exception {
200         final HttpClientContext context = HttpClientContext.create();
201 
202         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
203                 .thenReturn(leaseRequest);
204         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
205 
206         execRuntime.acquireEndpoint("some-id", route, null, context);
207         Assert.assertTrue(execRuntime.isEndpointAcquired());
208 
209         execRuntime.markConnectionReusable("some state", TimeValue.ofMilliseconds(100000));
210 
211         execRuntime.releaseEndpoint();
212 
213         Assert.assertFalse(execRuntime.isEndpointAcquired());
214 
215         Mockito.verify(connectionEndpoint, Mockito.never()).close();
216         Mockito.verify(mgr).release(connectionEndpoint, "some state", TimeValue.ofMilliseconds(100000));
217 
218         execRuntime.releaseEndpoint();
219 
220         Mockito.verify(mgr, Mockito.times(1)).release(
221                 Mockito.<ConnectionEndpoint>any(),
222                 Mockito.any(),
223                 Mockito.<TimeValue>any());
224     }
225 
226     @Test
227     public void testReleaseEndpointNonReusable() throws Exception {
228         final HttpClientContext context = HttpClientContext.create();
229 
230         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
231                 .thenReturn(leaseRequest);
232         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
233 
234         execRuntime.acquireEndpoint("some-id", route, null, context);
235         Assert.assertTrue(execRuntime.isEndpointAcquired());
236 
237         execRuntime.markConnectionReusable("some state", TimeValue.ofMilliseconds(100000));
238         execRuntime.markConnectionNonReusable();
239 
240         execRuntime.releaseEndpoint();
241 
242         Assert.assertFalse(execRuntime.isEndpointAcquired());
243 
244         Mockito.verify(connectionEndpoint, Mockito.times(1)).close(CloseMode.IMMEDIATE);
245         Mockito.verify(mgr).release(connectionEndpoint, null, TimeValue.ZERO_MILLISECONDS);
246 
247         execRuntime.releaseEndpoint();
248 
249         Mockito.verify(mgr, Mockito.times(1)).release(
250                 Mockito.<ConnectionEndpoint>any(),
251                 Mockito.any(),
252                 Mockito.<TimeValue>any());
253     }
254 
255     @Test
256     public void testConnectEndpoint() throws Exception {
257         final HttpClientContext context = HttpClientContext.create();
258         final RequestConfig config = RequestConfig.custom()
259                 .setConnectionRequestTimeout(345, TimeUnit.MILLISECONDS)
260                 .setConnectTimeout(123, TimeUnit.MILLISECONDS)
261                 .build();
262         context.setRequestConfig(config);
263 
264         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
265                 .thenReturn(leaseRequest);
266         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
267 
268         execRuntime.acquireEndpoint("some-id", route, null, context);
269         Assert.assertTrue(execRuntime.isEndpointAcquired());
270 
271         Mockito.when(connectionEndpoint.isConnected()).thenReturn(false);
272         Assert.assertFalse(execRuntime.isEndpointConnected());
273 
274         execRuntime.connectEndpoint(context);
275 
276         Mockito.verify(mgr).connect(connectionEndpoint, Timeout.ofMilliseconds(123), context);
277     }
278 
279     @Test
280     public void testDisonnectEndpoint() throws Exception {
281         final HttpClientContext context = HttpClientContext.create();
282 
283         Mockito.when(mgr.lease(Mockito.eq("some-id"), Mockito.eq(route), Mockito.<Timeout>any(), Mockito.any()))
284                 .thenReturn(leaseRequest);
285         Mockito.when(leaseRequest.get(Mockito.<Timeout>any())).thenReturn(connectionEndpoint);
286 
287         execRuntime.acquireEndpoint("some-id", route, null, context);
288         Assert.assertTrue(execRuntime.isEndpointAcquired());
289 
290         Mockito.when(connectionEndpoint.isConnected()).thenReturn(true);
291         Assert.assertTrue(execRuntime.isEndpointConnected());
292 
293         execRuntime.connectEndpoint(context);
294 
295         Mockito.verify(mgr, Mockito.never()).connect(
296                 Mockito.same(connectionEndpoint), Mockito.<TimeValue>any(), Mockito.<HttpClientContext>any());
297 
298         execRuntime.disconnectEndpoint();
299 
300         Mockito.verify(connectionEndpoint).close();
301     }
302 
303 }