import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.Test; public class MultiThreadedTestCase { /** * Generic method for doing multithreaded testing. * * @param message - Used when printing out test failures * @param tasks - The list of tasks to run in parallel * @param maxTimeoutSeconds - The maximum time to complete the test * @return the list of results from executing the tests * @throws InterruptedException */ private static List doTest(String message, final List> tasks, final int maxTimeoutSeconds) throws InterruptedException { // Create service to run the tests and run them; blocks for at most the timeout final int threadCount = tasks.size(); ExecutorService executorService = Executors.newFixedThreadPool(threadCount); final List> futures = executorService.invokeAll(tasks,maxTimeoutSeconds,TimeUnit.SECONDS); // Create a list of the results, and possible exceptions final List resultList = new ArrayList(futures.size()); final List exceptions = new ArrayList(); // Collect the results in a separate thread, so as to timeout if necessary for (Future future : futures) { // Throws an exception if an exception was thrown by the task. try { resultList.add(future.get()); } catch (Throwable t) { exceptions.add(t); } } // Got them all, or the timeout expired executorService.shutdownNow(); // See if we failed with an exception or some other problem Assert.assertTrue(message + " failed with exception(s) " + exceptions, exceptions.isEmpty()); Assert.assertTrue(message + " failed with not all threads returning", threadCount == futures.size()); // Return the results return resultList; } /** * Helper method to run multiple threads on the UniqueId object * * @param threadCount - how many threads to run with * @throws InterruptedException * @throws ExecutionException */ private void test(final int threadCount) throws InterruptedException, ExecutionException { final BrokenUniqueIdGenerator domainObject = new BrokenUniqueIdGenerator(); Callable task = new Callable() { @Override public Long call() throws InterruptedException { return domainObject.nextId(); } }; List> tasks = Collections.nCopies(threadCount, task); List resultList = doTest("test", tasks, 2); List expectedList = new ArrayList(threadCount); for (long i = 1; i <= threadCount; i++) { expectedList.add(i); } Collections.sort(resultList); Assert.assertEquals(expectedList, resultList); } @Test public void test01() throws InterruptedException, ExecutionException { test(1); } @Test public void test02() throws InterruptedException, ExecutionException { test(2); } @Test public void test04() throws InterruptedException, ExecutionException { test(4); } @Test public void test08() throws InterruptedException, ExecutionException { test(8); } @Test public void test16() throws InterruptedException, ExecutionException { test(16); } @Test public void test32() throws InterruptedException, ExecutionException { test(32); } }