CVS: plexus-container/src/test/org/apache/plexus/util AbstractTestThread.java,NONE,1.1 SweeperPoolTest.java,NONE,1.1 TestThreadManager.java,NONE,1.1 ThreadSafeMapTest.java,NONE,1.1
Jason van Zyl <[email protected]> Tue, 5 Aug 2003 19:46:06 -0500
| Newsgroups | gmane.comp.java.plexus.devel |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/plexus/plexus-container/src/test/org/apache/plexus/util In directory hogshead.codehaus.org:/tmp/cvs-serv4255/src/test/org/apache/plexus/util Added Files: AbstractTestThread.java SweeperPoolTest.java TestThreadManager.java ThreadSafeMapTest.java Log Message: --- NEW FILE: AbstractTestThread.java --- package org.apache.plexus.util; /** * A thread which is registered with a ThreadRegistry and notifies it when it has completed * running. Collects any errors and makes it available for analysis. * * <p>Created on 1/07/2003</p> * * @author <a href="mailto:[email protected]">Bert van Brakel</a> * @version $Revision: 1.1 $ */ public abstract class AbstractTestThread implements Runnable { //~ Instance fields ---------------------------------------------------------------------------- private String name; public static final boolean DEBUG = true; private boolean isRunning = false; /** Error msg provided by implementing class (of why the test failed) */ private String errorMsg = null; /** The registry to notify on completion */ private TestThreadManager registry; /** The error thrown when running the test. Not neccesarily a test failuer as some tests * may test for an exception */ private Throwable error; /** If the thread has been run */ private boolean hasRun = false; /** Flag indicating if the test has passed. Some test might require an * exception so using the error to determine if the test has passed is * not sufficient. */ private boolean passed = false; //~ Constructors ------------------------------------------------------------------------------- /** * Constructor * * <p>Remember to call <code>setThreadRegistry(ThreadRegistry)</code> */ public AbstractTestThread() { super(); } public AbstractTestThread(TestThreadManager registry) { super(); setThreadRegistry(registry); } //~ Methods ------------------------------------------------------------------------------------ /** * @return */ public Throwable getError() { return error; } /** * Resets the test back to it's state before starting. If the test * is currently running this method will block until the test has * finished running. Subclasses should call this method if * overriding it. * * */ public void reset() { //shouldn't reset until the test has finished running synchronized (this) { while (isRunning) { try { wait(); } catch (InterruptedException e) { } } errorMsg = null; error = null; hasRun = false; passed = false; } } /** * Start this TestThread running. If the test is currently running then * this method does nothing. * */ public final void start() { //shouldn't have multiple threads running this test at the same time synchronized (this) { if (isRunning == false) { isRunning = true; Thread t = new Thread(this); t.start(); } } } /** * @return */ public String getErrorMsg() { return errorMsg; } /** * @return */ public boolean hasFailed() { return !passed; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean hasPassed() { return passed; } /** * Don't override this. Calls <code>doRun()</code> * * @see java.lang.Runnable#run() */ public final void run() { if (registry == null) { throw new IllegalArgumentException("The ThreadRegistry is null. Ensure this is set before running this thread"); } passed = false; try { doRun(); } catch (Throwable t) { error = t; } registry.completed(this); hasRun = true; isRunning = false; //notify objects with blocked methods which are waiting //on this test to complete running synchronized( this) { notifyAll(); } } /** * Override this to run your custom test * * @throws Throwable */ public abstract void doRun() throws Throwable; /** * Set the registry this thread should notify when it has completed running * * @param registry */ public void setThreadRegistry(TestThreadManager registry) { this.registry = registry; } /** * Test if the test has run * * @return */ public boolean hasRun() { return hasRun; } /** * @param throwable */ public void setError(Throwable throwable) { error = throwable; } /** * @param string */ public void setErrorMsg(String string) { errorMsg = string; } /** * @param b */ public void setPassed(boolean b) { passed = b; } /** * @return */ public String getName() { return name; } /** * @param string */ public void setName(String string) { name = string; } private final void debug(String msg) { if (DEBUG) { System.out.println(this +":" + msg); } } } --- NEW FILE: SweeperPoolTest.java --- package org.apache.plexus.util; import java.util.Vector; import junit.framework.TestCase; /** * Created on 21/06/2003 * * @author <a href="mailto:[email protected]">Bert van Brakel</a> * @version $Revision: 1.1 $ */ public class SweeperPoolTest extends TestCase { /** The pool under test */ TestObjectPool pool; /** A bunch of object to pool */ Object o1; Object o2; Object o3; Object o4; Object o5; Object o6; /** * Constructor * * */ public SweeperPoolTest() { super(); } /** * Constructor * * @param arg0 */ public SweeperPoolTest(String arg0) { super(arg0); } /** * Test the pool limits it's size, and disposes unneeded objects correctly * */ public void testMaxSize() { int sweepInterval = 0; int initialCapacity = 5; int maxSize = 2; int minSize = 1; int triggerSize = 2; pool = new TestObjectPool( maxSize, minSize, initialCapacity, sweepInterval, triggerSize); Object tmp = pool.get(); assertNull("Expected object from pool to be null", tmp); pool.put(o1); assertEquals("Expected pool to contain 1 object", 1, pool.getSize()); tmp = pool.get(); assertSame( "Expected returned pool object to be the same as the one put in", tmp, o1); pool.put(o1); pool.put(o2); assertEquals("Expected pool to contain 2 objects", 2, pool.getSize()); pool.put(o3); assertEquals( "Expected pool to contain only a maximuim of 2 objects.", 2, pool.getSize()); assertEquals( "Expected 1 disposed pool object", 1, pool.testGetDisposedObjects().size()); tmp = pool.testGetDisposedObjects().iterator().next(); tmp = pool.get(); assertEquals( "Expected pool size to be 1 after removing one object", 1, pool.getSize()); Object tmp2 = pool.get(); assertEquals( "Expected pool size to be 0 after removing 2 objects", 0, pool.getSize()); assertNotSame("Expected returned objects to be differnet", tmp, tmp2); } public void testSweepAndTrim1() { //test trigger int sweepInterval = 1; int initialCapacity = 5; int maxSize = 5; int minSize = 1; int triggerSize = 2; pool = new TestObjectPool( maxSize, minSize, initialCapacity, sweepInterval, triggerSize); pool.put(o1); pool.put(o2); pool.put(o3); pool.put(o4); //give the seeper some time to run synchronized (this) { try { wait(2 * 1000); } catch (InterruptedException e) { fail( "Unexpected exception thrown. e=" + Tracer.traceToString(e)); } } assertEquals( "Expected pool to only contain 1 object", 1, pool.getSize()); assertEquals( "Expected 3 diposed objects", 3, pool.testGetDisposedObjects().size()); } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { o1 = new Object(); o2 = new Object(); o3 = new Object(); o4 = new Object(); o5 = new Object(); o6 = new Object(); super.setUp(); } /** * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { pool.dispose(); pool = null; super.tearDown(); } class TestObjectPool extends SweeperPool { private Vector disposedObjects = new Vector(); public TestObjectPool( int maxSize, int minSize, int intialCapacity, int sweepInterval, int triggerSize) { super(maxSize, minSize, intialCapacity, sweepInterval, triggerSize); } public void reset() { disposedObjects.clear(); } /** * @see nz.co.bonzo.beans.castor.pool.ObjectPool#objectDisposed(java.lang.Object) */ public void objectDisposed(Object obj) { disposedObjects.add(obj); } public Vector testGetDisposedObjects() { return disposedObjects; } } } --- NEW FILE: TestThreadManager.java --- package org.apache.plexus.util; import java.util.Collection; import java.util.Iterator; import java.util.Vector; import java.util.logging.Logger; /** * Manages a number of test threads, which notify this instance when they have * completed. Allows TestCases to easily start and manage multiple test threads. * * <p>Created on 9/06/2003</p> * * @author <a href="mailto:[email protected]">Bert van Brakel</a> * @version $Revision: 1.1 $ * */ public class TestThreadManager { //~ Instance fields ---------------------------------------------------------------------------- /** Test threads which have completed running */ private Collection runThreads = new Vector(); /** Test threads still needing to be run, or are currently running*/ private Collection toRunThreads = new Vector(); private Logger logger = null; /** Any test threads which failed */ private Vector failedThreads = new Vector(); /**The object to notify when all the test threads have complleted. Clients use this * to lock on (wait) while waiting for the tests to complete*/ private Object notify = null; //~ Constructors ------------------------------------------------------------------------------- public TestThreadManager(Object notify) { super(); this.notify = notify; } //~ Methods ------------------------------------------------------------------------------------ /** * @return */ public Collection getRunThreads() { return runThreads; } public void runTestThreads() { failedThreads.clear(); //use an array as the tests may run very quickly //and modify the toRunThreads vector and hence //cause a Concurrent ModificationException on an //iterator Object[] threads = toRunThreads.toArray(); for (int i = 0; i < threads.length; i++) { //System.out.println("Starting thread " + i +" ..." ); ((AbstractTestThread) threads[i]).start(); } } public Collection getFailedTests() { return failedThreads; } public boolean hasFailedThreads() { if( failedThreads.size() == 0) { return false; } else return true; } /** * Determine if any threads are still running! * * @return DOCUMENT ME! */ public boolean isStillRunningThreads() { return !toRunThreads.isEmpty(); } /** * @return */ public Collection getToRunThreads() { return toRunThreads; } /** * DOCUMENT ME! */ public void clear() { toRunThreads.clear(); runThreads.clear(); failedThreads.clear(); } /* (non-Javadoc) * @see java.util.Collection#remove(java.lang.Object) */ public void completed(AbstractTestThread thread) { toRunThreads.remove(thread); runThreads.add(thread); if (thread.hasFailed()) { failedThreads.add(thread); } //wakeup thread which is waiting for the threads to complete //execution if (toRunThreads.isEmpty()) { synchronized (notify) { notify.notify(); } } } /** * Overide this to add your own stuff. Called after * <code>registerThread(Object)</code> * * @param thread DOCUMENT ME! */ public void doRegisterThread(AbstractTestThread thread) { } public final void registerThread(AbstractTestThread thread) { thread.setThreadRegistry( this ); if( toRunThreads.contains( thread ) == false ) { toRunThreads.add(thread); doRegisterThread(thread); } } /** * Put all the runThreads back in the que to be run again and * clear the failedTest collection */ public void reset() { toRunThreads.clear(); Iterator iter = runThreads.iterator(); while (iter.hasNext()) { AbstractTestThread test = (AbstractTestThread) iter.next(); test.reset(); registerThread( test ); } runThreads.clear(); failedThreads.clear(); } } --- NEW FILE: ThreadSafeMapTest.java --- package org.apache.plexus.util; import java.util.Iterator; import junit.framework.TestCase; /** * Created on 21/06/2003 * * @author <a href="mailto:[email protected]">Bert van Brakel</a> * @version $Revision: 1.1 $ */ public class ThreadSafeMapTest extends TestCase { private ThreadSafeMap map; /** * Constructor * * */ public ThreadSafeMapTest() { super(); } /** * Constructor * * @param arg0 */ public ThreadSafeMapTest(String name) { super(name); } /** * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { // TODO Auto-generated method stub super.setUp(); } /** * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { // TODO Auto-generated method stub super.tearDown(); } public void test() { map = new ThreadSafeMap(); TestThreadManager registry = new TestThreadManager(this); //make the readers and writers. //mix them up incase VM gives startup times //dependent on thread creation order for (int i = 0; i < 20; i++) { //use the same key, but different values, so there will be contention Object key = Integer.toString(i); //a writer TestMapThread wTest = new TestMapThread(map, Integer.toString(i), new Object(), false); registry.registerThread(wTest); //a reader TestMapThread rTest = new TestMapThread(map, key, new Object(), true); registry.registerThread(rTest); } //now run the threads registry.runTestThreads(); //now wait for the threads to finish.. synchronized (this) { try { wait(); } catch (InterruptedException e) { //all threads have finished } } //now test for failures... if (registry.hasFailedThreads()) { StringBuffer out = new StringBuffer(); Iterator iter = registry.getFailedTests().iterator(); String nl = System.getProperty("line.separator"); while (iter.hasNext()) { TestMapThread test = (TestMapThread) iter.next(); out.append(nl); out.append(test.getErrorMsg()); out.append(" Exception=" + Tracer.traceToString(test.getError())); } fail("Failed test threads: " + out); } } } class TestMapThread extends AbstractTestThread { private ThreadSafeMap map; /** Indicates whether to read or write to the map */ private boolean reader = true; private Object key; private Object value; /** * Constructor * * */ public TestMapThread(ThreadSafeMap map, Object key, Object value, boolean reader) { super(); this.map = map; this.key = key; this.value = value; this.reader = reader; } /** * @see java.lang.Runnable#run() */ public void doRun() { try { if (reader) { value = map.get(key); } else { map.put(key, value); } setPassed(true); } catch (Throwable t) { if (reader) { setErrorMsg("Reader failed "); } else { setErrorMsg("Writer failed"); } setError(t); } } /** * @return */ public Object getKey() { return key; } /** * @return */ public boolean isReader() { return reader; } /** * @return */ public Object getValue() { return value; } }