    1   /*
    2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/test/org/apache/commons/httpclient/TestHttpConnectionManager.java,v 1.23 2004/07/17 18:58:33 mbecke Exp $
    3    * $Revision: 509320 $
    4    * $Date: 2007-02-19 20:52:43 +0100 (Mon, 19 Feb 2007) $
    5    * ====================================================================
    6    *
    7    *  Licensed to the Apache Software Foundation (ASF) under one or more
    8    *  contributor license agreements.  See the NOTICE file distributed with
    9    *  this work for additional information regarding copyright ownership.
    10   *  The ASF licenses this file to You under the Apache License, Version 2.0
    11   *  (the "License"); you may not use this file except in compliance with
    12   *  the License.  You may obtain a copy of the License at
    13   *
    14   *      http://www.apache.org/licenses/LICENSE-2.0
    15   *
    16   *  Unless required by applicable law or agreed to in writing, software
    17   *  distributed under the License is distributed on an "AS IS" BASIS,
    18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    19   *  See the License for the specific language governing permissions and
    20   *  limitations under the License.
    21   * ====================================================================
    22   *
    23   * This software consists of voluntary contributions made by many
    24   * individuals on behalf of the Apache Software Foundation.  For more
    25   * information on the Apache Software Foundation, please see
    26   * <http://www.apache.org/>.
    27   */
    28
    29  package org.apache.commons.httpclient;
    30
    31  import java.io.IOException;
    32  import java.lang.ref.WeakReference;
    33  import java.net.InetAddress;
    34  import java.net.Socket;
    35  import java.net.UnknownHostException;
    36
    37  import junit.framework.Test;
    38  import junit.framework.TestSuite;
    39
    40  import org.apache.commons.httpclient.methods.GetMethod;
    41  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
    42  import org.apache.commons.httpclient.params.HttpConnectionParams;
    43  import org.apache.commons.httpclient.protocol.Protocol;
    44  import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
    45  import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
    46  import org.apache.commons.httpclient.server.SimpleRequest;
    47  import org.apache.commons.httpclient.server.SimpleResponse;
    48
    49  /**
    50   * Unit tests for {@link HttpConnectionManager}.
    51   *
    52   * @author Marc A. Saegesser
    53   * @version $Id: TestHttpConnectionManager.java 509320 2007-02-19 19:52:43Z mbecke $
    54   */
    55  public class TestHttpConnectionManager extends HttpClientTestBase {
    56
    57      // ------------------------------------------------------------ Constructor
    58      public TestHttpConnectionManager(String testName) throws IOException {
    59          super(testName);
    60      }
    61
    62      // ------------------------------------------------------------------- Main
    63      public static void main(String args[]) {
    64          String[] testCaseName = { TestHttpConnectionManager.class.getName() };
    65          junit.textui.TestRunner.main(testCaseName);
    66      }
    67
    68      // ------------------------------------------------------- TestCase Methods
    69
    70      public static Test suite() {
    71          return new TestSuite(TestHttpConnectionManager.class);
    72      }
    73
    74
    75      // ----------------------------------------------------------- Test Methods
    76
    77      /**
    78       * Test that the ConnectMethod correctly releases connections when
    79       * CONNECT fails.
    80       */
    81      public void testConnectMethodFailureRelease() throws Exception {
    82
    83          MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
    84          mgr.getParams().setIntParameter(
    85              HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
    86          client.setHttpConnectionManager(mgr);
    87          this.server.setHttpService(new RejectConnectService());
    88
    89          // we're going to execute a connect method against the localhost, assuming
    90          // that CONNECT is not supported.  This should test the fakeResponse()
    91          // code on HttpMethodBase.
    92          client.getHostConfiguration().setProxy(server.getLocalAddress(), server.getLocalPort());
    93          // we must set the host to a secure destination or the CONNECT method
    94          // will not be used
    95          client.getHostConfiguration().setHost(
    96              "notARealHost",
    97              1234,
    98              new Protocol(
    99                  "https",
    100                 (ProtocolSocketFactory)new FakeSecureProtocolSocketFactory(),
    101                 443)
    102         );
    103
    104         GetMethod get = new GetMethod("/");
    105         try {
    106             assertTrue(client.executeMethod(get) != 200);
    107         } catch (IOException e) {
    108             e.printStackTrace();
    109             fail("Error executing connect: " + e);
    110         }
    111
    112         // this should calling releaseConnection() releases the connection
    113         try {
    114             get.releaseConnection();
    115             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
    116         } catch (ConnectTimeoutException e1) {
    117             fail("Connection should have been available.");
    118         }
    119
    120         get = new GetMethod("/");
    121
    122         try {
    123             assertTrue(client.executeMethod(get) != 200);
    124         } catch (IOException e) {
    125             e.printStackTrace();
    126             fail("Error executing connect: " + e);
    127         }
    128
    129         // make sure reading the response fully releases the connection
    130         try {
    131             get.getResponseBodyAsString();
    132             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
    133         } catch (ConnectTimeoutException e1) {
    134             fail("Connection should have been available.");
    135         }
    136
    137         get = new GetMethod("/");
    138
    139         try {
    140             assertTrue(client.executeMethod(get) != 200);
    141         } catch (IOException e) {
    142             e.printStackTrace();
    143             fail("Error executing connect: " + e);
    144         }
    145
    146         // make sure closing the output stream releases the connection
    147         try {
    148             get.getResponseBodyAsStream().close();
    149             mgr.getConnectionWithTimeout(client.getHostConfiguration(), 1).releaseConnection();
    150         } catch (ConnectTimeoutException e) {
    151             fail("Connection should have been available.");
    152         } catch (IOException e) {
    153             e.printStackTrace();
    154             fail("Close connection failed: " + e);
    155         }
    156     }
    157
    158     public void testGetConnection() {
    159         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
    160
    161         HostConfiguration hostConfiguration = new HostConfiguration();
    162         hostConfiguration.setHost("www.nosuchserver.com", 80, "http");
    163
    164         // Create a new connection
    165         HttpConnection conn = mgr.getConnection(hostConfiguration);
    166         // Validate the connection properties
    167         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
    168         assertEquals("Port", 80, conn.getPort());
    169         // Release the connection
    170         mgr.releaseConnection(conn);
    171
    172         // Create a new connection
    173         hostConfiguration.setHost("www.nosuchserver.com", -1, "https");
    174         conn = mgr.getConnection(hostConfiguration);
    175         // Validate the connection properties
    176         assertEquals("Host", "www.nosuchserver.com", conn.getHost());
    177         assertEquals("Port", 443, conn.getPort());
    178         // Release the connection
    179         mgr.releaseConnection(conn);
    180
    181         // Create a new connection
    182         hostConfiguration.setHost("www.nowhere.org", 8080, "http");
    183         conn = mgr.getConnection(hostConfiguration);
    184         // Validate the connection properties
    185         assertEquals("Host", "www.nowhere.org", conn.getHost());
    186         assertEquals("Port", 8080, conn.getPort());
    187         // Release the connection
    188         mgr.releaseConnection(conn);
    189
    190     }
    191
    192     public void testDroppedThread() throws Exception {
    193
    194         this.server.setHttpService(new EchoService());
    195
    196         MultiThreadedHttpConnectionManager mthcm = new MultiThreadedHttpConnectionManager();
    197         client.setHttpConnectionManager(mthcm);
    198         WeakReference wr = new WeakReference(mthcm);
    199
    200         GetMethod method = new GetMethod("/");
    201         client.executeMethod(method);
    202         method.releaseConnection();
    203
    204         mthcm = null;
    205         client = null;
    206         method = null;
    207
    208         System.gc();
    209
    210         // this sleep appears to be necessary in order to give the JVM
    211         // time to clean up the miscellaneous pointers to the connection manager
    212         try {
    213             Thread.sleep(1000);
    214         } catch (InterruptedException e) {
    215             fail("shouldn't be interrupted.");
    216         }
    217
    218         Object connectionManager = wr.get();
    219         assertNull("connectionManager should be null", connectionManager);
    220     }
    221
    222     public void testWriteRequestReleaseConnection() {
    223
    224         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    225         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    226
    227         client.setHttpConnectionManager(connectionManager);
    228
    229         GetMethod get = new GetMethod("/") {
    230             protected boolean writeRequestBody(HttpState state, HttpConnection conn)
    231                 throws IOException, HttpException {
    232                 throw new IOException("Oh no!!");
    233             }
    234         };
    235
    236         try {
    237             client.executeMethod(get);
    238             fail("An exception should have occurred.");
    239         } catch (HttpException e) {
    240             e.printStackTrace();
    241             fail("HttpException should not have occurred: " + e);
    242         } catch (IOException e) {
    243             // expected
    244         }
    245
    246         try {
    247             connectionManager.getConnectionWithTimeout(client.getHostConfiguration(), 1);
    248         } catch (ConnectTimeoutException e) {
    249             e.printStackTrace();
    250             fail("Connection was not released: " + e);
    251         }
    252
    253     }
    254
    255     public void testReleaseConnection() {
    256
    257         this.server.setHttpService(new EchoService());
    258
    259         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    260         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    261
    262         client.setHttpConnectionManager(connectionManager);
    263         // we shouldn't have to wait if a connection is available
    264         client.getParams().setConnectionManagerTimeout(1);
    265
    266         GetMethod getMethod = new GetMethod("/");
    267
    268         try {
    269             client.executeMethod(getMethod);
    270         } catch (Exception e) {
    271             fail("error reading from server: " + e);
    272         }
    273
    274         try {
    275             // this should fail quickly since the connection has not been released
    276             client.executeMethod(getMethod);
    277             fail("a httpConnection should not be available");
    278         } catch (ConnectTimeoutException e) {
    279         } catch (HttpException e) {
    280             fail("error reading from server; " + e);
    281         } catch (IOException e) {
    282             e.printStackTrace();
    283             fail("error reading from server; " + e);
    284         }
    285
    286         // this should release the connection
    287         getMethod.releaseConnection();
    288
    289         getMethod = new GetMethod("/");
    290
    291         try {
    292             // this should fail quickly if the connection has not been released
    293             client.executeMethod(getMethod);
    294         } catch (HttpException e) {
    295             fail("httpConnection does not appear to have been released: " + e);
    296         } catch (IOException e) {
    297             fail("error reading from server; " + e);
    298         }
    299
    300     }
    301
    302     /**
    303      * Makes sure that a connection gets released after the content of the body
    304      * is read.
    305      */
    306     public void testResponseAutoRelease() throws Exception  {
    307
    308         this.server.setHttpService(new EchoService());
    309
    310         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    311         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    312
    313         client.setHttpConnectionManager(connectionManager);
    314         // we shouldn't have to wait if a connection is available
    315         client.getParams().setConnectionManagerTimeout( 1 );
    316
    317         GetMethod getMethod = new GetMethod("/");
    318
    319         try {
    320             client.executeMethod(getMethod);
    321         } catch (Exception e) {
    322             fail("error reading from server: " + e);
    323         }
    324
    325         // this should release the connection
    326         getMethod.getResponseBody();
    327
    328         getMethod = new GetMethod("/");
    329
    330         try {
    331             // this should fail quickly if the connection has not been released
    332             client.executeMethod(getMethod);
    333         } catch (HttpException e) {
    334             fail("httpConnection does not appear to have been released: " + e);
    335         } catch (IOException e) {
    336             fail("error reading from server; " + e);
    337         }
    338
    339     }
    340
    341     /**
    342      * Tests the MultiThreadedHttpConnectionManager's ability to reclaim unused
    343      * connections.
    344      */
    345     public void testConnectionReclaiming() {
    346
    347         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    348         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    349         connectionManager.getParams().setMaxTotalConnections(1);
    350
    351         HostConfiguration host1 = new HostConfiguration();
    352         host1.setHost("host1", -1, "http");
    353
    354         HostConfiguration host2 = new HostConfiguration();
    355         host2.setHost("host2", -1, "http");
    356
    357         HttpConnection connection = connectionManager.getConnection(host1);
    358         // now release this connection
    359         connection.releaseConnection();
    360         connection = null;
    361
    362         try {
    363             // the connection from host1 should be reclaimed
    364             connection = connectionManager.getConnectionWithTimeout(host2, 100);
    365         } catch (ConnectTimeoutException e) {
    366             e.printStackTrace();
    367             fail("a httpConnection should have been available: " + e);
    368         }
    369     }
    370
    371     /**
    372      * Tests that {@link MultiThreadedHttpConnectionManager#shutdownAll()} closes all resources
    373      * and makes all connection mangers unusable.
    374      */
    375     public void testShutdownAll() {
    376
    377         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    378         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    379         connectionManager.getParams().setMaxTotalConnections(1);
    380
    381         HostConfiguration host1 = new HostConfiguration();
    382         host1.setHost("host1", -1, "http");
    383
    384         // hold on to the only connection
    385         HttpConnection connection = connectionManager.getConnection(host1);
    386
    387         // wait for a connection on another thread
    388         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
    389         getConn.start();
    390
    391         MultiThreadedHttpConnectionManager.shutdownAll();
    392
    393         // now release this connection, this should close the connection, but have no other effect
    394         connection.releaseConnection();
    395         connection = null;
    396
    397         try {
    398             getConn.join();
    399         } catch (InterruptedException e) {
    400             e.printStackTrace();
    401         }
    402
    403         // this thread should have caught an exception without getting a connection
    404         assertNull("Not connection should have been checked out", getConn.getConnection());
    405         assertNotNull("There should have been an exception", getConn.getException());
    406
    407         try {
    408             connectionManager.getConnection(host1);
    409             fail("An exception should have occurred");
    410         } catch (Exception e) {
    411             // this is expected
    412         }
    413     }
    414
    415     /**
    416      * Tests that {@link MultiThreadedHttpConnectionManager#shutdown()} closes all resources
    417      * and makes the connection manger unusable.
    418      */
    419     public void testShutdown() {
    420
    421         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    422         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    423         connectionManager.getParams().setMaxTotalConnections(1);
    424
    425         HostConfiguration host1 = new HostConfiguration();
    426         host1.setHost("host1", -1, "http");
    427
    428         // hold on to the only connection
    429         HttpConnection connection = connectionManager.getConnection(host1);
    430
    431         // wait for a connection on another thread
    432         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 0);
    433         getConn.start();
    434
    435         connectionManager.shutdown();
    436
    437         // now release this connection, this should close the connection, but have no other effect
    438         connection.releaseConnection();
    439         connection = null;
    440
    441         try {
    442             getConn.join();
    443         } catch (InterruptedException e) {
    444             e.printStackTrace();
    445         }
    446
    447         // this thread should have caught an exception without getting a connection
    448         assertNull("Not connection should have been checked out", getConn.getConnection());
    449         assertNotNull("There should have been an exception", getConn.getException());
    450
    451         try {
    452             connectionManager.getConnection(host1);
    453             fail("An exception should have occurred");
    454         } catch (Exception e) {
    455             // this is expected
    456         }
    457     }
    458
    459     /**
    460      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number
    461      * of connections.
    462      */
    463     public void testMaxConnections() {
    464
    465         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    466         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    467         connectionManager.getParams().setMaxTotalConnections(2);
    468
    469         HostConfiguration host1 = new HostConfiguration();
    470         host1.setHost("host1", -1, "http");
    471
    472         HostConfiguration host2 = new HostConfiguration();
    473         host2.setHost("host2", -1, "http");
    474
    475         HttpConnection connection1 = connectionManager.getConnection(host1);
    476         HttpConnection connection2 = connectionManager.getConnection(host2);
    477
    478         try {
    479             // this should fail quickly since the connection has not been released
    480             connectionManager.getConnectionWithTimeout(host2, 100);
    481             fail("ConnectionPoolTimeoutException should not be available");
    482         } catch (ConnectionPoolTimeoutException e) {
    483             // this should throw an exception
    484         }
    485
    486         // release one of the connections
    487         connection2.releaseConnection();
    488         connection2 = null;
    489
    490         try {
    491             // there should be a connection available now
    492             connection2 = connectionManager.getConnectionWithTimeout(host2, 100);
    493         } catch (ConnectionPoolTimeoutException e) {
    494             e.printStackTrace();
    495             fail("a httpConnection should have been available: " + e);
    496         }
    497     }
    498
    499     /**
    500      * Tests the MultiThreadedHttpConnectionManager's ability to restrict the maximum number
    501      * of connections per host.
    502      */
    503     public void testMaxConnectionsPerHost() throws Exception {
    504
    505         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    506         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    507         connectionManager.getParams().setMaxTotalConnections(100);
    508
    509         HostConfiguration host1 = new HostConfiguration();
    510         host1.setHost("host1", -1, "http");
    511
    512         HostConfiguration host2 = new HostConfiguration();
    513         host2.setHost("host2", -1, "http");
    514
    515         HostConfiguration host3 = new HostConfiguration();
    516         host3.setHost("host3", -1, "http");
    517
    518         connectionManager.getParams().setMaxConnectionsPerHost(host1, 3);
    519         connectionManager.getParams().setMaxConnectionsPerHost(host2, 2);
    520
    521         // Host1
    522         HttpConnection connection1 = connectionManager.getConnectionWithTimeout(host1, 1000);
    523         HttpConnection connection2 = connectionManager.getConnectionWithTimeout(host1, 1000);
    524         HttpConnection connection3 = connectionManager.getConnectionWithTimeout(host1, 1000);
    525         try {
    526             // this should fail quickly since the connection has not been released
    527             connectionManager.getConnectionWithTimeout(host1, 100);
    528             fail("ConnectionPoolTimeoutException should not be available");
    529         } catch (ConnectionPoolTimeoutException e) {
    530             // expected
    531         }
    532
    533         // Host2
    534         connection1 = connectionManager.getConnectionWithTimeout(host2, 1000);
    535         connection2 = connectionManager.getConnectionWithTimeout(host2, 1000);
    536         try {
    537             // this should fail quickly since the connection has not been released
    538             connectionManager.getConnectionWithTimeout(host2, 100);
    539             fail("ConnectionPoolTimeoutException should not be available");
    540         } catch (ConnectionPoolTimeoutException e) {
    541             // expected
    542         }
    543
    544         // Host3 (should use the default per host value)
    545         connection1 = connectionManager.getConnectionWithTimeout(host3, 1000);
    546         try {
    547             // this should fail quickly since the connection has not been released
    548             connectionManager.getConnectionWithTimeout(host3, 100);
    549             fail("ConnectionPoolTimeoutException should not be available");
    550         } catch (ConnectionPoolTimeoutException e) {
    551             // expected
    552         }
    553     }
    554
    555     public void testHostReusePreference() {
    556
    557         final MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    558         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    559         connectionManager.getParams().setMaxTotalConnections(1);
    560
    561         final HostConfiguration host1 = new HostConfiguration();
    562         host1.setHost("host1", -1, "http");
    563
    564         final HostConfiguration host2 = new HostConfiguration();
    565         host2.setHost("host2", -1, "http");
    566
    567         HttpConnection connection = connectionManager.getConnection(host1);
    568
    569         GetConnectionThread getHost1 = new GetConnectionThread(host1, connectionManager, 200);
    570         GetConnectionThread getHost2 = new GetConnectionThread(host2, connectionManager, 200);
    571
    572         getHost2.start();
    573         getHost1.start();
    574
    575         // give the threads some time to startup
    576         try {
    577             Thread.sleep(100);
    578         } catch (InterruptedException e1) {
    579             e1.printStackTrace();
    580         }
    581
    582         // after the connection to host1 is released it should be given to getHost1
    583         connection.releaseConnection();
    584         connection = null;
    585
    586         try {
    587             getHost1.join();
    588             getHost2.join();
    589         } catch (InterruptedException e) {
    590             e.printStackTrace();
    591         }
    592
    593         assertNotSame(
    594             "Connection should have been given to someone",
    595             getHost1.getConnection(),
    596             getHost2.getConnection()
    597         );
    598         assertNotNull("Connection should have been given to host1", getHost1.getConnection());
    599         assertNull("Connection should NOT have been given to host2", getHost2.getConnection());
    600
    601     }
    602
    603     public void testMaxConnectionsPerServer() {
    604
    605         this.server.setHttpService(new EchoService());
    606
    607         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    608         connectionManager.getParams().setDefaultMaxConnectionsPerHost(1);
    609
    610         client.setHttpConnectionManager(connectionManager);
    611         // we shouldn't have to wait if a connection is available
    612         client.getParams().setConnectionManagerTimeout( 1 );
    613
    614         GetMethod getMethod = new GetMethod("/");
    615
    616         try {
    617             client.executeMethod(getMethod);
    618         } catch (Exception e) {
    619             fail("error reading from server: " + e);
    620         }
    621
    622         GetMethod getMethod2 = new GetMethod("/");
    623
    624         try {
    625             // this should fail quickly since the connection has not been released
    626             client.executeMethod(getMethod2);
    627             fail("a httpConnection should not be available");
    628         } catch (ConnectTimeoutException e) {
    629         } catch (HttpException e) {
    630             fail("error reading from server; " + e);
    631         } catch (IOException e) {
    632             fail("error reading from server; " + e);
    633         }
    634
    635     }
    636
    637     public void testDeleteClosedConnections() {
    638
    639         MultiThreadedHttpConnectionManager manager = new MultiThreadedHttpConnectionManager();
    640
    641         HttpConnection conn = manager.getConnection(client.getHostConfiguration());
    642
    643         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
    644         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
    645
    646         conn.close();
    647         conn.releaseConnection();
    648
    649         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 1);
    650         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 1);
    651
    652         manager.deleteClosedConnections();
    653
    654         assertEquals("connectionsInPool", manager.getConnectionsInPool(), 0);
    655         assertEquals("connectionsInPool(host)", manager.getConnectionsInPool(client.getHostConfiguration()), 0);
    656     }
    657
    658     /**
    659      * Tests that thread waiting in the MultiThreadedHttpConnectionManager can be
    660      * interrupted.
    661      */
    662     public void testWaitingThreadInterrupted() {
    663
    664         this.server.setHttpService(new EchoService());
    665
    666         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    667         connectionManager.getParams().setIntParameter(
    668             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
    669
    670         HostConfiguration host1 = new HostConfiguration();
    671         host1.setHost("host1", -1, "http");
    672
    673         // hold on to the only connection
    674         HttpConnection connection = connectionManager.getConnection(host1);
    675
    676         // wait for a connection on another thread
    677         GetConnectionThread getConn = new GetConnectionThread(host1, connectionManager, 1000);
    678         getConn.start();
    679
    680         // give the thread a chance to block
    681         synchronized (this) {
    682             try {
    683                 this.wait(500);
    684             } catch (InterruptedException e) {
    685                 e.printStackTrace();
    686             }
    687         }
    688
    689         // interrupt the thread, this should cancel waiting with a RuntimeException
    690         getConn.interrupt();
    691
    692         try {
    693             getConn.join();
    694         } catch (InterruptedException e) {
    695             e.printStackTrace();
    696         }
    697
    698         // make sure the correct exception was thrown
    699         assertTrue(getConn.exception != null);
    700         assertEquals(getConn.exception.getClass(), IllegalThreadStateException.class);
    701
    702         // make sure the connection manager is still working
    703         connection.releaseConnection();
    704         try {
    705             connectionManager.getConnectionWithTimeout(host1, 10);
    706         } catch (ConnectionPoolTimeoutException e) {
    707             fail("Connection not available");
    708         }
    709     }
    710
    711     public void testReclaimUnusedConnection() {
    712
    713         this.server.setHttpService(new EchoService());
    714
    715         MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
    716         connectionManager.getParams().setIntParameter(
    717             HttpConnectionManagerParams.MAX_TOTAL_CONNECTIONS, 1);
    718
    719         client.setHttpConnectionManager(connectionManager);
    720         // we shouldn't have to wait if a connection is available
    721         client.getParams().setConnectionManagerTimeout( 30000 );
    722
    723         GetMethod getMethod = new GetMethod("/");
    724
    725         try {
    726             client.executeMethod(getMethod);
    727         } catch (Exception e) {
    728             fail("error reading from server: " + e);
    729         }
    730
    731         getMethod = new GetMethod("/");
    732
    733         Runtime.getRuntime().gc();
    734
    735         try {
    736             // we didn't explicitly release the connection, but it should be
    737             // reclaimed by the garbage collector, we hope:)
    738             client.executeMethod(getMethod);
    739         } catch (HttpException e) {
    740             fail("httpConnection does not appear to have been reclaimed by the GC: " + e);
    741         } catch (IOException e) {
    742             fail("error reading from server; " + e);
    743         }
    744
    745     }
    746
    747     public void testGetFromMultipleThreads() {
    748
    749         this.server.setHttpService(new EchoService());
    750
    751         client.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
    752         ExecuteMethodThread[] threads = new ExecuteMethodThread[10];
    753
    754         for (int i = 0; i < threads.length; i++) {
    755             GetMethod method = new GetMethod("/");
    756             method.setFollowRedirects(true);
    757
    758             threads[i] = new ExecuteMethodThread(method, client);
    759             threads[i].start();
    760         }
    761
    762         for (int i = 0; i < threads.length; i++) {
    763             try {
    764                 // wait until this thread finishes. we'll give it 10 seconds,
    765                 // but it shouldn't take that long
    766                 threads[i].join(10000);
    767             } catch (InterruptedException e) {
    768             }
    769             // make sure an exception did not occur
    770             Exception e = threads[i].getException();
    771             if (e != null) {
    772                 fail("An error occured in the get: " + e);
    773             }
    774             // we should have a 200 status
    775             assertEquals(threads[i].getMethod().getStatusCode(), HttpStatus.SC_OK);
    776         }
    777     }
    778
    779     public void testTimeout() {
    780         MultiThreadedHttpConnectionManager mgr = new MultiThreadedHttpConnectionManager();
    781         mgr.getParams().setDefaultMaxConnectionsPerHost(2);
    782
    783         try{
    784             HostConfiguration hostConfig = new HostConfiguration();
    785             hostConfig.setHost("www.nosuchserver.com", 80, "http");
    786
    787             HttpConnection conn1 = mgr.getConnection(hostConfig);
    788             HttpConnection conn2 = mgr.getConnection(hostConfig);
    789
    790             HttpConnection conn3 = mgr.getConnectionWithTimeout(hostConfig, 1000);
    791             fail("Expected an HttpException.");
    792
    793         }catch(ConnectTimeoutException e){
    794             //Expected result
    795         }
    796     }
    797
    798     static class FakeSecureProtocolSocketFactory implements SecureProtocolSocketFactory {
    799
    800         public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
    801             throws IOException, UnknownHostException {
    802             throw new IllegalStateException("createSocket() should never have been called.");
    803         }
    804
    805         public Socket createSocket(String host, int port)
    806             throws IOException, UnknownHostException {
    807             throw new IllegalStateException("createSocket() should never have been called.");
    808         }
    809
    810         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort)
    811             throws IOException, UnknownHostException {
    812             throw new IllegalStateException("createSocket() should never have been called.");
    813         }
    814
    815         public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort,
    816             HttpConnectionParams params)
    817             throws IOException, UnknownHostException {
    818             throw new IllegalStateException("createSocket() should never have been called.");
    819         }
    820     }
    821
    822     static class RejectConnectService extends EchoService {
    823 		public boolean process(SimpleRequest request, SimpleResponse response)
    824 				throws IOException {
    825             if (request.getRequestLine().getMethod().equalsIgnoreCase("CONNECT")) {
    826                 response.setStatusLine(request.getRequestLine().getHttpVersion(), HttpStatus.SC_METHOD_NOT_ALLOWED);
    827                 response.setHeader(new Header("Connection", "close"));
    828                 return true;
    829             } else {
    830                 return super.process(request, response);
    831             }
    832 		}
    833     }
    834
    835     static class GetConnectionThread extends Thread {
    836
    837         private HostConfiguration hostConfiguration;
    838         private MultiThreadedHttpConnectionManager connectionManager;
    839         private HttpConnection connection;
    840         private long timeout;
    841         private Exception exception;
    842
    843         public GetConnectionThread(
    844             HostConfiguration hostConfiguration,
    845             MultiThreadedHttpConnectionManager connectionManager,
    846             long timeout
    847         ) {
    848             this.hostConfiguration = hostConfiguration;
    849             this.connectionManager = connectionManager;
    850             this.timeout = timeout;
    851         }
    852
    853         public void run() {
    854             try {
    855                 connection = connectionManager.getConnectionWithTimeout(hostConfiguration, timeout);
    856             } catch (Exception e) {
    857                 this.exception = e;
    858             }
    859         }
    860
    861         public Exception getException() {
    862             return exception;
    863         }
    864
    865         public HttpConnection getConnection() {
    866             return connection;
    867         }
    868
    869     }
    870
    871 }
    872