de.cronn.testutils.ConcurrentTest Maven / Gradle / Ivy
The newest version!
package de.cronn.testutils;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public class ConcurrentTest {
private static final int TIMEOUT_MILLIS = 30_000;
private int concurrencyLevel = 10;
private final IndexedCallable task;
private String threadNamePrefix = ConcurrentTest.class.getSimpleName();
public ConcurrentTest(IndexedCallable task) {
this.task = task;
}
public static ConcurrentTest create(IndexedCallable task) {
return new ConcurrentTest<>(task);
}
public ConcurrentTest withConcurrencyLevel(int concurrencyLevel) {
this.concurrencyLevel = concurrencyLevel;
return this;
}
public ConcurrentTest withThreadNamePrefix(String threadNamePrefix) {
this.threadNamePrefix = threadNamePrefix;
return this;
}
public ConcurrentTest withThreadNamePrefixFromClass(Class> clazz) {
return withThreadNamePrefix(clazz.getSimpleName());
}
public void runAndAssertEachResult(Consumer assertion) throws InterruptedException, ExecutionException {
ThreadFactory threadFactory = new NamedThreadFactory(threadNamePrefix);
ExecutorService executorService = Executors.newFixedThreadPool(concurrencyLevel, threadFactory);
try {
CompletionService completionService = new ExecutorCompletionService<>(executorService);
for (int i = 0; i < concurrencyLevel; i++) {
completionService.submit(task.toCallable(i));
}
for (int i = 0; i < concurrencyLevel; i++) {
T result = completionService.take().get();
assertion.accept(result);
}
} finally {
ExecutorServiceUtils.shutdownOrThrow(executorService, threadNamePrefix, TIMEOUT_MILLIS);
}
}
private static class NamedThreadFactory implements ThreadFactory {
private final String prefix;
private final AtomicInteger threadCount = new AtomicInteger();
public NamedThreadFactory(String prefix) {
this.prefix = prefix;
}
@Override
public Thread newThread(Runnable r) {
return new Thread(r, prefix + threadCount.incrementAndGet());
}
}
@FunctionalInterface
public interface IndexedCallable {
T call(int index) throws Exception;
default Callable toCallable(int index) {
return () -> call(index);
}
}
}