package org.limewire.concurrent; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import junit.framework.Test; import org.limewire.service.ErrorCallback; import org.limewire.service.ErrorCallbackStub; import org.limewire.service.ErrorService; import org.limewire.util.BaseTestCase; public class ExecutorsHelperTest extends BaseTestCase { public ExecutorsHelperTest(String name) { super(name); } public static Test suite() { return buildTestSuite(ExecutorsHelperTest.class); } public void testProcessingQueueStarts() throws Exception { Runner r1 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("Sam"); service.execute(r1); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertEquals("Sam", r1.getName()); } public void testProcessingQueueReuseThread() throws Exception { Runner r1 = new Runner(); Runner r2 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("Sammy"); service.execute(r1); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertEquals("Sammy", r1.getName()); Thread.sleep(100); // let any potential renaming happen. assertEquals("Sammy", r1.getThread().getName()); service.execute(r2); assertTrue(r2.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertSame(r1.getThread(), r2.getThread()); assertEquals("Sammy", r2.getName()); } public void testProcessingQueueThreadLingersThenDies() throws Exception { Runner r1 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("SammyB"); service.execute(r1); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); Thread thread = r1.getThread(); assertEquals("SammyB", r1.getThread().getName()); assertTrue(thread.isAlive()); Thread.sleep(3500); assertTrue(thread.isAlive()); Thread.sleep(2000); assertFalse(thread.isAlive()); assertEquals("SammyB", r1.getThread().getName()); } public void testProcessingQueueGoesSequentially() throws Exception { CountDownLatch runLatch = new CountDownLatch(1); Runner r1 = new Runner(runLatch); Runner r2 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("SammyB"); service.execute(r1); service.execute(r2); assertTrue(r1.getStartedLatch().await(100, TimeUnit.MILLISECONDS)); assertFalse(r2.getStartedLatch().await(100, TimeUnit.MILLISECONDS)); assertFalse(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); runLatch.countDown(); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertTrue(r2.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertSame(r1.getThread(), r2.getThread()); assertEquals("SammyB", r1.getName()); assertEquals("SammyB", r2.getName()); } public void testProcessingQueueUsesDaemonThread() throws Exception { Runner r1 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("B"); service.execute(r1); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertTrue(r1.getThread().isDaemon()); } public void testProcessingQueueExceptionContinues() throws Exception { ErrorCallback oldCallback = ErrorService.getErrorCallback(); try { ErrorCallbackStub testCallback = new ErrorCallbackStub(); ErrorService.setErrorCallback(testCallback); assertEquals(0, testCallback.getExceptionCount()); CountDownLatch runLatch = new CountDownLatch(1); Runner r1 = new Runner(runLatch, true); Runner r2 = new Runner(); ExecutorService service = ExecutorsHelper.newProcessingQueue("Exceptionary"); service.execute(r1); service.execute(r2); assertTrue(r1.getStartedLatch().await(100, TimeUnit.MILLISECONDS)); assertFalse(r2.getStartedLatch().await(100, TimeUnit.MILLISECONDS)); assertFalse(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertEquals(0, testCallback.getExceptionCount()); runLatch.countDown(); assertTrue(r1.getRanLatch().await(100, TimeUnit.MILLISECONDS)); Thread.sleep(100); // let the exception propogate. assertEquals(1, testCallback.getExceptionCount()); assertTrue(r2.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertEquals(1, testCallback.getExceptionCount()); } finally { ErrorService.setErrorCallback(oldCallback); } } public void testNewFixedSizeThreadPoolStartsMoreThanOneThread() throws Exception { ErrorCallback oldCallback = ErrorService.getErrorCallback(); try { ErrorCallbackStub testCallback = new ErrorCallbackStub(); ErrorService.setErrorCallback(testCallback); ExecutorService service = ExecutorsHelper.newFixedSizeThreadPool(2, "fixedSizePool"); CountDownLatch runLatch = new CountDownLatch(1); Runner blockedRunner = new Runner(runLatch, false); Runner secondRunner = new Runner(); service.execute(blockedRunner); service.execute(secondRunner); Thread.yield(); assertTrue(blockedRunner.getStartedLatch().await(100, TimeUnit.MILLISECONDS)); assertFalse(blockedRunner.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertTrue("Second runner not run", secondRunner.getRanLatch().await(500, TimeUnit.MILLISECONDS)); runLatch.countDown(); assertTrue(blockedRunner.getRanLatch().await(100, TimeUnit.MILLISECONDS)); assertEquals(0, testCallback.getExceptionCount()); } finally { ErrorService.setErrorCallback(oldCallback); } } private static class Runner implements Runnable { private volatile Thread thread; private volatile String name; private final CountDownLatch startedLatch = new CountDownLatch(1); private final CountDownLatch ranLatch = new CountDownLatch(1); private final CountDownLatch runLatch; private final boolean throwException; public Runner() { this(null); } public Runner(CountDownLatch runLatch) { this(runLatch, false); } public Runner(boolean throwException) { this(null, throwException); } public Runner(CountDownLatch runLatch, boolean throwException) { this.throwException = throwException; this.runLatch = runLatch; } public void run() { thread = Thread.currentThread(); name = thread.getName(); startedLatch.countDown(); if(runLatch != null) { try { if(!runLatch.await(10, TimeUnit.SECONDS)) fail("never got notified!"); } catch(InterruptedException ignore) {} } ranLatch.countDown(); if(throwException) throw new RuntimeException("Abandon Hope."); } public CountDownLatch getRanLatch() { return ranLatch; } public CountDownLatch getStartedLatch() { return startedLatch; } public Thread getThread() { return thread; } public String getName() { return name; } } }