Added: jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/TestCompositeObjectPool.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/TestCompositeObjectPool.java?rev=387630&view=auto ============================================================================== --- jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/TestCompositeObjectPool.java (added) +++ jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/TestCompositeObjectPool.java Tue Mar 21 13:41:53 2006 @@ -0,0 +1,621 @@ +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.mcarthur.sandy.commons.pool.composite; + +import junit.framework.TestCase; +import org.apache.commons.pool.BasePoolableObjectFactory; +import org.apache.commons.pool.PoolableObjectFactory; + +import java.util.NoSuchElementException; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedList; + +/** + * Test [EMAIL PROTECTED] CompositeObjectPool} and it's components. + * + * @author Sandy McArthur + * @since #.# + * @version $Revision$ $Date$ + */ +public class TestCompositeObjectPool extends TestCase { + private CompositeObjectPool pool = null; + + protected void setUp() throws Exception { + } + + protected void tearDown() throws Exception { + if (pool != null) { + pool.close(); + pool = null; + } + } + + // Test Managers -------------------------------------- + + /** + * Make sure [EMAIL PROTECTED] FailManager} throws an exception. + */ + public void testFailManager() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new FailManager(), new FifoLender(), new DebugTracker(), false); + try { + pool.borrowObject(); + fail("Should have thrown a NoSuchElementException"); + } catch (NoSuchElementException nsee) { + // correct + } + } + + /** + * Make sure [EMAIL PROTECTED] GrowManager} makes a new object. + */ + public void testGrowManager() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new FifoLender(), new DebugTracker(), false); + Object obj = null; + obj = pool.borrowObject(); + assertEquals(new Integer(0), obj); + } + + /** + * Make sure [EMAIL PROTECTED] IdleLimitManager} prevents the idle pool from getting too large. + */ + public void testIdleLimitManager() throws Exception { + final IdleLimitManager manager = new IdleLimitManager(new GrowManager()); + manager.setMaxIdle(2); + pool = new CompositeObjectPool(new IntegerFactory(), manager, new FifoLender(), new DebugTracker(), false); + + assertEquals(0, pool.getNumIdle()); + + pool.addObject(); + assertEquals(1, pool.getNumIdle()); + + pool.addObject(); + assertEquals(2, pool.getNumIdle()); + + pool.addObject(); + assertEquals(2, pool.getNumIdle()); + + pool.clear(); + assertEquals(0, pool.getNumIdle()); + + final Integer a = (Integer)pool.borrowObject(); + final Integer b = (Integer)pool.borrowObject(); + final Integer c = (Integer)pool.borrowObject(); + + pool.returnObject(a); + assertEquals(1, pool.getNumIdle()); + + pool.returnObject(b); + assertEquals(2, pool.getNumIdle()); + + pool.returnObject(c); + assertEquals(2, pool.getNumIdle()); + } + + /** + * Make sure [EMAIL PROTECTED] IdleLimitManager} discards the "most idle" object when discarding objects because the pool + * is full. + */ + public void testIdleLimitManagerDiscardsMostIdle() throws Exception { + // FIFO test - the oldest object would be the next one returned. + { // create some scope + final IdleLimitManager manager = new IdleLimitManager(new GrowManager()); + manager.setMaxIdle(2); + pool = new CompositeObjectPool(new IntegerFactory(), manager, new FifoLender(), new DebugTracker(), false); + pool.addObject(); + pool.addObject(); + pool.addObject(); + + final Integer one = (Integer)pool.borrowObject(); + final Integer two = (Integer)pool.borrowObject(); + final Integer three = (Integer)pool.borrowObject(); + + assertEquals(1, one.intValue()); + assertEquals(2, two.intValue()); + assertEquals(3, three.intValue()); + } + + // LIFO test - the oldest object would be the last one returned. + { // create some scope + final IdleLimitManager manager = new IdleLimitManager(new GrowManager()); + manager.setMaxIdle(2); + pool = new CompositeObjectPool(new IntegerFactory(), manager, new LifoLender(), new DebugTracker(), false); + pool.addObject(); + pool.addObject(); + pool.addObject(); + + final Integer two = (Integer)pool.borrowObject(); + final Integer one = (Integer)pool.borrowObject(); + final Integer three = (Integer)pool.borrowObject(); + + assertEquals(2, two.intValue()); + assertEquals(1, one.intValue()); + assertEquals(3, three.intValue()); + } + } + + /** + * Make sure [EMAIL PROTECTED] FailLimitManager} actually limits the number of active objects. + */ + public void testFailLimitManager() throws Exception { + final ActiveLimitManager manager = new FailLimitManager(new GrowManager()); + manager.setMaxActive(2); + pool = new CompositeObjectPool(new IntegerFactory(), manager, new FifoLender(), new DebugTracker(), false); + + assertEquals(0, pool.getNumActive()); + + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + Integer one = (Integer)pool.borrowObject(); + assertEquals(2, pool.getNumActive()); + + try { + pool.borrowObject(); + fail("Should have thrown a NoSuchElementException"); + } catch(NoSuchElementException nsee) { + // expected + } + assertEquals(2, pool.getNumActive()); + + pool.returnObject(zero); + assertEquals(1, pool.getNumActive()); + + zero = (Integer)pool.borrowObject(); + assertEquals(2, pool.getNumActive()); + + try { + pool.borrowObject(); + fail("Should have thrown a NoSuchElementException"); + } catch(NoSuchElementException nsee) { + // expected + } + assertEquals(2, pool.getNumActive()); + } + + /** + * Make sure that [EMAIL PROTECTED] WaitLimitManager} both times out and returns an object once one is available. + */ + public void testWaitLimitManager() throws Exception { + final WaitLimitManager manager = new WaitLimitManager(new GrowManager()); + manager.setMaxActive(1); + manager.setMaxWaitMillis(100); + pool = new CompositeObjectPool(new IntegerFactory(), manager, new FifoLender(), new DebugTracker(), false); + + assertEquals(0, pool.getNumActive()); + + final Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + // Test that the max wait + try { + pool.borrowObject(); + fail("Should have thrown a NoSuchElementException"); + } catch(NoSuchElementException nsee) { + // expected + } + + // test that if an object is returned while waiting it works. + // What happens is: + // this thread locks pool.pool and starts Thread t. + // this thread will get wait for an object to become available and relase the lock on pool.pool + // Thread t will then be able to lock on pool.pool and return an object + // this thread will then be able to borrow an object and should reutrn. + final List actualOrder = new ArrayList(); + final Runnable r = new Runnable() { + public void run() { + try { + synchronized(pool.getPool()) { + pool.returnObject(zero); + actualOrder.add("returned"); + } + } catch (Exception e) { + waitFailed = true; + } + } + }; + final Thread t = new Thread(r); + + synchronized (pool.getPool()) { + t.start(); + + actualOrder.add("waiting"); + assertEquals(zero, pool.borrowObject()); + actualOrder.add("borrowed"); + } + + assertEquals("Wait failed", false, waitFailed); + + List expectedOrder = new ArrayList(); + expectedOrder.add("waiting"); + expectedOrder.add("returned"); + expectedOrder.add("borrowed"); + + assertEquals(expectedOrder, actualOrder); + } + private boolean waitFailed = false; + + // Test Trackers -------------------------------------- + + /** + * Make sure the [EMAIL PROTECTED] NullTracker} doesn't do anything and throws an [EMAIL PROTECTED] UnsupportedOperationException}. + */ + public void testNullTracker() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new FifoLender(), new NullTracker(), false); + try { + pool.getNumActive(); + fail("Should have thrown an UnsupportedOperationException."); + } catch(UnsupportedOperationException usoee) { + // expected + } + + Integer zero = (Integer)pool.borrowObject(); + + try { + pool.getNumActive(); + fail("Should have thrown an UnsupportedOperationException."); + } catch(UnsupportedOperationException usoee) { + // expected + } + } + + /** + * Make sure [EMAIL PROTECTED] SimpleTracker} counts the number of borrowed and returned objects and that an + * [EMAIL PROTECTED] IllegalStateException} is thrown when more objects are returned than were borrowed. + */ + public void testSimpleTracker() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + assertEquals(0, pool.getNumActive()); + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + Integer one = (Integer)pool.borrowObject(); + assertEquals(2, pool.getNumActive()); + pool.returnObject(zero); + assertEquals(1, pool.getNumActive()); + pool.returnObject(one); + assertEquals(0, pool.getNumActive()); + + try { + pool.returnObject(new Object()); + fail("Should have thrown an IllegalStateException."); + } catch(IllegalStateException ise) { + // expected + } + } + + /** + * Make sure [EMAIL PROTECTED] ReferenceTracker} detects when an active object is "lost". Make sure an + * [EMAIL PROTECTED] IllegalStateException} is thrown with an object that wasn't borrowed is returned. + * This covers the core funtionality of [EMAIL PROTECTED] DebugTracker} too; it's unique features aren't easily testable. + */ + public void testReferenceTracker() throws Exception { + // setup + final SortedSet borrowedIds = new TreeSet(); + final SortedSet removedIds = new TreeSet(); + final Tracker tracker = new ReferenceTracker() { + protected void referenceToBeRemoved(final IdentityReference ref) { + removedIds.add(new Integer(ref.getKey().hashCode())); + } + }; + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new FifoLender(), tracker, false); + + // borrow some objects + List objs = new ArrayList(10); + for (int i=0; i < 10 ; i++) { + Object obj = pool.borrowObject(); + borrowedIds.add(new Integer(System.identityHashCode(obj))); + objs.add(obj); + obj = null; // prevent leak + } + assertEquals(10, pool.getNumActive()); + objs.clear(); + + + // garbage collect it + while (!removedIds.containsAll(borrowedIds)) { + new Object(); // create garbage + System.gc(); + pool.getNumActive(); // works the reference queue + } + assertEquals(10, removedIds.size()); + assertEquals(0, pool.getNumActive()); + + // make sure we didn't pick up anything extra + assertEquals(borrowedIds, removedIds); + + try { + pool.returnObject(new Object()); + fail("Should have thrown an IllegalStateException. Cannot reutrn an object that wasn't borrowed."); + } catch(IllegalStateException ise) { + // expected + } + + // Make sure we don't accept the same object returned twice + final Object obj = pool.borrowObject(); + pool.returnObject(obj); + try { + pool.returnObject(obj); + fail("Should have thrown an IllegalStateException. Cannot return the same object twice."); + } catch(IllegalStateException ise) { + // expected + } + } + + // Test Lenders --------------------------------------- + + /** + * Make sure [EMAIL PROTECTED] FifoLender} is a FIFO. + */ + public void testFifoLender() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + Integer one = (Integer)pool.borrowObject(); + Integer two = (Integer)pool.borrowObject(); + + pool.returnObject(zero); + pool.returnObject(one); + pool.returnObject(two); + + assertEquals(zero, pool.borrowObject()); + assertEquals(one, pool.borrowObject()); + assertEquals(two, pool.borrowObject()); + } + + /** + * Make sure [EMAIL PROTECTED] LifoLender} is a LIFO. + */ + public void testLifoLender() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new LifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + Integer one = (Integer)pool.borrowObject(); + Integer two = (Integer)pool.borrowObject(); + + pool.returnObject(two); + pool.returnObject(one); + pool.returnObject(zero); + + assertEquals(zero, pool.borrowObject()); + assertEquals(one, pool.borrowObject()); + assertEquals(two, pool.borrowObject()); + } + + /** + * Make sure [EMAIL PROTECTED] SoftLender} responds to memory pressure. + * <p>Note: this test is not completely deterministic and could fail erroneously. + */ + public void testSoftLender() throws Exception { + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), new SoftLender(new FifoLender()), new SimpleTracker(), false); + + Object zero = pool.borrowObject(); + Object one = pool.borrowObject(); + + pool.returnObject(zero); + zero = null; + pool.returnObject(one); + one = null; + + /* This requires a bit of memory pressure to reliablly force a [EMAIL PROTECTED] SoftReference} to break. */ + List garbage = new LinkedList(); + Runtime runtime = Runtime.getRuntime(); + while (pool.getNumIdle() > 0) { + garbage.add(new byte[Math.min(1024 * 1024, (int)runtime.freeMemory())]); + System.gc(); + } + garbage.clear(); + System.gc(); + + assertEquals(0, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + } + + /** + * Make sure [EMAIL PROTECTED] IdleEvictorLender} waits at least the minimum amount of time before evicting objects. + * <p>Note: this test is not completely deterministic and could fail erroneously. + */ + public void testIdleEvictorLender() throws Exception { + final IdleEvictorLender lender = new IdleEvictorLender(new FifoLender()); + lender.setIdleTimeoutMillis(20L); + pool = new CompositeObjectPool(new IntegerFactory(), new GrowManager(), lender, new SimpleTracker(), false); + + pool.addObject(); + assertEquals(1, pool.getNumIdle()); + Thread.sleep(100L); + assertEquals(0, pool.getNumIdle()); + + // XXX This could be more extensive + } + + /** + * Make sure [EMAIL PROTECTED] InvalidEvictorLender} only evicts objects that are no longer valid. + * <p>Note: this test is not completely deterministic and could fail erroneously. + */ + public void testInvalidEvictorLender() throws Exception { + final InvalidEvictorLender lender = new InvalidEvictorLender(new FifoLender()); + lender.setValidationFrequencyMillis(20L); + final IntegerFactory factory = new IntegerFactory(); + pool = new CompositeObjectPool(factory, new GrowManager(), lender, new SimpleTracker(), false); + + pool.addObject(); + pool.addObject(); + assertEquals(2, pool.getNumIdle()); + Thread.sleep(100L); + assertEquals(2, pool.getNumIdle()); + + factory.setEvenValid(false); + Thread.sleep(100L); + assertEquals(1, pool.getNumIdle()); + + factory.setOddValid(false); + Thread.sleep(100L); + assertEquals(0, pool.getNumIdle()); + } + + // Test exceptions from PoolableObjectFactory --------- + + /** + * Make sure [EMAIL PROTECTED] CompositeObjectPool#borrowObject()} doesn't mask exceptions from + * [EMAIL PROTECTED] PoolableObjectFactory#makeObject()}. + */ + public void testExceptionOnNewObject() throws Exception { + PoolableObjectFactory pof = new BasePoolableObjectFactory() { + public Object makeObject() throws Exception { + throw new PrivateException("Cannot make new objects."); + } + }; + pool = new CompositeObjectPool(pof, new GrowManager(), new SoftLender(new FifoLender()), new SimpleTracker(), false); + + try { + pool.borrowObject(); + fail("Should have thrown a PrivateException"); + } catch (PrivateException pe) { + // expected + } + + try { + pool.addObject(); + fail("Should have thrown a PrivateException"); + } catch (PrivateException pe) { + // expected + } + } + + public void testExceptionOnActivateObject() throws Exception { + PoolableObjectFactory pof = new IntegerFactory() { + public void activateObject(Object obj) throws Exception { + throw new PrivateException("Cannot activate objects."); + } + }; + pool = new CompositeObjectPool(pof, new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + pool.returnObject(zero); + + assertEquals(1, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + + // Should successed even though activation failed by discarding zero and making one. + final Integer one = (Integer)pool.borrowObject(); + assertEquals(new Integer(1), one); + assertEquals(0, pool.getNumIdle()); + assertEquals(1, pool.getNumActive()); + } + + public void testExceptionOnValidateObject() throws Exception { + PoolableObjectFactory pof = new IntegerFactory() { + public boolean validateObject(final Object obj) { + throw new PrivateException("Cannot validate objects."); + } + }; + pool = new CompositeObjectPool(pof, new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + pool.returnObject(zero); + + assertEquals(1, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + + assertEquals(new Integer(1), pool.borrowObject()); + assertEquals(0, pool.getNumIdle()); + assertEquals(1, pool.getNumActive()); + } + + public void testExceptionOnPasivateObject() throws Exception { + PoolableObjectFactory pof = new IntegerFactory() { + public void passivateObject(final Object obj) throws Exception { + throw new PrivateException("Cannot passivate objects."); + } + }; + pool = new CompositeObjectPool(pof, new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + pool.returnObject(zero); + + assertEquals(0, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + } + + public void testExceptionOnDestroyObject() throws Exception { + PoolableObjectFactory pof = new IntegerFactory() { + public void destroyObject(final Object obj) throws Exception { + throw new PrivateException("Cannot destroy objects."); + } + }; + pool = new CompositeObjectPool(pof, new GrowManager(), new FifoLender(), new SimpleTracker(), false); + + Integer zero = (Integer)pool.borrowObject(); + assertEquals(1, pool.getNumActive()); + + pool.invalidateObject(zero); + + assertEquals(0, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + } + + // Utility classes ------------------------------------ + + private static class IntegerFactory extends BasePoolableObjectFactory { + private int count = 0; + private boolean oddValid = true; + private boolean evenValid = true; + + public Object makeObject() throws Exception { + return new Integer(count++); + } + + public boolean validateObject(final Object obj) { + final Integer num = (Integer)obj; + if (num.intValue() % 2 == 0) { + return evenValid; + } else { + return oddValid; + } + } + + public void setValid(final boolean valid) { + setEvenValid(valid); + setOddValid(valid); + } + + public void setOddValid(final boolean oddValid) { + this.oddValid = oddValid; + } + + public void setEvenValid(final boolean evenValid) { + this.evenValid = evenValid; + } + } + + /** + * An exception that only is thrown by this test. + */ + private static class PrivateException extends RuntimeException { + PrivateException(final String message) { + super(message); + } + } +} \ No newline at end of file
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]