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.ObjectPool;
023    import org.apache.commons.pool.PoolableObjectFactory;
024    import org.apache.commons.pool.TestBaseObjectPool;
025    
026    import java.util.ArrayList;
027    import java.util.BitSet;
028    import java.util.List;
029    import java.util.NoSuchElementException;
030    
031    /**
032     * @author Rodney Waldhoff
033     * @author Dirk Verbeeck
034     * @author Sandy McArthur
035     * @version $Revision: 775703 $ $Date: 2009-05-17 12:39:51 -0400 (Sun, 17 May 2009) $
036     */
037    public class TestStackObjectPool extends TestBaseObjectPool {
038        public TestStackObjectPool(String testName) {
039            super(testName);
040        }
041    
042        public static Test suite() {
043            return new TestSuite(TestStackObjectPool.class);
044        }
045    
046        protected ObjectPool makeEmptyPool(int mincap) {
047            return new StackObjectPool(new SimpleFactory());
048        }
049    
050        protected ObjectPool makeEmptyPool(final PoolableObjectFactory factory) {
051            return new StackObjectPool(factory);
052        }
053    
054        protected Object getNthObject(int n) {
055            return String.valueOf(n);
056        }
057    
058        public void testIdleCap() throws Exception {
059            ObjectPool pool = makeEmptyPool(8);
060            Object[] active = new Object[100];
061            for(int i=0;i<100;i++) {
062                active[i] = pool.borrowObject();
063            }
064            assertEquals(100,pool.getNumActive());
065            assertEquals(0,pool.getNumIdle());
066            for(int i=0;i<100;i++) {
067                pool.returnObject(active[i]);
068                assertEquals(99 - i,pool.getNumActive());
069                assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
070            }
071        }
072    
073        public void testPoolWithNullFactory() throws Exception {
074            ObjectPool pool = new StackObjectPool(10);
075            for(int i=0;i<10;i++) {
076                pool.returnObject(new Integer(i));
077            }
078            for(int j=0;j<3;j++) {
079                Integer[] borrowed = new Integer[10];
080                BitSet found = new BitSet();
081                for(int i=0;i<10;i++) {
082                    borrowed[i] = (Integer)(pool.borrowObject());
083                    assertNotNull(borrowed);
084                    assertTrue(!found.get(borrowed[i].intValue()));
085                    found.set(borrowed[i].intValue());
086                }
087                for(int i=0;i<10;i++) {
088                    pool.returnObject(borrowed[i]);
089                }
090            }
091            pool.invalidateObject(pool.borrowObject());
092            pool.invalidateObject(pool.borrowObject());
093            pool.clear();        
094        }
095        
096        public void testBorrowFromEmptyPoolWithNullFactory() throws Exception {
097            ObjectPool pool = new StackObjectPool();
098            try {
099                pool.borrowObject();
100                fail("Expected NoSuchElementException");
101            } catch(NoSuchElementException e) {
102                // expected
103            }
104        }
105        
106        public void testSetFactory() throws Exception {
107            ObjectPool pool = new StackObjectPool();
108            try {
109                pool.borrowObject();
110                fail("Expected NoSuchElementException");
111            } catch(NoSuchElementException e) {
112                // expected
113            }
114            pool.setFactory(new SimpleFactory());
115            Object obj = pool.borrowObject();
116            assertNotNull(obj);
117            pool.returnObject(obj);
118        }
119    
120        public void testCantResetFactoryWithActiveObjects() throws Exception {
121            ObjectPool pool = new StackObjectPool();
122            pool.setFactory(new SimpleFactory());
123            Object obj = pool.borrowObject();
124            assertNotNull(obj);
125    
126            try {
127                pool.setFactory(new SimpleFactory());
128                fail("Expected IllegalStateException");
129            } catch(IllegalStateException e) {
130                // expected
131            }        
132        }
133        
134        public void testCanResetFactoryWithoutActiveObjects() throws Exception {
135            ObjectPool pool = new StackObjectPool();
136            {
137                pool.setFactory(new SimpleFactory());
138                Object obj = pool.borrowObject();        
139                assertNotNull(obj);
140                pool.returnObject(obj);
141            }
142            {
143                pool.setFactory(new SimpleFactory());
144                Object obj = pool.borrowObject();        
145                assertNotNull(obj);
146                pool.returnObject(obj);
147            }
148        }
149    
150    
151        public void testBorrowWithSometimesInvalidObjects() throws Exception {
152            ObjectPool pool = new StackObjectPool(20);
153            pool.setFactory(
154                new PoolableObjectFactory() {
155                    // factory makes Integer objects
156                    int counter = 0;
157                    public Object makeObject() { return new Integer(counter++); }
158                    public void destroyObject(Object obj) { }
159                    public boolean validateObject(Object obj) {
160                        // only odd objects are valid
161                        if(obj instanceof Integer) {
162                            return ((((Integer)obj).intValue() % 2) == 1);
163                        } else {
164                            return false;
165                        }
166                    }
167                    public void activateObject(Object obj) { }
168                    public void passivateObject(Object obj) { 
169                        final Integer integer = (Integer)obj;
170                        if (integer.intValue() % 3 == 0) {
171                            throw new RuntimeException("Couldn't passivate: " + integer);
172                        }
173                    }
174                }
175            );
176    
177            Object[] obj = new Object[10];
178            for(int i=0;i<10;i++) {
179                Object object = null;
180                int k = 0;
181                while (object == null && k < 100) { // bound not really needed
182                    try {
183                        k++;
184                        object = pool.borrowObject();
185                        obj[i] = object;
186                    } catch (NoSuchElementException ex) {
187                        // Expected for evens, which fail validation
188                    }
189                }
190                assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
191            }
192            // 1,3,5,...,19 pass validation, get checked out
193            for(int i=0;i<10;i++) {
194                pool.returnObject(obj[i]);
195                assertEquals("Each time we return, get one less active.", 9-i, pool.getNumActive());
196            }
197            // 3, 9, 15 fail passivation.  
198            assertEquals(7,pool.getNumIdle());
199            assertEquals(new Integer(19), pool.borrowObject());
200            assertEquals(new Integer(17), pool.borrowObject());
201            assertEquals(new Integer(13), pool.borrowObject());
202            assertEquals(new Integer(11), pool.borrowObject());
203            assertEquals(new Integer(7), pool.borrowObject());
204            assertEquals(new Integer(5), pool.borrowObject());
205            assertEquals(new Integer(1), pool.borrowObject());     
206        }
207        
208        public void testBorrowReturnWithSometimesInvalidObjects() throws Exception {
209            ObjectPool pool = new StackObjectPool(20);
210    
211            class TestingPoolableObjectFactory implements PoolableObjectFactory {
212                // factory makes Integer objects
213                int counter = 0;
214                boolean reject = false;
215                public Object makeObject() { return new Integer(counter++); }
216                public void destroyObject(Object obj) { }
217                public boolean validateObject(Object obj) {
218                    if (reject) {
219                        // only odd objects are valid
220                        if(obj instanceof Integer) {
221                            return ((((Integer)obj).intValue() % 2) == 1);
222                        } else {
223                            return false;
224                        }
225                    } else {
226                        return true;
227                    }
228                        
229                }
230                public void activateObject(Object obj) { }
231                public void passivateObject(Object obj) { 
232                    if(obj instanceof Integer) {
233                        if((((Integer)obj).intValue() % 3) == 0) {
234                            throw new RuntimeException("Couldn't passivate");
235                        }
236                    } else {
237                        throw new RuntimeException("Couldn't passivate");
238                    }
239                }
240            }
241            
242            TestingPoolableObjectFactory factory = new TestingPoolableObjectFactory();
243            
244            pool.setFactory(factory);
245    
246            Object[] obj = new Object[10];
247            for(int i=0;i<10;i++) {
248                obj[i] = pool.borrowObject();
249                assertEquals("Each time we borrow, get one more active.", i+1, pool.getNumActive());
250                
251            }
252            
253            // now reject even numbers
254            factory.reject = true;
255    
256            for(int i=0;i<10;i++) {
257                pool.returnObject(obj[i]);
258                assertEquals("Each time we return, get one less active.", 9-i, pool.getNumActive());
259            }
260            // 0,2,4,6,8 fail validation, 3, 9 fail passivation - 3 left.
261            assertEquals(3,pool.getNumIdle());
262        }
263        
264        public void testVariousConstructors() throws Exception {
265            {
266                StackObjectPool pool = new StackObjectPool();
267                assertNotNull(pool);
268            }
269            {
270                StackObjectPool pool = new StackObjectPool(10);
271                assertNotNull(pool);
272            }
273            {
274                StackObjectPool pool = new StackObjectPool(10,5);
275                assertNotNull(pool);
276            }
277            {
278                StackObjectPool pool = new StackObjectPool(null);
279                assertNotNull(pool);
280            }
281            {
282                StackObjectPool pool = new StackObjectPool(null,10);
283                assertNotNull(pool);
284            }
285            {
286                StackObjectPool pool = new StackObjectPool(null,10,5);
287                assertNotNull(pool);
288            }
289        }
290    
291        private final List destroyed = new ArrayList();
292        public void testReturnObjectDiscardOrder() throws Exception {
293            // setup
294            // We need a factory that tracks what was discarded.
295            PoolableObjectFactory pof = new PoolableObjectFactory() {
296                int i = 0;
297                public Object makeObject() throws Exception {
298                    return new Integer(i++);
299                }
300    
301                public void destroyObject(Object obj) throws Exception {
302                    destroyed.add(obj);
303                }
304    
305                public boolean validateObject(Object obj) {
306                    return obj instanceof Integer;
307                }
308    
309                public void activateObject(Object obj) throws Exception {
310                }
311    
312                public void passivateObject(Object obj) throws Exception {
313                }
314            };
315            ObjectPool pool = new StackObjectPool(pof, 3);
316    
317            // borrow more objects than the pool can hold
318            Integer i0 = (Integer)pool.borrowObject();
319            Integer i1 = (Integer)pool.borrowObject();
320            Integer i2 = (Integer)pool.borrowObject();
321            Integer i3 = (Integer)pool.borrowObject();
322    
323            // tests
324            // return as many as the pool will hold.
325            pool.returnObject(i0);
326            pool.returnObject(i1);
327            pool.returnObject(i2);
328    
329            // the pool should now be full.
330            assertEquals("No returned objects should have been destroyed yet.",0, destroyed.size());
331    
332            // cause the pool to discard a returned object.
333            pool.returnObject(i3);
334            assertEquals("One object should have been destroyed.", 1, destroyed.size());
335    
336            // check to see what object was destroyed
337            Integer d = (Integer)destroyed.get(0);
338            assertEquals("Destoryed objects should have the stalest object.", i0, d);
339        }
340    
341        static class SimpleFactory implements PoolableObjectFactory {
342            int counter = 0;
343            public Object makeObject() { return String.valueOf(counter++); }
344            public void destroyObject(Object obj) { }
345            public boolean validateObject(Object obj) { return true; }
346            public void activateObject(Object obj) { }
347            public void passivateObject(Object obj) { }
348        }
349    
350        protected boolean isLifo() {
351            return true;
352        }
353    
354        protected boolean isFifo() {
355            return false;
356        }
357    }
358