Author: psteitz Date: Mon Jul 5 17:15:07 2010 New Revision: 960644 URL: http://svn.apache.org/viewvc?rev=960644&view=rev Log: Consolidated test factories, improved test coverage.
Modified: commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackObjectPool.java Modified: commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackObjectPool.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackObjectPool.java?rev=960644&r1=960643&r2=960644&view=diff ============================================================================== --- commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackObjectPool.java (original) +++ commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackObjectPool.java Mon Jul 5 17:15:07 2010 @@ -64,6 +64,9 @@ public class TestStackObjectPool extends } } + /** + * @deprecated - to be removed in pool 2.0 + */ public void testPoolWithNullFactory() throws Exception { ObjectPool pool = new StackObjectPool(10); for(int i=0;i<10;i++) { @@ -87,6 +90,9 @@ public class TestStackObjectPool extends pool.clear(); } + /** + * @deprecated - to be removed in pool 2.0 + */ public void testBorrowFromEmptyPoolWithNullFactory() throws Exception { ObjectPool pool = new StackObjectPool(); try { @@ -97,6 +103,9 @@ public class TestStackObjectPool extends } } + /** + * @deprecated - to be removed in pool 2.0 + */ public void testSetFactory() throws Exception { ObjectPool pool = new StackObjectPool(); try { @@ -111,6 +120,9 @@ public class TestStackObjectPool extends pool.returnObject(obj); } + /** + * @deprecated - to be removed in pool 2.0 + */ public void testCantResetFactoryWithActiveObjects() throws Exception { ObjectPool pool = new StackObjectPool(); pool.setFactory(new SimpleFactory()); @@ -125,6 +137,9 @@ public class TestStackObjectPool extends } } + /** + * @deprecated - to be removed in pool 2.0 + */ public void testCanResetFactoryWithoutActiveObjects() throws Exception { ObjectPool pool = new StackObjectPool(); { @@ -141,33 +156,16 @@ public class TestStackObjectPool extends } } - + /** + * Verifies that validation failures when borrowing newly created instances + * from the pool result in NoSuchElementExceptions and passivation failures + * result in instances not being returned to the pool. + */ public void testBorrowWithSometimesInvalidObjects() throws Exception { - ObjectPool pool = new StackObjectPool(20); - pool.setFactory( - new PoolableObjectFactory() { - // factory makes Integer objects - int counter = 0; - public Object makeObject() { return new Integer(counter++); } - public void destroyObject(Object obj) { } - public boolean validateObject(Object obj) { - // only odd objects are valid - if(obj instanceof Integer) { - return ((((Integer)obj).intValue() % 2) == 1); - } else { - return false; - } - } - public void activateObject(Object obj) { } - public void passivateObject(Object obj) { - final Integer integer = (Integer)obj; - if (integer.intValue() % 3 == 0) { - throw new RuntimeException("Couldn't passivate: " + integer); - } - } - } - ); - + SelectiveFactory factory = new SelectiveFactory(); + factory.setValidateSelectively(true); // Even numbers fail validation + factory.setPassivateSelectively(true); // Multiples of 3 fail passivation + ObjectPool pool = new StackObjectPool(factory, 20); Object[] obj = new Object[10]; for(int i=0;i<10;i++) { Object object = null; @@ -176,9 +174,13 @@ public class TestStackObjectPool extends try { k++; object = pool.borrowObject(); - obj[i] = object; + if (((Integer) object).intValue() % 2 == 0) { + fail("Expecting NoSuchElementException"); + } else { + obj[i] = object; + } } catch (NoSuchElementException ex) { - // Expected for evens, which fail validation + // Should fail for evens } } assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive()); @@ -199,43 +201,13 @@ public class TestStackObjectPool extends assertEquals(new Integer(1), pool.borrowObject()); } + /** + * Verifies that validation and passivation failures returning objects are handled + * properly - instances destroyed and not returned to the pool, but no exceptions propagated. + */ public void testBorrowReturnWithSometimesInvalidObjects() throws Exception { - ObjectPool pool = new StackObjectPool(20); - - class TestingPoolableObjectFactory implements PoolableObjectFactory { - // factory makes Integer objects - int counter = 0; - boolean reject = false; - public Object makeObject() { return new Integer(counter++); } - public void destroyObject(Object obj) { } - public boolean validateObject(Object obj) { - if (reject) { - // only odd objects are valid - if(obj instanceof Integer) { - return ((((Integer)obj).intValue() % 2) == 1); - } else { - return false; - } - } else { - return true; - } - - } - public void activateObject(Object obj) { } - public void passivateObject(Object obj) { - if(obj instanceof Integer) { - if((((Integer)obj).intValue() % 3) == 0) { - throw new RuntimeException("Couldn't passivate"); - } - } else { - throw new RuntimeException("Couldn't passivate"); - } - } - } - - TestingPoolableObjectFactory factory = new TestingPoolableObjectFactory(); - - pool.setFactory(factory); + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory, 20); Object[] obj = new Object[10]; for(int i=0;i<10;i++) { @@ -244,8 +216,8 @@ public class TestStackObjectPool extends } - // now reject even numbers - factory.reject = true; + factory.setValidateSelectively(true); // Even numbers fail validation + factory.setPassivateSelectively(true); // Multiples of 3 fail passivation for(int i=0;i<10;i++) { pool.returnObject(obj[i]); @@ -254,7 +226,7 @@ public class TestStackObjectPool extends // 0,2,4,6,8 fail validation, 3, 9 fail passivation - 3 left. assertEquals(3,pool.getNumIdle()); } - + public void testVariousConstructors() throws Exception { { StackObjectPool pool = new StackObjectPool(); @@ -281,32 +253,25 @@ public class TestStackObjectPool extends assertNotNull(pool); } } + + /** + * Verify that out of range constructor arguments are ignored. + */ + public void testMaxIdleInitCapacityOutOfRange() throws Exception { + SimpleFactory factory = new SimpleFactory(); + StackObjectPool pool = new StackObjectPool(factory, -1, 0); + assertEquals(pool.getMaxSleeping(), StackObjectPool.DEFAULT_MAX_SLEEPING); + pool.addObject(); + pool.close(); + } - private final List destroyed = new ArrayList(); + /** + * Verifies that when returning objects cause maxSleeping exceeded, oldest instances + * are destroyed to make room for returning objects. + */ public void testReturnObjectDiscardOrder() throws Exception { - // setup - // We need a factory that tracks what was discarded. - PoolableObjectFactory pof = new PoolableObjectFactory() { - int i = 0; - public Object makeObject() throws Exception { - return new Integer(i++); - } - - public void destroyObject(Object obj) throws Exception { - destroyed.add(obj); - } - - public boolean validateObject(Object obj) { - return obj instanceof Integer; - } - - public void activateObject(Object obj) throws Exception { - } - - public void passivateObject(Object obj) throws Exception { - } - }; - ObjectPool pool = new StackObjectPool(pof, 3); + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory, 3); // borrow more objects than the pool can hold Integer i0 = (Integer)pool.borrowObject(); @@ -321,17 +286,215 @@ public class TestStackObjectPool extends pool.returnObject(i2); // the pool should now be full. - assertEquals("No returned objects should have been destroyed yet.",0, destroyed.size()); + assertEquals("No returned objects should have been destroyed yet.", 0, factory.getDestroyed().size()); - // cause the pool to discard a returned object. + // cause the pool to discard a stale object. pool.returnObject(i3); - assertEquals("One object should have been destroyed.", 1, destroyed.size()); + assertEquals("One object should have been destroyed.", 1, factory.getDestroyed().size()); // check to see what object was destroyed - Integer d = (Integer)destroyed.get(0); - assertEquals("Destoryed objects should have the stalest object.", i0, d); + Integer d = (Integer)factory.getDestroyed().get(0); + assertEquals("Destoryed object should be the stalest object.", i0, d); + } + + /** + * Verifies that exceptions thrown by factory activate method are not propagated to + * the caller. Objects that throw on activate are destroyed and if none succeed, + * the caller gets NoSuchElementException. + */ + public void testExceptionOnActivate() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory); + pool.addObject(); + pool.addObject(); + factory.setThrowOnActivate(true); + try { + pool.borrowObject(); + fail("Expecting NoSuchElementException"); + } catch (NoSuchElementException ex) { + // expected + } + assertEquals(0, pool.getNumIdle()); + assertEquals(0, pool.getNumActive()); + } + + /** + * Verifies that exceptions thrown by factory destroy are swallowed + * by both addObject and returnObject. + */ + public void testExceptionOnDestroy() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory, 2); + factory.setThrowOnDestroy(true); + for (int i = 0; i < 3; i++) { + pool.addObject(); // Third one will destroy, exception should be swallowed + } + assertEquals(2, pool.getNumIdle()); + + Object[] objects = new Object[3]; + for (int i = 0; i < 3; i++) { + objects[i] = pool.borrowObject(); + } + for (int i = 0; i < 3; i++) { + pool.returnObject(objects[i]); // Third triggers destroy + } + assertEquals(2, pool.getNumIdle()); + } + + /** + * Verifies that addObject propagates exceptions thrown by + * factory passivate, but returnObject swallows these. + */ + public void testExceptionOnPassivate() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory, 2); + factory.setThrowOnPassivate(true); + + // addObject propagates + try { + pool.addObject(); + fail("Expecting IntegerFactoryException"); + } catch (IntegerFactoryException ex) { + assertEquals("passivateObject", ex.getType()); + assertEquals(0, ex.getValue()); + } + assertEquals(0, pool.getNumIdle()); + + // returnObject swallows + Object obj = pool.borrowObject(); + pool.returnObject(obj); + assertEquals(0, pool.getNumIdle()); + } + + /** + * Verifies that validation exceptions always propagate + */ + public void testExceptionOnValidate() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory, 2); + factory.setThrowOnValidate(true); + + // addObject + try { + pool.addObject(); + fail("Expecting IntegerFactoryException"); + } catch (IntegerFactoryException ex) { + assertEquals("validateObject", ex.getType()); + } + assertEquals(0, pool.getNumIdle()); + + // returnObject + factory.setThrowOnValidate(false); + Object obj = pool.borrowObject(); + factory.setThrowOnValidate(true); + try { + pool.returnObject(obj); + fail("Expecting IntegerFactoryException"); + } catch (IntegerFactoryException ex) { + assertEquals("validateObject", ex.getType()); + } + assertEquals(0, pool.getNumIdle()); + + // borrowObject - throws NoSuchElementException + try { + pool.borrowObject(); + fail("Expecting NoSuchElementException"); + } catch (NoSuchElementException ex) { + // Expected + } + } + + /** + * Verifies that exceptions thrown by makeObject are propagated. + */ + public void testExceptionOnMake() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + factory.setThrowOnMake(true); + ObjectPool pool = new StackObjectPool(factory); + try { + pool.borrowObject(); + fail("Expecting IntegerFactoryException"); + } catch (IntegerFactoryException ex) { + assertEquals("makeObject", ex.getType()); + } + try { + pool.addObject(); + fail("Expecting IntegerFactoryException"); + } catch (IntegerFactoryException ex) { + assertEquals("makeObject", ex.getType()); + } + } + + /** + * Verifies NoSuchElementException when the factory returns a null object in borrowObject + */ + public void testMakeNull() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory); + factory.setMakeNull(true); + try { + pool.borrowObject(); + fail("Expecting NoSuchElementException"); + } catch (NoSuchElementException ex) { + // Expected + } + } + + /** + * Verifies that initIdleCapacity is not a hard limit, but maxIdle is. + */ + public void testInitIdleCapacityExceeded() throws Exception { + PoolableObjectFactory factory = new SimpleFactory(); + ObjectPool pool = new StackObjectPool(factory, 2, 1); + pool.addObject(); + pool.addObject(); + assertEquals(2, pool.getNumIdle()); + pool.close(); + pool = new StackObjectPool(factory, 1, 2); + pool.addObject(); + pool.addObject(); + assertEquals(1, pool.getNumIdle()); + } + + /** + * Verifies close contract - idle instances are destroyed, returning instances + * are destroyed, add/borrowObject throw IllegalStateException. + */ + public void testClose() throws Exception { + SelectiveFactory factory = new SelectiveFactory(); + ObjectPool pool = new StackObjectPool(factory); + pool.addObject(); // 0 + pool.addObject(); // 1 + pool.addObject(); // 2 + Integer two = (Integer) pool.borrowObject(); + assertEquals(2, two.intValue()); + pool.close(); + assertEquals(0, pool.getNumIdle()); + assertEquals(1, pool.getNumActive()); + List destroyed = factory.getDestroyed(); + assertEquals(2, destroyed.size()); + assertTrue(destroyed.contains(new Integer(0))); + assertTrue(destroyed.contains(new Integer(0))); + pool.returnObject(two); + assertTrue(destroyed.contains(two)); + try { + pool.addObject(); + fail("Expecting IllegalStateException"); + } catch (IllegalStateException ex) { + // Expected + } + try { + pool.borrowObject(); + fail("Expecting IllegalStateException"); + } catch (IllegalStateException ex) { + // Expected + } } + /** + * Simple factory that creates Integers. Validation and other factory methods + * always succeed. + */ static class SimpleFactory implements PoolableObjectFactory { int counter = 0; public Object makeObject() { return String.valueOf(counter++); } @@ -340,6 +503,117 @@ public class TestStackObjectPool extends public void activateObject(Object obj) { } public void passivateObject(Object obj) { } } + + /** + * Integer factory that fails validation and other factory methods "selectively" and + * tracks object destruction. + */ + static class SelectiveFactory implements PoolableObjectFactory { + private List destroyed = new ArrayList(); + private int counter = 0; + private boolean validateSelectively = false; // true <-> validate returns false for even Integers + private boolean passivateSelectively = false; // true <-> passivate throws RTE if Integer = 0 mod 3 + private boolean throwOnDestroy = false; // true <-> destroy throws RTE (always) + private boolean throwOnActivate = false; // true <-> activate throws RTE (always) + private boolean throwOnMake = false; // true <-> make throws RTE (always) + private boolean throwOnValidate= false; // true <-> validate throws RTE (always) + private boolean throwOnPassivate = false; // true <-> passivate throws RTE (always) + private boolean makeNull = false; // true <-> make returns null + public Object makeObject() { + if (throwOnMake) { + final int next = counter + 1; + throw new IntegerFactoryException("makeObject", next); + } else { + return makeNull? null : new Integer(counter++); + } + } + public void destroyObject(Object obj) { + if (throwOnDestroy) { + final Integer integer = (Integer)obj; + throw new IntegerFactoryException("destroyObject", integer.intValue()); + } + destroyed.add(obj); + } + public boolean validateObject(Object obj) { + if (throwOnValidate) { + final Integer integer = (Integer)obj; + throw new IntegerFactoryException("validateObject", integer.intValue()); + } + if (validateSelectively) { + // only odd objects are valid + if(obj instanceof Integer) { + return ((((Integer)obj).intValue() % 2) == 1); + } else { + return false; + } + } + return true; + } + public void activateObject(Object obj) { + if (throwOnActivate) { + final Integer integer = (Integer)obj; + throw new IntegerFactoryException("activateObject", integer.intValue()); + } + } + public void passivateObject(Object obj) { + if (throwOnPassivate) { + final Integer integer = (Integer)obj; + throw new IntegerFactoryException("passivateObject", integer.intValue()); + } + if (passivateSelectively) { + final Integer integer = (Integer)obj; + if (integer.intValue() % 3 == 0) { + throw new IntegerFactoryException("passivateObject", integer.intValue()); + } + } + } + public List getDestroyed() { + return destroyed; + } + public void setCounter(int counter) { + this.counter = counter; + } + public void setValidateSelectively(boolean validateSelectively) { + this.validateSelectively = validateSelectively; + } + public void setPassivateSelectively(boolean passivateSelectively) { + this.passivateSelectively = passivateSelectively; + } + public void setThrowOnDestroy(boolean throwOnDestroy) { + this.throwOnDestroy = throwOnDestroy; + } + public void setThrowOnActivate(boolean throwOnActivate) { + this.throwOnActivate = throwOnActivate; + } + public void setThrowOnMake(boolean throwOnMake) { + this.throwOnMake = throwOnMake; + } + public void setThrowOnPassivate(boolean throwOnPassivate) { + this.throwOnPassivate = throwOnPassivate; + } + public void setThrowOnValidate(boolean throwOnValidate) { + this.throwOnValidate = throwOnValidate; + } + public void setMakeNull(boolean makeNull) { + this.makeNull = makeNull; + } + } + + static class IntegerFactoryException extends RuntimeException { + private String type; + private int value; + public IntegerFactoryException(String type, int value) { + super(type + " failed. Value: " + value); + this.type = type; + this.value = value; + } + public String getType() { + return type; + } + public int getValue() { + return value; + } + } protected boolean isLifo() { return true;