1 /*
2 * $Header: /home/cvs/jakarta-commons/httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.8.2.3 2003/12/19 06:02:13 mbecke Exp $
3 * $Revision: 1.8.2.3 $
4 * $Date: 2003/12/19 06:02:13 $
5 * ====================================================================
6 *
7 * The Apache Software License, Version 1.1
8 *
9 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights
10 * reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided with the
22 * distribution.
23 *
24 * 3. The end-user documentation included with the redistribution, if
25 * any, must include the following acknowlegement:
26 * "This product includes software developed by the
27 * Apache Software Foundation (http://www.apache.org/)."
28 * Alternately, this acknowlegement may appear in the software itself,
29 * if and wherever such third-party acknowlegements normally appear.
30 *
31 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
32 * Foundation" must not be used to endorse or promote products derived
33 * from this software without prior written permission. For written
34 * permission, please contact apache@apache.org.
35 *
36 * 5. Products derived from this software may not be called "Apache"
37 * nor may "Apache" appear in their names without prior written
38 * permission of the Apache Group.
39 *
40 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
44 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 * ====================================================================
53 *
54 * This software consists of voluntary contributions made by many
55 * individuals on behalf of the Apache Software Foundation. For more
56 * information on the Apache Software Foundation, please see
57 * <http://www.apache.org/>.
58 *
59 * [Additional notices, if required by prior licensing conditions]
60 *
61 */
62
63 package org.apache.commons.httpclient;
64
65 import java.io.IOException;
66 import java.lang.ref.WeakReference;
67
68 import junit.framework.Test;
69 import junit.framework.TestSuite;
70
71 import org.apache.commons.httpclient.methods.GetMethod;
72
73 /***
74 * Unit tests for {@link HttpConnectionManager}.
75 *
76 * @author Marc A. Saegesser
77 * @version $Id: TestHttpConnectionManager.java,v 1.8.2.3 2003/12/19 06:02:13 mbecke Exp $
78 */
79 public class TestHttpConnectionManager extends TestLocalHostBase {
80
81 // ------------------------------------------------------------ Constructor
82 public TestHttpConnectionManager(String testName) {
83 super(testName);
84 }
85
86 // ------------------------------------------------------------------- Main
87 public static void main(String args[]) {
88 String[] testCaseName = { TestHttpConnectionManager.class.getName() };
89 junit.textui.TestRunner.main(testCaseName);
90 }
91
92 // ------------------------------------------------------- TestCase Methods
93
94 public static Test suite() {
95 return new TestSuite(TestHttpConnectionManager.class);
96 }
97
98
99 // ----------------------------------------------------------- Test Methods
100
101 // Test the accessor methods
102 public void testMaxConnectionsAccessors() {
103 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
104
105 // First test the default value
106 assertEquals("Default MaxConnections", 2, mgr.getMaxConnectionsPerHost());
107
108 mgr.setMaxConnectionsPerHost(10);
109 assertEquals("MaxConnections", 10, mgr.getMaxConnectionsPerHost());
110 }
111
112 /***
113 * Test that the ConnectMethod correctly releases connections when
114 * CONNECT fails.
115 */
116 public void testConnectMethodFailureRelease() {
117
118 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
119 mgr.setMaxTotalConnections(1);
120
121 // we're going to execute a connect method against the localhost, assuming
122 // that CONNECT is not supported. This should test the fakeResponse()
123 // code on HttpMethodBase.
124 HostConfiguration hostConfiguration = new HostConfiguration();
125 hostConfiguration.setHost(getHost(), getPort(), getProtocol());
126
127 GetMethod get = new GetMethod("/");
128 try {
129 HttpConnection connection = mgr.getConnection(hostConfiguration);
130 ConnectMethod connect = new ConnectMethod(get);
131 assertTrue(connect.execute(new HttpState(), connection) != 200);
132 } catch (IOException e) {
133 e.printStackTrace();
134 fail("Error executing connect: " + e);
135 }
136
137 // this should calling releaseConnection() releases the connection
138 try {
139 get.releaseConnection();
140 mgr.getConnection(hostConfiguration, 1).releaseConnection();
141 } catch (HttpException e1) {
142 fail("Connection should have been available.");
143 }
144
145 get = new GetMethod("/");
146
147 try {
148 HttpConnection connection = mgr.getConnection(hostConfiguration);
149 ConnectMethod connect = new ConnectMethod(get);
150 assertTrue(connect.execute(new HttpState(), connection) != 200);
151 } catch (IOException e) {
152 e.printStackTrace();
153 fail("Error executing connect: " + e);
154 }
155
156 // make sure reading the response fully releases the connection
157 try {
158 get.getResponseBodyAsString();
159 mgr.getConnection(hostConfiguration, 1).releaseConnection();
160 } catch (HttpException e1) {
161 fail("Connection should have been available.");
162 }
163
164 get = new GetMethod("/");
165
166 try {
167 HttpConnection connection = mgr.getConnection(hostConfiguration);
168 ConnectMethod connect = new ConnectMethod(get);
169 assertTrue(connect.execute(new HttpState(), connection) != 200);
170 } catch (IOException e) {
171 e.printStackTrace();
172 fail("Error executing connect: " + e);
173 }
174
175 // make sure closing the output stream releases the connection
176 try {
177 get.getResponseBodyAsStream().close();
178 mgr.getConnection(hostConfiguration, 1).releaseConnection();
179 } catch (HttpException e) {
180 fail("Connection should have been available.");
181 } catch (IOException e) {
182 e.printStackTrace();
183 fail("Close connection failed: " + e);
184 }
185 }
186
187 public void testGetConnection() {
188 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
189
190 HostConfiguration hostConfiguration = new HostConfiguration();
191 hostConfiguration.setHost("www.nosuchserver.com", 80, "http");
192
193 // Create a new connection
194 HttpConnection conn = mgr.getConnection(hostConfiguration);
195 // Validate the connection properties
196 assertEquals("Host", "www.nosuchserver.com", conn.getHost());
197 assertEquals("Port", 80, conn.getPort());
198 // Release the connection
199 mgr.releaseConnection(conn);
200
201 // Create a new connection
202 hostConfiguration.setHost("www.nosuchserver.com", -1, "https");
203 conn = mgr.getConnection(hostConfiguration);
204 // Validate the connection properties
205 assertEquals("Host", "www.nosuchserver.com", conn.getHost());
206 assertEquals("Port", 443, conn.getPort());
207 // Release the connection
208 mgr.releaseConnection(conn);
209
210 // Create a new connection
211 hostConfiguration.setHost("www.nowhere.org", 8080, "http");
212 conn = mgr.getConnection(hostConfiguration);
213 // Validate the connection properties
214 assertEquals("Host", "www.nowhere.org", conn.getHost());
215 assertEquals("Port", 8080, conn.getPort());
216 // Release the connection
217 mgr.releaseConnection(conn);
218
219 }
220
221 public void testDroppedThread() throws Exception {
222
223 MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
224 HttpClient httpClient = createHttpClient(mthcm);
225 WeakReference wr = new WeakReference(mthcm);
226
227 GetMethod method = new GetMethod("/");
228 httpClient.executeMethod(method);
229 method.releaseConnection();
230
231 mthcm = null;
232 httpClient = null;
233 method = null;
234
235 System.gc();
236
237 // this sleep appears to be necessary in order to give the JVM
238 // time to clean up the miscellaneous pointers to the connection manager
239 try {
240 Thread.sleep(1000);
241 } catch (InterruptedException e) {
242 fail("shouldn't be interrupted.");
243 }
244
245 Object connectionManager = wr.get();
246 assertNull("connectionManager should be null", connectionManager);
247 }
248
249 public void testWriteRequestReleaseConnection() {
250
251 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
252 connectionManager.setMaxConnectionsPerHost(1);
253
254 HttpClient client = createHttpClient(connectionManager);
255
256 GetMethod get = new GetMethod("/") {
257 protected boolean writeRequestBody(HttpState state, HttpConnection conn)
258 throws IOException, HttpException {
259 throw new IOException("Oh no!!");
260 }
261 };
262
263 try {
264 client.executeMethod(get);
265 fail("An exception should have occurred.");
266 } catch (HttpException e) {
267 e.printStackTrace();
268 fail("HttpException should not have occurred: " + e);
269 } catch (IOException e) {
270 // expected
271 }
272
273 try {
274 connectionManager.getConnection(client.getHostConfiguration(), 1);
275 } catch (HttpException e) {
276 e.printStackTrace();
277 fail("Connection was not released: " + e);
278 }
279
280 }
281
282 public void testReleaseConnection() {
283
284 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
285 connectionManager.setMaxConnectionsPerHost(1);
286
287 HttpClient client = createHttpClient(connectionManager);
288 // we shouldn't have to wait if a connection is available
289 client.setHttpConnectionFactoryTimeout( 1 );
290
291 GetMethod getMethod = new GetMethod("/");
292
293 try {
294 client.executeMethod(getMethod);
295 } catch (Exception e) {
296 fail("error reading from server: " + e);
297 }
298
299 try {
300 // this should fail quickly since the connection has not been released
301 client.executeMethod(getMethod);
302 fail("a httpConnection should not be available");
303 } catch (HttpException e) {
304 } catch (IOException e) {
305 fail("error reading from server; " + e);
306 }
307
308 // this should release the connection
309 getMethod.releaseConnection();
310
311 getMethod = new GetMethod("/");
312
313 try {
314 // this should fail quickly if the connection has not been released
315 client.executeMethod(getMethod);
316 } catch (HttpException e) {
317 fail("httpConnection does not appear to have been released: " + e);
318 } catch (IOException e) {
319 fail("error reading from server; " + e);
320 }
321
322 }
323
324 /***
325 * Makes sure that a connection gets released after the content of the body
326 * is read.
327 */
328 public void testResponseAutoRelease() {
329
330 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
331 connectionManager.setMaxConnectionsPerHost(1);
332
333 HttpClient client = createHttpClient(connectionManager);
334 // we shouldn't have to wait if a connection is available
335 client.setHttpConnectionFactoryTimeout( 1 );
336
337 GetMethod getMethod = new GetMethod("/");
338
339 try {
340 client.executeMethod(getMethod);
341 } catch (Exception e) {
342 fail("error reading from server: " + e);
343 }
344
345 // this should release the connection
346 getMethod.getResponseBody();
347
348 getMethod = new GetMethod("/");
349
350 try {
351 // this should fail quickly if the connection has not been released
352 client.executeMethod(getMethod);
353 } catch (HttpException e) {
354 fail("httpConnection does not appear to have been released: " + e);
355 } catch (IOException e) {
356 fail("error reading from server; " + e);
357 }
358
359 }
360
361 /***
362 * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused
363 * connections.
364 */
365 public void testConnectionReclaiming() {
366
367 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
368 connectionManager.setMaxConnectionsPerHost(1);
369 connectionManager.setMaxTotalConnections(1);
370
371 HostConfiguration host1 = new HostConfiguration();
372 host1.setHost("host1", -1, "http");
373
374 HostConfiguration host2 = new HostConfiguration();
375 host2.setHost("host2", -1, "http");
376
377 HttpConnection connection = connectionManager.getConnection(host1);
378 // now release this connection
379 connection.releaseConnection();
380 connection = null;
381
382 try {
383 // the connection from host1 should be reclaimed
384 connection = connectionManager.getConnection(host2, 100);
385 } catch (HttpException e) {
386 e.printStackTrace();
387 fail("a httpConnection should have been available: " + e);
388 }
389 }
390
391 /***
392 * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number
393 * of connections.
394 */
395 public void testMaxConnections() {
396
397 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
398 connectionManager.setMaxConnectionsPerHost(1);
399 connectionManager.setMaxTotalConnections(2);
400
401 HostConfiguration host1 = new HostConfiguration();
402 host1.setHost("host1", -1, "http");
403
404 HostConfiguration host2 = new HostConfiguration();
405 host2.setHost("host2", -1, "http");
406
407 HttpConnection connection1 = connectionManager.getConnection(host1);
408 HttpConnection connection2 = connectionManager.getConnection(host2);
409
410 try {
411 // this should fail quickly since the connection has not been released
412 connectionManager.getConnection(host2, 100);
413 fail("a httpConnection should not be available");
414 } catch (HttpException e) {
415 // this should throw an exception
416 }
417
418 // release one of the connections
419 connection2.releaseConnection();
420 connection2 = null;
421
422 try {
423 // there should be a connection available now
424 connection2 = connectionManager.getConnection(host2, 100);
425 } catch (HttpException e) {
426 e.printStackTrace();
427 fail("a httpConnection should have been available: " + e);
428 }
429 }
430
431 public void testHostReusePreference() {
432
433 final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
434 connectionManager.setMaxConnectionsPerHost(1);
435 connectionManager.setMaxTotalConnections(1);
436
437 final HostConfiguration host1 = new HostConfiguration();
438 host1.setHost("host1", -1, "http");
439
440 final HostConfiguration host2 = new HostConfiguration();
441 host2.setHost("host2", -1, "http");
442
443 HttpConnection connection = connectionManager.getConnection(host1);
444
445 GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
446 GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
447
448 getHost2.start();
449 getHost1.start();
450
451 // give the threads some time to startup
452 try {
453 Thread.sleep(100);
454 } catch (InterruptedException e1) {
455 e1.printStackTrace();
456 }
457
458 // after the connection to host1 is released it should be given to getHost1
459 connection.releaseConnection();
460 connection = null;
461
462 try {
463 getHost1.join();
464 getHost2.join();
465 } catch (InterruptedException e) {
466 e.printStackTrace();
467 }
468
469 assertNotSame(
470 "Connection should have been given to someone",
471 getHost1.getConnection(),
472 getHost2.getConnection()
473 );
474 assertNotNull("Connection should have been given to host1", getHost1.getConnection());
475 assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
476
477 }
478
479 public void testMaxConnectionsPerServer() {
480
481 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
482 connectionManager.setMaxConnectionsPerHost(1);
483
484 HttpClient client = createHttpClient(connectionManager);
485 // we shouldn't have to wait if a connection is available
486 client.setHttpConnectionFactoryTimeout( 1 );
487
488 GetMethod getMethod = new GetMethod("/");
489
490 try {
491 client.executeMethod(getMethod);
492 } catch (Exception e) {
493 fail("error reading from server: " + e);
494 }
495
496 GetMethod getMethod2 = new GetMethod("/");
497
498 try {
499 // this should fail quickly since the connection has not been released
500 client.executeMethod(getMethod2);
501 fail("a httpConnection should not be available");
502 } catch (HttpException e) {
503 } catch (IOException e) {
504 fail("error reading from server; " + e);
505 }
506
507 }
508
509 public void testReclaimUnusedConnection() {
510
511 MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
512 connectionManager.setMaxConnectionsPerHost(1);
513
514 HttpClient client = createHttpClient(connectionManager);
515 // we shouldn't have to wait if a connection is available
516 client.setHttpConnectionFactoryTimeout( 30000 );
517
518 GetMethod getMethod = new GetMethod("/");
519
520 try {
521 client.executeMethod(getMethod);
522 } catch (Exception e) {
523 fail("error reading from server: " + e);
524 }
525
526 getMethod = new GetMethod("/");
527
528 Runtime.getRuntime().gc();
529
530 try {
531 // we didn't explicitly release the connection, but it should be
532 // reclaimed by the garbage collector, we hope:)
533 client.executeMethod(getMethod);
534 } catch (HttpException e) {
535 fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
536 } catch (IOException e) {
537 fail("error reading from server; " + e);
538 }
539
540 }
541
542 public void testGetFromMultipleThreads() {
543
544 HttpClient client = createHttpClient(new MultiThreadedHttpConnectionManager());
545 ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
546
547 for (int i = 0; i < threads.length; i++) {
548 GetMethod method = new GetMethod("/");
549 method.setFollowRedirects(true);
550
551 threads[i] = new ExecuteMethodThread(method, client);
552 threads[i].start();
553 }
554
555 for (int i = 0; i < threads.length; i++) {
556 try {
557 // wait until this thread finishes. we'll give it 10 seconds,
558 // but it shouldn't take that long
559 threads[i].join(10000);
560 } catch (InterruptedException e) {
561 }
562 // make sure an exception did not occur
563 Exception e = threads[i].getException();
564 if (e != null) {
565 fail("An error occured in the get: " + e);
566 }
567 // we should have a 200 status
568 assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
569 }
570 }
571
572 public void testTimeout() {
573 MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
574 mgr.setMaxConnectionsPerHost(2);
575
576 try{
577 HostConfiguration hostConfig = new HostConfiguration();
578 hostConfig.setHost("www.nosuchserver.com", 80, "http");
579
580 HttpConnection conn1 = mgr.getConnection(hostConfig);
581 HttpConnection conn2 = mgr.getConnection(hostConfig);
582
583 HttpConnection conn3 = mgr.getConnection(hostConfig, 1000);
584 fail("Expected an HttpException.");
585
586 }catch(HttpException e){
587 //Expected result
588 }
589 }
590
591 static class GetConnectionThread extends Thread {
592
593 private HostConfiguration hostConfiguration;
594 private MultiThreadedHttpConnectionManager connectionManager;
595 private HttpConnection connection;
596 private long timeout;
597
598 public GetConnectionThread(
599 HostConfiguration hostConfiguration,
600 MultiThreadedHttpConnectionManager connectionManager,
601 long timeout
602 ) {
603 this.hostConfiguration = hostConfiguration;
604 this.connectionManager = connectionManager;
605 this.timeout = timeout;
606 }
607
608 public void run() {
609 try {
610 connection = connectionManager.getConnection(hostConfiguration, timeout);
611 } catch (HttpException e) {
612 }
613 }
614
615 public HttpConnection getConnection() {
616 return connection;
617 }
618
619 }
620
621 }
622
This page was automatically generated by Maven