@Test
  public void testCreateNewIfExpired() throws Exception {
    final LocalConnFactory connFactory = Mockito.mock(LocalConnFactory.class);

    final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn1.isOpen()).thenReturn(true);
    Mockito.when(connFactory.create(Mockito.eq("somehost"))).thenReturn(conn1);

    final LocalConnPool pool = new LocalConnPool(connFactory, 2, 2);

    final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
    final LocalPoolEntry entry1 = future1.get(1, TimeUnit.SECONDS);
    Assert.assertNotNull(entry1);

    Mockito.verify(connFactory, Mockito.times(1)).create(Mockito.eq("somehost"));

    entry1.updateExpiry(1, TimeUnit.MILLISECONDS);
    pool.release(entry1, true);

    Thread.sleep(200L);

    final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
    final LocalPoolEntry entry2 = future2.get(1, TimeUnit.SECONDS);
    Assert.assertNotNull(entry2);

    Mockito.verify(connFactory, Mockito.times(2)).create(Mockito.eq("somehost"));

    final PoolStats totals = pool.getTotalStats();
    Assert.assertEquals(0, totals.getAvailable());
    Assert.assertEquals(1, totals.getLeased());
    Assert.assertEquals(Collections.singleton("somehost"), pool.getRoutes());
    final PoolStats stats = pool.getStats("somehost");
    Assert.assertEquals(0, stats.getAvailable());
    Assert.assertEquals(1, stats.getLeased());
  }
  @Test
  public void testCloseExpired() throws Exception {
    final LocalConnFactory connFactory = Mockito.mock(LocalConnFactory.class);

    final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn1.isOpen()).thenReturn(Boolean.FALSE);
    final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn2.isOpen()).thenReturn(Boolean.TRUE);

    Mockito.when(connFactory.create(Mockito.eq("somehost"))).thenReturn(conn1, conn2);

    final LocalConnPool pool = new LocalConnPool(connFactory, 2, 2);

    final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
    final LocalPoolEntry entry1 = future1.get(1, TimeUnit.SECONDS);
    Assert.assertNotNull(entry1);
    final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
    final LocalPoolEntry entry2 = future2.get(1, TimeUnit.SECONDS);
    Assert.assertNotNull(entry2);

    entry1.updateExpiry(1, TimeUnit.MILLISECONDS);
    pool.release(entry1, true);

    Thread.sleep(200);

    entry2.updateExpiry(1000, TimeUnit.SECONDS);
    pool.release(entry2, true);

    pool.closeExpired();

    Mockito.verify(conn1).close();
    Mockito.verify(conn2, Mockito.never()).close();

    final PoolStats totals = pool.getTotalStats();
    Assert.assertEquals(1, totals.getAvailable());
    Assert.assertEquals(0, totals.getLeased());
    final PoolStats stats = pool.getStats("somehost");
    Assert.assertEquals(1, stats.getAvailable());
    Assert.assertEquals(0, stats.getLeased());
  }
 @Override
 protected boolean validate(final LocalPoolEntry entry) {
   return !entry.getConnection().isStale();
 }
  @Test
  public void testStatefulConnectionRedistributionOnPerRouteMaxLimit() throws Exception {
    final LocalConnFactory connFactory = Mockito.mock(LocalConnFactory.class);

    final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn1.isOpen()).thenReturn(true);
    final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn2.isOpen()).thenReturn(true);
    final HttpConnection conn3 = Mockito.mock(HttpConnection.class);
    Mockito.when(conn3.isOpen()).thenReturn(true);
    Mockito.when(connFactory.create(Mockito.eq("somehost"))).thenReturn(conn1, conn2, conn3);

    final LocalConnPool pool = new LocalConnPool(connFactory, 2, 10);
    pool.setMaxPerRoute("somehost", 2);
    pool.setMaxTotal(2);

    final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
    final GetPoolEntryThread t1 = new GetPoolEntryThread(future1);
    t1.start();

    t1.join(GRACE_PERIOD);
    Assert.assertTrue(future1.isDone());
    final LocalPoolEntry entry1 = t1.getEntry();
    Assert.assertNotNull(entry1);

    final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
    final GetPoolEntryThread t2 = new GetPoolEntryThread(future2);
    t2.start();

    t2.join(GRACE_PERIOD);
    Assert.assertTrue(future2.isDone());
    final LocalPoolEntry entry2 = t2.getEntry();
    Assert.assertNotNull(entry2);

    PoolStats totals = pool.getTotalStats();
    Assert.assertEquals(0, totals.getAvailable());
    Assert.assertEquals(2, totals.getLeased());
    Assert.assertEquals(0, totals.getPending());

    entry1.setState("some-stuff");
    pool.release(entry1, true);
    entry2.setState("some-stuff");
    pool.release(entry2, true);

    Mockito.verify(connFactory, Mockito.times(2)).create(Mockito.eq("somehost"));

    final Future<LocalPoolEntry> future3 = pool.lease("somehost", "some-other-stuff");
    final GetPoolEntryThread t3 = new GetPoolEntryThread(future3);
    t3.start();

    t3.join(GRACE_PERIOD);
    Assert.assertTrue(future3.isDone());
    final LocalPoolEntry entry3 = t3.getEntry();
    Assert.assertNotNull(entry3);

    Mockito.verify(connFactory, Mockito.times(3)).create(Mockito.eq("somehost"));

    Mockito.verify(conn1).close();
    Mockito.verify(conn2, Mockito.never()).close();

    totals = pool.getTotalStats();
    Assert.assertEquals(1, totals.getAvailable());
    Assert.assertEquals(1, totals.getLeased());
  }