/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://opensource.org/licenses/cddl1.php * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at http://opensource.org/licenses/cddl1.php. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.framework.impl.api.local; import org.identityconnectors.framework.common.serializer.SerializerUtil; import org.testng.Assert; import org.testng.annotations.Test; import org.identityconnectors.common.pooling.ObjectPoolConfiguration; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.impl.api.local.ObjectPool.Statistics; public class ObjectPoolTests { private class MyTestConnection { private boolean _isGood = true; @Test public void test() { if (!_isGood) { throw new ConnectorException("Connection is bad"); } } public void dispose() { _isGood = false; } public boolean isGood() { return _isGood; } } private class MyTestConnectionFactory implements ObjectPoolHandler<MyTestConnection> { private boolean _createBadConnection = false; private int _totalCreatedConnections = 0; public ObjectPoolConfiguration validate(ObjectPoolConfiguration original) { ObjectPoolConfiguration configuration = (ObjectPoolConfiguration) SerializerUtil.cloneObject(original); //validate it configuration.validate(); return configuration; } public MyTestConnection makeObject() { _totalCreatedConnections++; MyTestConnection rv = new MyTestConnection(); if (_createBadConnection) { rv.dispose(); } return rv; } @Test public void testObject(MyTestConnection object) { object.test(); } public void disposeObject(MyTestConnection object) { object.dispose(); } public int getTotalCreatedConnections() { return _totalCreatedConnections; } public void setCreateBadConnection(boolean v) { _createBadConnection = v; } public void shutdown() { } } private class MyTestThread extends Thread { private final ObjectPool<MyTestConnection> _pool; private final int _numIterations; private Exception _exception; public MyTestThread(ObjectPool<MyTestConnection> pool, int numIterations) { _pool = pool; _numIterations = numIterations; } @Override public void run() { try { for ( int i = 0; i < _numIterations; i++ ) { ObjectPoolEntry<MyTestConnection> con = _pool.borrowObject(); Thread.sleep(300); con.close(); } } catch (Exception e) { _exception = e; } } public void shutdown() throws Exception { join(); if (_exception != null) { throw _exception; } } } @Test public void testWithManyThreads() throws Exception { final int NUM_ITERATIONS = 10; final int NUM_THREADS = 10; final int MAX_CONNECTIONS = NUM_THREADS-3; //make sure we get some waiting ObjectPoolConfiguration config = new ObjectPoolConfiguration(); config.setMaxObjects(MAX_CONNECTIONS); config.setMaxIdle(MAX_CONNECTIONS); config.setMinIdle(MAX_CONNECTIONS); config.setMinEvictableIdleTimeMillis(60*1000); config.setMaxWait(60*1000); MyTestConnectionFactory fact = new MyTestConnectionFactory(); ObjectPool<MyTestConnection> pool = new ObjectPool<MyTestConnection>(fact,config); MyTestThread [] threads = new MyTestThread[NUM_THREADS]; for (int i = 0; i < threads.length; i++) { threads[i] = new MyTestThread(pool,NUM_ITERATIONS); threads[i].start(); } for (MyTestThread thread : threads) { thread.shutdown(); } //these should be the same since we never //should have disposed anything Assert.assertEquals(MAX_CONNECTIONS, fact.getTotalCreatedConnections()); Statistics stats = pool.getStatistics(); Assert.assertEquals(stats.getNumActive(), 0); Assert.assertEquals(MAX_CONNECTIONS, stats.getNumIdle()); pool.shutdown(); stats = pool.getStatistics(); Assert.assertEquals(0, stats.getNumActive()); Assert.assertEquals(0, stats.getNumIdle()); } @Test public void testBadConnection() throws Exception { final int MAX_CONNECTIONS = 3; ObjectPoolConfiguration config = new ObjectPoolConfiguration(); config.setMaxObjects(MAX_CONNECTIONS); config.setMaxIdle(MAX_CONNECTIONS); config.setMinIdle(MAX_CONNECTIONS); config.setMinEvictableIdleTimeMillis(60*1000); config.setMaxWait(60*1000); MyTestConnectionFactory fact = new MyTestConnectionFactory(); ObjectPool<MyTestConnection> pool = new ObjectPool<MyTestConnection>(fact,config); //borrow first connection and return ObjectPoolEntry<MyTestConnection> conn = pool.borrowObject(); Assert.assertEquals(1, fact.getTotalCreatedConnections()); conn.close(); Assert.assertEquals(1, fact.getTotalCreatedConnections()); //re-borrow same connection and return conn = pool.borrowObject(); Assert.assertEquals(1, fact.getTotalCreatedConnections()); conn.close(); Assert.assertEquals(1, fact.getTotalCreatedConnections()); //dispose and make sure we get a new connection conn.getPooledObject().dispose(); conn = pool.borrowObject(); Assert.assertEquals(2, fact.getTotalCreatedConnections()); conn.close(); Assert.assertEquals(2, fact.getTotalCreatedConnections()); } @Test public void testIdleCleanup() throws Exception { ObjectPoolConfiguration config = new ObjectPoolConfiguration(); config.setMaxObjects(3); config.setMaxIdle(2); config.setMinIdle(1); config.setMinEvictableIdleTimeMillis(3000); config.setMaxWait(60*1000); MyTestConnectionFactory fact = new MyTestConnectionFactory(); ObjectPool<MyTestConnection> pool = new ObjectPool<MyTestConnection>(fact,config); ObjectPoolEntry<MyTestConnection> conn1 = pool.borrowObject(); ObjectPoolEntry<MyTestConnection> conn2 = pool.borrowObject(); ObjectPoolEntry<MyTestConnection> conn3 = pool.borrowObject(); Assert.assertEquals(3, fact.getTotalCreatedConnections()); conn1.close(); Assert.assertEquals(1, pool.getStatistics().getNumIdle()); conn2.close(); Assert.assertEquals(pool.getStatistics().getNumIdle(), 2); conn3.close(); Assert.assertEquals(pool.getStatistics().getNumIdle(), 2); Assert.assertEquals(false, conn1.getPooledObject().isGood()); Assert.assertEquals(true, conn2.getPooledObject().isGood()); Assert.assertEquals(true, conn3.getPooledObject().isGood()); Thread.sleep(config.getMinEvictableIdleTimeMillis()+1000); ObjectPoolEntry<MyTestConnection> conn4 = pool.borrowObject(); Assert.assertSame(conn3, conn4); Assert.assertEquals(false, conn1.getPooledObject().isGood()); Assert.assertEquals(false, conn2.getPooledObject().isGood()); Assert.assertEquals(true, conn3.getPooledObject().isGood()); Assert.assertEquals(true, conn4.getPooledObject().isGood()); } @Test public void testCreateBadConnection() throws Exception { MyTestConnectionFactory fact = new MyTestConnectionFactory(); fact.setCreateBadConnection(true); ObjectPool<MyTestConnection> pool = new ObjectPool<MyTestConnection>(fact,new ObjectPoolConfiguration()); try { pool.borrowObject(); Assert.fail("expected exception"); } catch (ConnectorException e) { Assert.assertEquals("Connection is bad", e.getMessage()); } } }