package com.limegroup.gnutella.util; import java.util.Random; import junit.framework.Test; public class ThreadWorkGroupTest extends BaseTestCase { private int _total = 0; private int _numTasks = 0; private final int NUM_WORKERS=10; public ThreadWorkGroupTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ThreadWorkGroupTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public synchronized void increment(int inc) { _total += inc; } public void testWorkGroupWithCleaner() throws Exception { Counter[] workers = new Counter[NUM_WORKERS]; for (int i = 0; i < workers.length; i++) workers[i] = new Counter(); ThreadWorkGroup workGroup = new ThreadWorkGroup(workers, new Cleaner()); assertTrue(workGroup.isActive()); Random rand = new Random(); int localTotal = 0; // make sure all workers are woken up, and then set them to just process // --------------------------------------------------------------------- _numTasks += 200; for (int i = 0; i < _numTasks; i++) { int currInt = rand.nextInt(200); workGroup.addTask(new Object[] { new Integer(currInt) }); localTotal += currInt; } Thread.sleep(500); // give each thread time to wake up... for (int i = 0; i < workers.length; i++) assertTrue(workers[i].wakeUp()); Thread.sleep(4*1000); // let the workers work.... assertEquals(_total, localTotal); assertTrue(workGroup.isActive()); // make sure NO workers are working for (int i = 0; i < workers.length; i++) assertTrue(!workers[i].wakeUp()); // --------------------------------------------------------------------- // put in a bad task and make sure it doesn't get executed, though // this is only half testing ThreadWorkGroup // --------------------------------------------------------------------- _numTasks++; workGroup.addTask(new Object[] { new Long(0) }); Thread.sleep(100); assertEquals(_total, localTotal); assertTrue(workGroup.isActive()); // make sure NO workers are working for (int i = 0; i < workers.length; i++) assertTrue(!workers[i].wakeUp()); // --------------------------------------------------------------------- // now make sure that enough workers are woken up as necessary // --------------------------------------------------------------------- for (int i = 0; i < workers.length; i++) workers[i].makeWait(); int halfOfWorkers = NUM_WORKERS/2; _numTasks += halfOfWorkers; for (int i = 0; i < halfOfWorkers; i++) { int currInt = rand.nextInt(200); workGroup.addTask(new Object[] { new Integer(currInt) }); localTotal += currInt; } { // give the scheduler some time and then.... Thread.sleep(1*1000); // make sure some workers are woken up, and then set them to just // process int numAlive = 0; for (int i = 0; i < workers.length; i++) { if (workers[i].wakeUp()) numAlive++; } assertEquals(halfOfWorkers, numAlive); } Thread.sleep(500); // let the workers work.... assertEquals(_total, localTotal); assertTrue(workGroup.isActive()); // make sure NO workers are working for (int i = 0; i < workers.length; i++) assertTrue(!workers[i].wakeUp()); // --------------------------------------------------------------------- // make sure after stop no work is done.... // --------------------------------------------------------------------- workGroup.stop(0); assertTrue(!workGroup.isActive()); // anybody woken up should wait so i can tell.... for (int i = 0; i < workers.length; i++) workers[i].makeWait(); workGroup.addTask(new Object[] { new Integer(rand.nextInt(200)) }); // give the scheduler some time and then.... Thread.sleep(300); // make sure NO workers are woken up for (int i = 0; i < workers.length; i++) assertTrue(!workers[i].wakeUp()); assertEquals(_total, localTotal); // --------------------------------------------------------------------- } private class Cleaner implements ThreadWorkGroup.CleanUpInterface { private int _calls = 0; public void cleanUp(Object[] input) { assertTrue(++_calls <= _numTasks); } } private class Counter implements ThreadWorkGroup.WorkerInterface { private Integer _int; private boolean shouldWait = true; private boolean waiting = false; public boolean checkInput(Object[] input) { if ((input.length == 1) && (input[0] instanceof Integer)) { _int = (Integer) input[0]; return true; } return false; } public void run() { if (shouldWait) { synchronized (_int) { waiting = true; try { _int.wait(); } catch (InterruptedException ie) {} waiting = false; } } increment(_int.intValue()); } // use this to make sure a guy is running and then let him proceed // return whether this guy was waiting.... public boolean wakeUp() { if (_int == null) return waiting; synchronized (_int) { shouldWait = false; _int.notify(); return waiting; } } // if you want a guy to wait after having wakeUp()'ed public void makeWait() { if (_int == null) shouldWait = true; else { synchronized (_int) { shouldWait = true; } } } } }