001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.pool.impl; 019 020 import junit.framework.Test; 021 import junit.framework.TestSuite; 022 import org.apache.commons.pool.BasePoolableObjectFactory; 023 import org.apache.commons.pool.ObjectPool; 024 import org.apache.commons.pool.PoolableObjectFactory; 025 import org.apache.commons.pool.PoolUtils; 026 import org.apache.commons.pool.TestBaseObjectPool; 027 import org.apache.commons.pool.VisitTracker; 028 import org.apache.commons.pool.VisitTrackerFactory; 029 030 import java.util.NoSuchElementException; 031 import java.util.Random; 032 033 /** 034 * @author Rodney Waldhoff 035 * @author Dirk Verbeeck 036 * @author Sandy McArthur 037 * @version $Revision: 791860 $ $Date: 2009-07-07 11:10:30 -0400 (Tue, 07 Jul 2009) $ 038 */ 039 public class TestGenericObjectPool extends TestBaseObjectPool { 040 public TestGenericObjectPool(String testName) { 041 super(testName); 042 } 043 044 public static Test suite() { 045 return new TestSuite(TestGenericObjectPool.class); 046 } 047 048 protected ObjectPool makeEmptyPool(int mincap) { 049 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 050 pool.setMaxActive(mincap); 051 pool.setMaxIdle(mincap); 052 return pool; 053 } 054 055 protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) { 056 return new GenericObjectPool(factory); 057 } 058 059 protected Object getNthObject(int n) { 060 return String.valueOf(n); 061 } 062 063 public void setUp() throws Exception { 064 super.setUp(); 065 pool = new GenericObjectPool(new SimpleFactory()); 066 } 067 068 public void tearDown() throws Exception { 069 super.tearDown(); 070 pool.clear(); 071 pool.close(); 072 pool = null; 073 } 074 075 public void testWhenExhaustedGrow() throws Exception { 076 pool.setMaxActive(1); 077 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); 078 Object obj1 = pool.borrowObject(); 079 assertNotNull(obj1); 080 Object obj2 = pool.borrowObject(); 081 assertNotNull(obj2); 082 pool.returnObject(obj2); 083 pool.returnObject(obj1); 084 pool.close(); 085 } 086 087 public void testWhenExhaustedFail() throws Exception { 088 pool.setMaxActive(1); 089 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 090 Object obj1 = pool.borrowObject(); 091 assertNotNull(obj1); 092 try { 093 pool.borrowObject(); 094 fail("Expected NoSuchElementException"); 095 } catch(NoSuchElementException e) { 096 // expected 097 } 098 pool.returnObject(obj1); 099 assertEquals(1, pool.getNumIdle()); 100 pool.close(); 101 } 102 103 public void testWhenExhaustedBlock() throws Exception { 104 pool.setMaxActive(1); 105 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 106 pool.setMaxWait(10L); 107 Object obj1 = pool.borrowObject(); 108 assertNotNull(obj1); 109 try { 110 pool.borrowObject(); 111 fail("Expected NoSuchElementException"); 112 } catch(NoSuchElementException e) { 113 // expected 114 } 115 pool.returnObject(obj1); 116 pool.close(); 117 } 118 119 public void testEvictWhileEmpty() throws Exception { 120 pool.evict(); 121 pool.evict(); 122 pool.close(); 123 } 124 125 /** 126 * Tests addObject contention between ensureMinIdle triggered by 127 * the Evictor with minIdle > 0 and borrowObject. 128 */ 129 public void testEvictAddObjects() throws Exception { 130 SimpleFactory factory = new SimpleFactory(); 131 factory.setMakeLatency(300); 132 factory.setMaxActive(2); 133 GenericObjectPool pool = new GenericObjectPool(factory); 134 pool.setMaxActive(2); 135 pool.setMinIdle(1); 136 pool.borrowObject(); // numActive = 1, numIdle = 0 137 // Create a test thread that will run once and try a borrow after 138 // 150ms fixed delay 139 TestThread borrower = new TestThread(pool, 1, 150, false); 140 Thread borrowerThread = new Thread(borrower); 141 // Set evictor to run in 100 ms - will create idle instance 142 pool.setTimeBetweenEvictionRunsMillis(100); 143 borrowerThread.start(); // Off to the races 144 borrowerThread.join(); 145 assertTrue(!borrower.failed()); 146 pool.close(); 147 } 148 149 public void testEvictLIFO() throws Exception { 150 checkEvict(true); 151 } 152 153 public void testEvictFIFO() throws Exception { 154 checkEvict(false); 155 } 156 157 public void checkEvict(boolean lifo) throws Exception { 158 // yea this is hairy but it tests all the code paths in GOP.evict() 159 final SimpleFactory factory = new SimpleFactory(); 160 final GenericObjectPool pool = new GenericObjectPool(factory); 161 pool.setSoftMinEvictableIdleTimeMillis(10); 162 pool.setMinIdle(2); 163 pool.setTestWhileIdle(true); 164 pool.setLifo(lifo); 165 PoolUtils.prefill(pool, 5); 166 pool.evict(); 167 factory.setEvenValid(false); 168 factory.setOddValid(false); 169 factory.setThrowExceptionOnActivate(true); 170 pool.evict(); 171 PoolUtils.prefill(pool, 5); 172 factory.setThrowExceptionOnActivate(false); 173 factory.setThrowExceptionOnPassivate(true); 174 pool.evict(); 175 factory.setThrowExceptionOnPassivate(false); 176 factory.setEvenValid(true); 177 factory.setOddValid(true); 178 Thread.sleep(125); 179 pool.evict(); 180 assertEquals(2, pool.getNumIdle()); 181 } 182 183 /** 184 * Test to make sure evictor visits least recently used objects first, 185 * regardless of FIFO/LIFO 186 * 187 * JIRA: POOL-86 188 */ 189 public void testEvictionOrder() throws Exception { 190 checkEvictionOrder(false); 191 checkEvictionOrder(true); 192 } 193 194 private void checkEvictionOrder(boolean lifo) throws Exception { 195 SimpleFactory factory = new SimpleFactory(); 196 GenericObjectPool pool = new GenericObjectPool(factory); 197 pool.setNumTestsPerEvictionRun(2); 198 pool.setMinEvictableIdleTimeMillis(100); 199 pool.setLifo(lifo); 200 for (int i = 0; i < 5; i++) { 201 pool.addObject(); 202 Thread.sleep(100); 203 } 204 // Order, oldest to youngest, is "0", "1", ...,"4" 205 pool.evict(); // Should evict "0" and "1" 206 Object obj = pool.borrowObject(); 207 assertTrue("oldest not evicted", !obj.equals("0")); 208 assertTrue("second oldest not evicted", !obj.equals("1")); 209 // 2 should be next out for FIFO, 4 for LIFO 210 assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj); 211 212 // Two eviction runs in sequence 213 factory = new SimpleFactory(); 214 pool = new GenericObjectPool(factory); 215 pool.setNumTestsPerEvictionRun(2); 216 pool.setMinEvictableIdleTimeMillis(100); 217 pool.setLifo(lifo); 218 for (int i = 0; i < 5; i++) { 219 pool.addObject(); 220 Thread.sleep(100); 221 } 222 pool.evict(); // Should evict "0" and "1" 223 pool.evict(); // Should evict "2" and "3" 224 obj = pool.borrowObject(); 225 assertEquals("Wrong instance remaining in pool", "4", obj); 226 } 227 228 /** 229 * Verifies that the evictor visits objects in expected order 230 * and frequency. 231 */ 232 public void testEvictorVisiting() throws Exception { 233 checkEvictorVisiting(true); 234 checkEvictorVisiting(false); 235 } 236 237 private void checkEvictorVisiting(boolean lifo) throws Exception { 238 VisitTrackerFactory factory = new VisitTrackerFactory(); 239 GenericObjectPool pool = new GenericObjectPool(factory); 240 pool.setNumTestsPerEvictionRun(2); 241 pool.setMinEvictableIdleTimeMillis(-1); 242 pool.setTestWhileIdle(true); 243 pool.setLifo(lifo); 244 pool.setTestOnReturn(false); 245 pool.setTestOnBorrow(false); 246 for (int i = 0; i < 8; i++) { 247 pool.addObject(); 248 } 249 pool.evict(); // Visit oldest 2 - 0 and 1 250 Object obj = pool.borrowObject(); 251 pool.returnObject(obj); 252 obj = pool.borrowObject(); 253 pool.returnObject(obj); 254 // borrow, return, borrow, return 255 // FIFO will move 0 and 1 to end 256 // LIFO, 7 out, then in, then out, then in 257 pool.evict(); // Should visit 2 and 3 in either case 258 for (int i = 0; i < 8; i++) { 259 VisitTracker tracker = (VisitTracker) pool.borrowObject(); 260 if (tracker.getId() >= 4) { 261 assertEquals("Unexpected instance visited " + tracker.getId(), 262 0, tracker.getValidateCount()); 263 } else { 264 assertEquals("Instance " + tracker.getId() + 265 " visited wrong number of times.", 266 1, tracker.getValidateCount()); 267 } 268 } 269 270 factory = new VisitTrackerFactory(); 271 pool = new GenericObjectPool(factory); 272 pool.setNumTestsPerEvictionRun(3); 273 pool.setMinEvictableIdleTimeMillis(-1); 274 pool.setTestWhileIdle(true); 275 pool.setLifo(lifo); 276 pool.setTestOnReturn(false); 277 pool.setTestOnBorrow(false); 278 for (int i = 0; i < 8; i++) { 279 pool.addObject(); 280 } 281 pool.evict(); // 0, 1, 2 282 pool.evict(); // 3, 4, 5 283 obj = pool.borrowObject(); 284 pool.returnObject(obj); 285 obj = pool.borrowObject(); 286 pool.returnObject(obj); 287 obj = pool.borrowObject(); 288 pool.returnObject(obj); 289 // borrow, return, borrow, return 290 // FIFO 3,4,5,6,7,0,1,2 291 // LIFO 7,6,5,4,3,2,1,0 292 // In either case, pointer should be at 6 293 pool.evict(); 294 // Should hit 6,7,0 - 0 for second time 295 for (int i = 0; i < 8; i++) { 296 VisitTracker tracker = (VisitTracker) pool.borrowObject(); 297 if (tracker.getId() != 0) { 298 assertEquals("Instance " + tracker.getId() + 299 " visited wrong number of times.", 300 1, tracker.getValidateCount()); 301 } else { 302 assertEquals("Instance " + tracker.getId() + 303 " visited wrong number of times.", 304 2, tracker.getValidateCount()); 305 } 306 } 307 // Randomly generate a pools with random numTests 308 // and make sure evictor cycles through elements appropriately 309 int[] smallPrimes = {2, 3, 5, 7}; 310 Random random = new Random(); 311 random.setSeed(System.currentTimeMillis()); 312 for (int i = 0; i < 4; i++) { 313 pool.setNumTestsPerEvictionRun(smallPrimes[i]); 314 for (int j = 0; j < 5; j++) { 315 pool = new GenericObjectPool(factory); 316 pool.setNumTestsPerEvictionRun(3); 317 pool.setMinEvictableIdleTimeMillis(-1); 318 pool.setTestWhileIdle(true); 319 pool.setLifo(lifo); 320 pool.setTestOnReturn(false); 321 pool.setTestOnBorrow(false); 322 pool.setMaxIdle(-1); 323 int instanceCount = 10 + random.nextInt(20); 324 pool.setMaxActive(instanceCount); 325 for (int k = 0; k < instanceCount; k++) { 326 pool.addObject(); 327 } 328 329 // Execute a random number of evictor runs 330 int runs = 10 + random.nextInt(50); 331 for (int k = 0; k < runs; k++) { 332 pool.evict(); 333 } 334 335 // Number of times evictor should have cycled through the pool 336 int cycleCount = (runs * pool.getNumTestsPerEvictionRun()) 337 / instanceCount; 338 339 // Look at elements and make sure they are visited cycleCount 340 // or cycleCount + 1 times 341 VisitTracker tracker = null; 342 int visitCount = 0; 343 for (int k = 0; k < instanceCount; k++) { 344 tracker = (VisitTracker) pool.borrowObject(); 345 assertTrue(pool.getNumActive() <= pool.getMaxActive()); 346 visitCount = tracker.getValidateCount(); 347 assertTrue(visitCount >= cycleCount && 348 visitCount <= cycleCount + 1); 349 } 350 } 351 } 352 } 353 354 public void testExceptionOnPassivateDuringReturn() throws Exception { 355 SimpleFactory factory = new SimpleFactory(); 356 GenericObjectPool pool = new GenericObjectPool(factory); 357 Object obj = pool.borrowObject(); 358 factory.setThrowExceptionOnPassivate(true); 359 pool.returnObject(obj); 360 assertEquals(0,pool.getNumIdle()); 361 pool.close(); 362 } 363 364 public void testExceptionOnDestroyDuringBorrow() throws Exception { 365 SimpleFactory factory = new SimpleFactory(); 366 factory.setThrowExceptionOnDestroy(true); 367 GenericObjectPool pool = new GenericObjectPool(factory); 368 pool.setTestOnBorrow(true); 369 pool.borrowObject(); 370 factory.setValid(false); // Make validation fail on next borrow attempt 371 try { 372 pool.borrowObject(); 373 fail("Expecting NoSuchElementException"); 374 } catch (NoSuchElementException ex) { 375 // expected 376 } 377 assertEquals(1, pool.getNumActive()); 378 assertEquals(0, pool.getNumIdle()); 379 } 380 381 public void testExceptionOnDestroyDuringReturn() throws Exception { 382 SimpleFactory factory = new SimpleFactory(); 383 factory.setThrowExceptionOnDestroy(true); 384 GenericObjectPool pool = new GenericObjectPool(factory); 385 pool.setTestOnReturn(true); 386 Object obj1 = pool.borrowObject(); 387 pool.borrowObject(); 388 factory.setValid(false); // Make validation fail 389 pool.returnObject(obj1); 390 assertEquals(1, pool.getNumActive()); 391 assertEquals(0, pool.getNumIdle()); 392 } 393 394 public void testExceptionOnActivateDuringBorrow() throws Exception { 395 SimpleFactory factory = new SimpleFactory(); 396 GenericObjectPool pool = new GenericObjectPool(factory); 397 Object obj1 = pool.borrowObject(); 398 Object obj2 = pool.borrowObject(); 399 pool.returnObject(obj1); 400 pool.returnObject(obj2); 401 factory.setThrowExceptionOnActivate(true); 402 factory.setEvenValid(false); 403 // Activation will now throw every other time 404 // First attempt throws, but loop continues and second succeeds 405 Object obj = pool.borrowObject(); 406 assertEquals(1, pool.getNumActive()); 407 assertEquals(0, pool.getNumIdle()); 408 409 pool.returnObject(obj); 410 factory.setValid(false); 411 // Validation will now fail on activation when borrowObject returns 412 // an idle instance, and then when attempting to create a new instance 413 try { 414 obj1 = pool.borrowObject(); 415 fail("Expecting NoSuchElementException"); 416 } catch (NoSuchElementException ex) { 417 // expected 418 } 419 assertEquals(0, pool.getNumActive()); 420 assertEquals(0, pool.getNumIdle()); 421 } 422 423 public void testSetFactoryWithActiveObjects() throws Exception { 424 GenericObjectPool pool = new GenericObjectPool(); 425 pool.setMaxIdle(10); 426 pool.setFactory(new SimpleFactory()); 427 Object obj = pool.borrowObject(); 428 assertNotNull(obj); 429 try { 430 pool.setFactory(null); 431 fail("Expected IllegalStateException"); 432 } catch(IllegalStateException e) { 433 // expected 434 } 435 try { 436 pool.setFactory(new SimpleFactory()); 437 fail("Expected IllegalStateException"); 438 } catch(IllegalStateException e) { 439 // expected 440 } 441 } 442 443 public void testSetFactoryWithNoActiveObjects() throws Exception { 444 GenericObjectPool pool = new GenericObjectPool(); 445 pool.setMaxIdle(10); 446 pool.setFactory(new SimpleFactory()); 447 Object obj = pool.borrowObject(); 448 pool.returnObject(obj); 449 assertEquals(1,pool.getNumIdle()); 450 pool.setFactory(new SimpleFactory()); 451 assertEquals(0,pool.getNumIdle()); 452 } 453 454 public void testNegativeMaxActive() throws Exception { 455 pool.setMaxActive(-1); 456 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 457 Object obj = pool.borrowObject(); 458 assertEquals(getNthObject(0),obj); 459 pool.returnObject(obj); 460 } 461 462 public void testMaxIdle() throws Exception { 463 pool.setMaxActive(100); 464 pool.setMaxIdle(8); 465 Object[] active = new Object[100]; 466 for(int i=0;i<100;i++) { 467 active[i] = pool.borrowObject(); 468 } 469 assertEquals(100,pool.getNumActive()); 470 assertEquals(0,pool.getNumIdle()); 471 for(int i=0;i<100;i++) { 472 pool.returnObject(active[i]); 473 assertEquals(99 - i,pool.getNumActive()); 474 assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle()); 475 } 476 } 477 478 public void testMaxIdleZero() throws Exception { 479 pool.setMaxActive(100); 480 pool.setMaxIdle(0); 481 Object[] active = new Object[100]; 482 for(int i=0;i<100;i++) { 483 active[i] = pool.borrowObject(); 484 } 485 assertEquals(100,pool.getNumActive()); 486 assertEquals(0,pool.getNumIdle()); 487 for(int i=0;i<100;i++) { 488 pool.returnObject(active[i]); 489 assertEquals(99 - i,pool.getNumActive()); 490 assertEquals(0, pool.getNumIdle()); 491 } 492 } 493 494 public void testMaxActive() throws Exception { 495 pool.setMaxActive(3); 496 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 497 498 pool.borrowObject(); 499 pool.borrowObject(); 500 pool.borrowObject(); 501 try { 502 pool.borrowObject(); 503 fail("Expected NoSuchElementException"); 504 } catch(NoSuchElementException e) { 505 // expected 506 } 507 } 508 509 public void testTimeoutNoLeak() throws Exception { 510 pool.setMaxActive(2); 511 pool.setMaxWait(10); 512 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 513 Object obj = pool.borrowObject(); 514 Object obj2 = pool.borrowObject(); 515 try { 516 pool.borrowObject(); 517 fail("Expecting NoSuchElementException"); 518 } catch (NoSuchElementException ex) { 519 //xpected 520 } 521 pool.returnObject(obj2); 522 pool.returnObject(obj); 523 524 obj = pool.borrowObject(); 525 obj2 = pool.borrowObject(); 526 } 527 528 public void testMaxActiveZero() throws Exception { 529 pool.setMaxActive(0); 530 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 531 532 try { 533 pool.borrowObject(); 534 fail("Expected NoSuchElementException"); 535 } catch(NoSuchElementException e) { 536 // expected 537 } 538 } 539 540 public void testMaxActiveUnderLoad() { 541 // Config 542 int numThreads = 199; // And main thread makes a round 200. 543 int numIter = 20; 544 int delay = 25; 545 int maxActive = 10; 546 547 SimpleFactory factory = new SimpleFactory(); 548 factory.setMaxActive(maxActive); 549 pool.setFactory(factory); 550 pool.setMaxActive(maxActive); 551 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 552 pool.setTimeBetweenEvictionRunsMillis(-1); 553 554 // Start threads to borrow objects 555 TestThread[] threads = new TestThread[numThreads]; 556 for(int i=0;i<numThreads;i++) { 557 // Factor of 2 on iterations so main thread does work whilst other 558 // threads are running. Factor of 2 on delay so average delay for 559 // other threads == actual delay for main thread 560 threads[i] = new TestThread(pool, numIter * 2, delay * 2); 561 Thread t = new Thread(threads[i]); 562 t.start(); 563 } 564 // Give the threads a chance to start doing some work 565 try { 566 Thread.sleep(5000); 567 } catch(InterruptedException e) { 568 // ignored 569 } 570 571 for (int i = 0; i < numIter; i++) { 572 Object obj = null; 573 try { 574 try { 575 Thread.sleep(delay); 576 } catch(InterruptedException e) { 577 // ignored 578 } 579 obj = pool.borrowObject(); 580 // Under load, observed _numActive > _maxActive 581 if (pool.getNumActive() > pool.getMaxActive()) { 582 throw new IllegalStateException("Too many active objects"); 583 } 584 try { 585 Thread.sleep(delay); 586 } catch(InterruptedException e) { 587 // ignored 588 } 589 } catch (Exception e) { 590 // Shouldn't happen 591 e.printStackTrace(); 592 fail("Exception on borrow"); 593 } finally { 594 if (obj != null) { 595 try { 596 pool.returnObject(obj); 597 } catch (Exception e) { 598 // Ignore 599 } 600 } 601 } 602 } 603 604 for(int i=0;i<numThreads;i++) { 605 while(!(threads[i]).complete()) { 606 try { 607 Thread.sleep(500L); 608 } catch(InterruptedException e) { 609 // ignored 610 } 611 } 612 if(threads[i].failed()) { 613 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 614 } 615 } 616 } 617 618 public void testInvalidWhenExhaustedAction() throws Exception { 619 try { 620 pool.setWhenExhaustedAction(Byte.MAX_VALUE); 621 fail("Expected IllegalArgumentException"); 622 } catch(IllegalArgumentException e) { 623 // expected 624 } 625 626 try { 627 ObjectPool pool = new GenericObjectPool( 628 new SimpleFactory(), 629 GenericObjectPool.DEFAULT_MAX_ACTIVE, 630 Byte.MAX_VALUE, 631 GenericObjectPool.DEFAULT_MAX_WAIT, 632 GenericObjectPool.DEFAULT_MAX_IDLE, 633 false, 634 false, 635 GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, 636 GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, 637 GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, 638 false 639 ); 640 assertNotNull(pool); 641 fail("Expected IllegalArgumentException"); 642 } catch(IllegalArgumentException e) { 643 // expected 644 } 645 } 646 647 public void testSettersAndGetters() throws Exception { 648 GenericObjectPool pool = new GenericObjectPool(); 649 { 650 pool.setFactory(new SimpleFactory()); 651 } 652 { 653 pool.setMaxActive(123); 654 assertEquals(123,pool.getMaxActive()); 655 } 656 { 657 pool.setMaxIdle(12); 658 assertEquals(12,pool.getMaxIdle()); 659 } 660 { 661 pool.setMaxWait(1234L); 662 assertEquals(1234L,pool.getMaxWait()); 663 } 664 { 665 pool.setMinEvictableIdleTimeMillis(12345L); 666 assertEquals(12345L,pool.getMinEvictableIdleTimeMillis()); 667 } 668 { 669 pool.setNumTestsPerEvictionRun(11); 670 assertEquals(11,pool.getNumTestsPerEvictionRun()); 671 } 672 { 673 pool.setTestOnBorrow(true); 674 assertTrue(pool.getTestOnBorrow()); 675 pool.setTestOnBorrow(false); 676 assertTrue(!pool.getTestOnBorrow()); 677 } 678 { 679 pool.setTestOnReturn(true); 680 assertTrue(pool.getTestOnReturn()); 681 pool.setTestOnReturn(false); 682 assertTrue(!pool.getTestOnReturn()); 683 } 684 { 685 pool.setTestWhileIdle(true); 686 assertTrue(pool.getTestWhileIdle()); 687 pool.setTestWhileIdle(false); 688 assertTrue(!pool.getTestWhileIdle()); 689 } 690 { 691 pool.setTimeBetweenEvictionRunsMillis(11235L); 692 assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis()); 693 } 694 { 695 pool.setSoftMinEvictableIdleTimeMillis(12135L); 696 assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis()); 697 } 698 { 699 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 700 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK,pool.getWhenExhaustedAction()); 701 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL); 702 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL,pool.getWhenExhaustedAction()); 703 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW); 704 assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW,pool.getWhenExhaustedAction()); 705 } 706 } 707 708 public void testDefaultConfiguration() throws Exception { 709 GenericObjectPool pool = new GenericObjectPool(); 710 assertConfiguration(new GenericObjectPool.Config(),pool); 711 } 712 713 public void testConstructors() throws Exception { 714 { 715 GenericObjectPool pool = new GenericObjectPool(); 716 assertConfiguration(new GenericObjectPool.Config(),pool); 717 } 718 { 719 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 720 assertConfiguration(new GenericObjectPool.Config(),pool); 721 } 722 { 723 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 724 expected.maxActive = 2; 725 expected.maxIdle = 3; 726 expected.maxWait = 5L; 727 expected.minEvictableIdleTimeMillis = 7L; 728 expected.numTestsPerEvictionRun = 9; 729 expected.testOnBorrow = true; 730 expected.testOnReturn = true; 731 expected.testWhileIdle = true; 732 expected.timeBetweenEvictionRunsMillis = 11L; 733 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 734 GenericObjectPool pool = new GenericObjectPool(null,expected); 735 assertConfiguration(expected,pool); 736 } 737 { 738 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 739 expected.maxActive = 2; 740 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive); 741 assertConfiguration(expected,pool); 742 } 743 { 744 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 745 expected.maxActive = 2; 746 expected.maxWait = 5L; 747 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 748 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait); 749 assertConfiguration(expected,pool); 750 } 751 { 752 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 753 expected.maxActive = 2; 754 expected.maxWait = 5L; 755 expected.testOnBorrow = true; 756 expected.testOnReturn = true; 757 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 758 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.testOnBorrow,expected.testOnReturn); 759 assertConfiguration(expected,pool); 760 } 761 { 762 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 763 expected.maxActive = 2; 764 expected.maxIdle = 3; 765 expected.maxWait = 5L; 766 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 767 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.maxIdle); 768 assertConfiguration(expected,pool); 769 } 770 { 771 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 772 expected.maxActive = 2; 773 expected.maxIdle = 3; 774 expected.maxWait = 5L; 775 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 776 expected.testOnBorrow = true; 777 expected.testOnReturn = true; 778 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive,expected.whenExhaustedAction,expected.maxWait,expected.maxIdle,expected.testOnBorrow,expected.testOnReturn); 779 assertConfiguration(expected,pool); 780 } 781 { 782 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 783 expected.maxActive = 2; 784 expected.maxIdle = 3; 785 expected.maxWait = 5L; 786 expected.minEvictableIdleTimeMillis = 7L; 787 expected.numTestsPerEvictionRun = 9; 788 expected.testOnBorrow = true; 789 expected.testOnReturn = true; 790 expected.testWhileIdle = true; 791 expected.timeBetweenEvictionRunsMillis = 11L; 792 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 793 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle, expected.testOnBorrow, expected.testOnReturn, expected.timeBetweenEvictionRunsMillis, expected.numTestsPerEvictionRun, expected.minEvictableIdleTimeMillis, expected.testWhileIdle); 794 assertConfiguration(expected,pool); 795 } 796 { 797 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 798 expected.maxActive = 2; 799 expected.maxIdle = 3; 800 expected.minIdle = 1; 801 expected.maxWait = 5L; 802 expected.minEvictableIdleTimeMillis = 7L; 803 expected.numTestsPerEvictionRun = 9; 804 expected.testOnBorrow = true; 805 expected.testOnReturn = true; 806 expected.testWhileIdle = true; 807 expected.timeBetweenEvictionRunsMillis = 11L; 808 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 809 GenericObjectPool pool = new GenericObjectPool(null,expected.maxActive, expected.whenExhaustedAction, expected.maxWait, expected.maxIdle, expected.minIdle, expected.testOnBorrow, expected.testOnReturn, expected.timeBetweenEvictionRunsMillis, expected.numTestsPerEvictionRun, expected.minEvictableIdleTimeMillis, expected.testWhileIdle); 810 assertConfiguration(expected,pool); 811 } 812 } 813 814 public void testSetConfig() throws Exception { 815 GenericObjectPool.Config expected = new GenericObjectPool.Config(); 816 GenericObjectPool pool = new GenericObjectPool(); 817 assertConfiguration(expected,pool); 818 expected.maxActive = 2; 819 expected.maxIdle = 3; 820 expected.maxWait = 5L; 821 expected.minEvictableIdleTimeMillis = 7L; 822 expected.numTestsPerEvictionRun = 9; 823 expected.testOnBorrow = true; 824 expected.testOnReturn = true; 825 expected.testWhileIdle = true; 826 expected.timeBetweenEvictionRunsMillis = 11L; 827 expected.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW; 828 pool.setConfig(expected); 829 assertConfiguration(expected,pool); 830 } 831 832 public void testDebugInfo() throws Exception { 833 GenericObjectPool pool = new GenericObjectPool(new SimpleFactory()); 834 pool.setMaxIdle(3); 835 assertNotNull(pool.debugInfo()); 836 Object obj = pool.borrowObject(); 837 assertNotNull(pool.debugInfo()); 838 pool.returnObject(obj); 839 assertNotNull(pool.debugInfo()); 840 } 841 842 public void testStartAndStopEvictor() throws Exception { 843 // set up pool without evictor 844 pool.setMaxIdle(6); 845 pool.setMaxActive(6); 846 pool.setNumTestsPerEvictionRun(6); 847 pool.setMinEvictableIdleTimeMillis(100L); 848 849 for(int j=0;j<2;j++) { 850 // populate the pool 851 { 852 Object[] active = new Object[6]; 853 for(int i=0;i<6;i++) { 854 active[i] = pool.borrowObject(); 855 } 856 for(int i=0;i<6;i++) { 857 pool.returnObject(active[i]); 858 } 859 } 860 861 // note that it stays populated 862 assertEquals("Should have 6 idle",6,pool.getNumIdle()); 863 864 // start the evictor 865 pool.setTimeBetweenEvictionRunsMillis(50L); 866 867 // wait a second (well, .2 seconds) 868 try { Thread.sleep(200L); } catch(InterruptedException e) { } 869 870 // assert that the evictor has cleared out the pool 871 assertEquals("Should have 0 idle",0,pool.getNumIdle()); 872 873 // stop the evictor 874 pool.startEvictor(0L); 875 } 876 } 877 878 public void testEvictionWithNegativeNumTests() throws Exception { 879 // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test 880 pool.setMaxIdle(6); 881 pool.setMaxActive(6); 882 pool.setNumTestsPerEvictionRun(-2); 883 pool.setMinEvictableIdleTimeMillis(50L); 884 pool.setTimeBetweenEvictionRunsMillis(100L); 885 886 Object[] active = new Object[6]; 887 for(int i=0;i<6;i++) { 888 active[i] = pool.borrowObject(); 889 } 890 for(int i=0;i<6;i++) { 891 pool.returnObject(active[i]); 892 } 893 894 try { Thread.sleep(100L); } catch(InterruptedException e) { } 895 assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6); 896 try { Thread.sleep(100L); } catch(InterruptedException e) { } 897 assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3); 898 try { Thread.sleep(100L); } catch(InterruptedException e) { } 899 assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2); 900 try { Thread.sleep(100L); } catch(InterruptedException e) { } 901 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 902 } 903 904 public void testEviction() throws Exception { 905 pool.setMaxIdle(500); 906 pool.setMaxActive(500); 907 pool.setNumTestsPerEvictionRun(100); 908 pool.setMinEvictableIdleTimeMillis(250L); 909 pool.setTimeBetweenEvictionRunsMillis(500L); 910 pool.setTestWhileIdle(true); 911 912 Object[] active = new Object[500]; 913 for(int i=0;i<500;i++) { 914 active[i] = pool.borrowObject(); 915 } 916 for(int i=0;i<500;i++) { 917 pool.returnObject(active[i]); 918 } 919 920 try { Thread.sleep(1000L); } catch(InterruptedException e) { } 921 assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500); 922 try { Thread.sleep(600L); } catch(InterruptedException e) { } 923 assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400); 924 try { Thread.sleep(600L); } catch(InterruptedException e) { } 925 assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300); 926 try { Thread.sleep(600L); } catch(InterruptedException e) { } 927 assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200); 928 try { Thread.sleep(600L); } catch(InterruptedException e) { } 929 assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100); 930 try { Thread.sleep(600L); } catch(InterruptedException e) { } 931 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 932 933 for(int i=0;i<500;i++) { 934 active[i] = pool.borrowObject(); 935 } 936 for(int i=0;i<500;i++) { 937 pool.returnObject(active[i]); 938 } 939 940 try { Thread.sleep(1000L); } catch(InterruptedException e) { } 941 assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500); 942 try { Thread.sleep(600L); } catch(InterruptedException e) { } 943 assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400); 944 try { Thread.sleep(600L); } catch(InterruptedException e) { } 945 assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300); 946 try { Thread.sleep(600L); } catch(InterruptedException e) { } 947 assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200); 948 try { Thread.sleep(600L); } catch(InterruptedException e) { } 949 assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100); 950 try { Thread.sleep(600L); } catch(InterruptedException e) { } 951 assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle()); 952 } 953 954 public void testEvictionSoftMinIdle() throws Exception { 955 GenericObjectPool pool = null; 956 957 class TimeTest extends BasePoolableObjectFactory { 958 private final long createTime; 959 public TimeTest() { 960 createTime = System.currentTimeMillis(); 961 } 962 public Object makeObject() throws Exception { 963 return new TimeTest(); 964 } 965 public long getCreateTime() { 966 return createTime; 967 } 968 } 969 970 pool = new GenericObjectPool(new TimeTest()); 971 972 pool.setMaxIdle(5); 973 pool.setMaxActive(5); 974 pool.setNumTestsPerEvictionRun(5); 975 pool.setMinEvictableIdleTimeMillis(3000L); 976 pool.setSoftMinEvictableIdleTimeMillis(1000L); 977 pool.setMinIdle(2); 978 979 Object[] active = new Object[5]; 980 Long[] creationTime = new Long[5] ; 981 for(int i=0;i<5;i++) { 982 active[i] = pool.borrowObject(); 983 creationTime[i] = new Long(((TimeTest)active[i]).getCreateTime()); 984 } 985 986 for(int i=0;i<5;i++) { 987 pool.returnObject(active[i]); 988 } 989 990 // Soft evict all but minIdle(2) 991 Thread.sleep(1500L); 992 pool.evict(); 993 assertEquals("Idle count different than expected.", 2, pool.getNumIdle()); 994 995 // Hard evict the rest. 996 Thread.sleep(2000L); 997 pool.evict(); 998 assertEquals("Idle count different than expected.", 0, pool.getNumIdle()); 999 } 1000 1001 public void testMinIdle() throws Exception { 1002 pool.setMaxIdle(500); 1003 pool.setMinIdle(5); 1004 pool.setMaxActive(10); 1005 pool.setNumTestsPerEvictionRun(0); 1006 pool.setMinEvictableIdleTimeMillis(50L); 1007 pool.setTimeBetweenEvictionRunsMillis(100L); 1008 pool.setTestWhileIdle(true); 1009 1010 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1011 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1012 1013 Object[] active = new Object[5]; 1014 active[0] = pool.borrowObject(); 1015 1016 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1017 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1018 1019 for(int i=1 ; i<5 ; i++) { 1020 active[i] = pool.borrowObject(); 1021 } 1022 1023 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1024 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1025 1026 for(int i=0 ; i<5 ; i++) { 1027 pool.returnObject(active[i]); 1028 } 1029 1030 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1031 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1032 } 1033 1034 public void testMinIdleMaxActive() throws Exception { 1035 pool.setMaxIdle(500); 1036 pool.setMinIdle(5); 1037 pool.setMaxActive(10); 1038 pool.setNumTestsPerEvictionRun(0); 1039 pool.setMinEvictableIdleTimeMillis(50L); 1040 pool.setTimeBetweenEvictionRunsMillis(100L); 1041 pool.setTestWhileIdle(true); 1042 1043 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1044 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1045 1046 Object[] active = new Object[10]; 1047 1048 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1049 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1050 1051 for(int i=0 ; i<5 ; i++) { 1052 active[i] = pool.borrowObject(); 1053 } 1054 1055 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1056 assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5); 1057 1058 for(int i=0 ; i<5 ; i++) { 1059 pool.returnObject(active[i]); 1060 } 1061 1062 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1063 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1064 1065 for(int i=0 ; i<10 ; i++) { 1066 active[i] = pool.borrowObject(); 1067 } 1068 1069 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1070 assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0); 1071 1072 for(int i=0 ; i<10 ; i++) { 1073 pool.returnObject(active[i]); 1074 } 1075 1076 try { Thread.sleep(150L); } catch(InterruptedException e) { } 1077 assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10); 1078 } 1079 1080 /** 1081 * Kicks off <numThreads> test threads, each of which will go through 1082 * <iterations> borrow-return cycles with random delay times <= delay 1083 * in between. 1084 */ 1085 public void runTestThreads(int numThreads, int iterations, int delay) { 1086 TestThread[] threads = new TestThread[numThreads]; 1087 for(int i=0;i<numThreads;i++) { 1088 threads[i] = new TestThread(pool,iterations,delay); 1089 Thread t = new Thread(threads[i]); 1090 t.start(); 1091 } 1092 for(int i=0;i<numThreads;i++) { 1093 while(!(threads[i]).complete()) { 1094 try { 1095 Thread.sleep(500L); 1096 } catch(InterruptedException e) { 1097 // ignored 1098 } 1099 } 1100 if(threads[i].failed()) { 1101 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 1102 } 1103 } 1104 } 1105 1106 public void testThreaded1() throws Exception { 1107 pool.setMaxActive(15); 1108 pool.setMaxIdle(15); 1109 pool.setMaxWait(1000L); 1110 runTestThreads(20, 100, 50); 1111 } 1112 1113 /** 1114 * Verifies that maxActive is not exceeded when factory destroyObject 1115 * has high latency, testOnReturn is set and there is high incidence of 1116 * validation failures. 1117 */ 1118 public void testMaxActiveInvariant() throws Exception { 1119 int maxActive = 15; 1120 SimpleFactory factory = new SimpleFactory(); 1121 factory.setEvenValid(false); // Every other validation fails 1122 factory.setDestroyLatency(100); // Destroy takes 100 ms 1123 factory.setMaxActive(maxActive); // (makes - destroys) bound 1124 factory.setValidationEnabled(true); 1125 pool = new GenericObjectPool(factory); 1126 pool.setMaxActive(maxActive); 1127 pool.setMaxIdle(-1); 1128 pool.setTestOnReturn(true); 1129 pool.setMaxWait(1000L); 1130 runTestThreads(5, 10, 50); 1131 } 1132 1133 static class TestThread implements Runnable { 1134 private final java.util.Random _random = new java.util.Random(); 1135 1136 // Thread config items 1137 private final ObjectPool _pool; 1138 private final int _iter; 1139 private final int _delay; 1140 private final boolean _randomDelay; 1141 private final Object _expectedObject; 1142 1143 private volatile boolean _complete = false; 1144 private volatile boolean _failed = false; 1145 private volatile Throwable _error; 1146 1147 public TestThread(ObjectPool pool) { 1148 this(pool, 100, 50, true, null); 1149 } 1150 1151 public TestThread(ObjectPool pool, int iter) { 1152 this(pool, iter, 50, true, null); 1153 } 1154 1155 public TestThread(ObjectPool pool, int iter, int delay) { 1156 this(pool, iter, delay, true, null); 1157 } 1158 1159 public TestThread(ObjectPool pool, int iter, int delay, 1160 boolean randomDelay) { 1161 this(pool, iter, delay, randomDelay, null); 1162 } 1163 1164 public TestThread(ObjectPool pool, int iter, int delay, 1165 boolean randomDelay, Object obj) { 1166 _pool = pool; 1167 _iter = iter; 1168 _delay = delay; 1169 _randomDelay = randomDelay; 1170 _expectedObject = obj; 1171 } 1172 1173 public boolean complete() { 1174 return _complete; 1175 } 1176 1177 public boolean failed() { 1178 return _failed; 1179 } 1180 1181 public void run() { 1182 for(int i=0;i<_iter;i++) { 1183 long delay = 1184 _randomDelay ? (long)_random.nextInt(_delay) : _delay; 1185 try { 1186 Thread.sleep(delay); 1187 } catch(InterruptedException e) { 1188 // ignored 1189 } 1190 Object obj = null; 1191 try { 1192 obj = _pool.borrowObject(); 1193 } catch(Exception e) { 1194 _error = e; 1195 _failed = true; 1196 _complete = true; 1197 break; 1198 } 1199 1200 if (_expectedObject != null && !_expectedObject.equals(obj)) { 1201 _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj); 1202 _failed = true; 1203 _complete = true; 1204 break; 1205 } 1206 1207 try { 1208 Thread.sleep(delay); 1209 } catch(InterruptedException e) { 1210 // ignored 1211 } 1212 try { 1213 _pool.returnObject(obj); 1214 } catch(Exception e) { 1215 _error = e; 1216 _failed = true; 1217 _complete = true; 1218 break; 1219 } 1220 } 1221 _complete = true; 1222 } 1223 } 1224 1225 public void testFIFO() throws Exception { 1226 pool.setLifo(false); 1227 pool.addObject(); // "0" 1228 pool.addObject(); // "1" 1229 pool.addObject(); // "2" 1230 assertEquals("Oldest", "0", pool.borrowObject()); 1231 assertEquals("Middle", "1", pool.borrowObject()); 1232 assertEquals("Youngest", "2", pool.borrowObject()); 1233 assertEquals("new-3", "3", pool.borrowObject()); 1234 pool.returnObject("r"); 1235 assertEquals("returned", "r", pool.borrowObject()); 1236 assertEquals("new-4", "4", pool.borrowObject()); 1237 } 1238 1239 public void testLIFO() throws Exception { 1240 pool.setLifo(true); 1241 pool.addObject(); // "0" 1242 pool.addObject(); // "1" 1243 pool.addObject(); // "2" 1244 assertEquals("Youngest", "2", pool.borrowObject()); 1245 assertEquals("Middle", "1", pool.borrowObject()); 1246 assertEquals("Oldest", "0", pool.borrowObject()); 1247 assertEquals("new-3", "3", pool.borrowObject()); 1248 pool.returnObject("r"); 1249 assertEquals("returned", "r", pool.borrowObject()); 1250 assertEquals("new-4", "4", pool.borrowObject()); 1251 } 1252 1253 public void testAddObject() throws Exception { 1254 assertEquals("should be zero idle", 0, pool.getNumIdle()); 1255 pool.addObject(); 1256 assertEquals("should be one idle", 1, pool.getNumIdle()); 1257 assertEquals("should be zero active", 0, pool.getNumActive()); 1258 Object obj = pool.borrowObject(); 1259 assertEquals("should be zero idle", 0, pool.getNumIdle()); 1260 assertEquals("should be one active", 1, pool.getNumActive()); 1261 pool.returnObject(obj); 1262 assertEquals("should be one idle", 1, pool.getNumIdle()); 1263 assertEquals("should be zero active", 0, pool.getNumActive()); 1264 1265 ObjectPool op = new GenericObjectPool(); 1266 try { 1267 op.addObject(); 1268 fail("Expected IllegalStateException when there is no factory."); 1269 } catch (IllegalStateException ise) { 1270 //expected 1271 } 1272 op.close(); 1273 } 1274 1275 protected GenericObjectPool pool = null; 1276 1277 private void assertConfiguration(GenericObjectPool.Config expected, GenericObjectPool actual) throws Exception { 1278 assertEquals("testOnBorrow",expected.testOnBorrow,actual.getTestOnBorrow()); 1279 assertEquals("testOnReturn",expected.testOnReturn,actual.getTestOnReturn()); 1280 assertEquals("testWhileIdle",expected.testWhileIdle,actual.getTestWhileIdle()); 1281 assertEquals("whenExhaustedAction",expected.whenExhaustedAction,actual.getWhenExhaustedAction()); 1282 assertEquals("maxActive",expected.maxActive,actual.getMaxActive()); 1283 assertEquals("maxIdle",expected.maxIdle,actual.getMaxIdle()); 1284 assertEquals("maxWait",expected.maxWait,actual.getMaxWait()); 1285 assertEquals("minEvictableIdleTimeMillis",expected.minEvictableIdleTimeMillis,actual.getMinEvictableIdleTimeMillis()); 1286 assertEquals("numTestsPerEvictionRun",expected.numTestsPerEvictionRun,actual.getNumTestsPerEvictionRun()); 1287 assertEquals("timeBetweenEvictionRunsMillis",expected.timeBetweenEvictionRunsMillis,actual.getTimeBetweenEvictionRunsMillis()); 1288 } 1289 1290 public class SimpleFactory implements PoolableObjectFactory { 1291 public SimpleFactory() { 1292 this(true); 1293 } 1294 public SimpleFactory(boolean valid) { 1295 this(valid,valid); 1296 } 1297 public SimpleFactory(boolean evalid, boolean ovalid) { 1298 evenValid = evalid; 1299 oddValid = ovalid; 1300 } 1301 void setValid(boolean valid) { 1302 setEvenValid(valid); 1303 setOddValid(valid); 1304 } 1305 void setEvenValid(boolean valid) { 1306 evenValid = valid; 1307 } 1308 void setOddValid(boolean valid) { 1309 oddValid = valid; 1310 } 1311 public void setThrowExceptionOnPassivate(boolean bool) { 1312 exceptionOnPassivate = bool; 1313 } 1314 public void setMaxActive(int maxActive) { 1315 this.maxActive = maxActive; 1316 } 1317 public void setDestroyLatency(long destroyLatency) { 1318 this.destroyLatency = destroyLatency; 1319 } 1320 public void setMakeLatency(long makeLatency) { 1321 this.makeLatency = makeLatency; 1322 } 1323 public Object makeObject() { 1324 synchronized(this) { 1325 activeCount++; 1326 if (activeCount > maxActive) { 1327 throw new IllegalStateException( 1328 "Too many active instances: " + activeCount); 1329 } 1330 } 1331 if (makeLatency > 0) { 1332 doWait(makeLatency); 1333 } 1334 return String.valueOf(makeCounter++); 1335 } 1336 public void destroyObject(Object obj) throws Exception { 1337 if (destroyLatency > 0) { 1338 doWait(destroyLatency); 1339 } 1340 synchronized(this) { 1341 activeCount--; 1342 } 1343 if (exceptionOnDestroy) { 1344 throw new Exception(); 1345 } 1346 } 1347 public boolean validateObject(Object obj) { 1348 if (enableValidation) { 1349 return validateCounter++%2 == 0 ? evenValid : oddValid; 1350 } 1351 else { 1352 return true; 1353 } 1354 } 1355 public void activateObject(Object obj) throws Exception { 1356 if (exceptionOnActivate) { 1357 if (!(validateCounter++%2 == 0 ? evenValid : oddValid)) { 1358 throw new Exception(); 1359 } 1360 } 1361 } 1362 public void passivateObject(Object obj) throws Exception { 1363 if(exceptionOnPassivate) { 1364 throw new Exception(); 1365 } 1366 } 1367 int makeCounter = 0; 1368 int validateCounter = 0; 1369 int activeCount = 0; 1370 boolean evenValid = true; 1371 boolean oddValid = true; 1372 boolean exceptionOnPassivate = false; 1373 boolean exceptionOnActivate = false; 1374 boolean exceptionOnDestroy = false; 1375 boolean enableValidation = true; 1376 long destroyLatency = 0; 1377 long makeLatency = 0; 1378 int maxActive = Integer.MAX_VALUE; 1379 1380 public boolean isThrowExceptionOnActivate() { 1381 return exceptionOnActivate; 1382 } 1383 1384 public void setThrowExceptionOnActivate(boolean b) { 1385 exceptionOnActivate = b; 1386 } 1387 1388 public void setThrowExceptionOnDestroy(boolean b) { 1389 exceptionOnDestroy = b; 1390 } 1391 1392 public boolean isValidationEnabled() { 1393 return enableValidation; 1394 } 1395 1396 public void setValidationEnabled(boolean b) { 1397 enableValidation = b; 1398 } 1399 1400 private void doWait(long latency) { 1401 try { 1402 Thread.sleep(latency); 1403 } catch (InterruptedException ex) { 1404 // ignore 1405 } 1406 } 1407 } 1408 protected boolean isLifo() { 1409 return true; 1410 } 1411 1412 protected boolean isFifo() { 1413 return false; 1414 } 1415 1416 /* 1417 * Note: This test relies on timing for correct execution. There *should* be 1418 * enough margin for this to work correctly on most (all?) systems but be 1419 * aware of this if you see a failure of this test. 1420 */ 1421 public void testBorrowObjectFairness() { 1422 // Config 1423 int numThreads = 30; 1424 int maxActive = 10; 1425 1426 SimpleFactory factory = new SimpleFactory(); 1427 factory.setMaxActive(maxActive); 1428 pool.setFactory(factory); 1429 pool.setMaxActive(maxActive); 1430 pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK); 1431 pool.setTimeBetweenEvictionRunsMillis(-1); 1432 1433 // Start threads to borrow objects 1434 TestThread[] threads = new TestThread[numThreads]; 1435 for(int i=0;i<numThreads;i++) { 1436 threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxActive)); 1437 Thread t = new Thread(threads[i]); 1438 t.start(); 1439 // Short delay to ensure threads start in correct order 1440 try { 1441 Thread.sleep(50); 1442 } catch (InterruptedException e) { 1443 fail(e.toString()); 1444 } 1445 } 1446 1447 // Wait for threads to finish 1448 for(int i=0;i<numThreads;i++) { 1449 while(!(threads[i]).complete()) { 1450 try { 1451 Thread.sleep(500L); 1452 } catch(InterruptedException e) { 1453 // ignored 1454 } 1455 } 1456 if(threads[i].failed()) { 1457 fail("Thread "+i+" failed: "+threads[i]._error.toString()); 1458 } 1459 } 1460 } 1461 }