package com.orientechnologies.orient.test; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.util.ArrayList; import java.util.Collection; 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; /** * @author Artem Orobets (enisher-at-gmail.com) * @param <T> see {@link TestFactory} */ public class ConcurrentTestHelper<T> { private final ExecutorService executor; private final List<Future<T>> futures; public static <T> Collection<T> test(int threadCount, TestFactory<T> factory) { final List<Callable<T>> callables = prepareWorkers(threadCount, factory); return go(callables); } protected static <T> Collection<T> go(List<Callable<T>> workers) { final ConcurrentTestHelper<T> helper = new ConcurrentTestHelper<T>(workers.size()); helper.submit(workers); return helper.assertSuccess(); } protected static <T> List<Callable<T>> prepareWorkers(int threadCount, TestFactory<T> factory) { final List<Callable<T>> callables = new ArrayList<Callable<T>>(threadCount); for (int i = 0; i < threadCount; i++) { callables.add(factory.createWorker()); } return callables; } public static <T> TestBuilder<T> build() { return new TestBuilder<T>(); } private Collection<T> assertSuccess() { try { executor.shutdown(); assertTrue(executor.awaitTermination(30, TimeUnit.MINUTES), "Test threads hanged"); List<T> results = new ArrayList<T>(futures.size()); List<Exception> exceptions = new ArrayList<Exception>(); for (Future<T> future : futures) { try { results.add(future.get()); } catch (ExecutionException e) { exceptions.add(e); } } if (exceptions.isEmpty()) { return results; } else { throw new CompositeException(exceptions); } } catch (InterruptedException e) { fail("interrupted", e); throw new RuntimeException("unreached exception", e); } } private void submit(List<Callable<T>> callables) { for (Callable<T> callable : callables) { futures.add(executor.submit(callable)); } } private ConcurrentTestHelper(int threadCount) { this.futures = new ArrayList<Future<T>>(threadCount); this.executor = Executors.newFixedThreadPool(threadCount); } }