// Process test classes and resources.
long start = System.currentTimeMillis();
final List<String> testClassNames = processTestResources();
final EventBus aggregatedBus = new EventBus("aggregated");
final TestsSummaryEventListener summaryListener = new TestsSummaryEventListener();
aggregatedBus.register(summaryListener);
for (Object o : listeners) {
if (o instanceof ProjectComponent) {
((ProjectComponent) o).setProject(getProject());
}
if (o instanceof AggregatedEventListener) {
((AggregatedEventListener) o).setOuter(this);
}
aggregatedBus.register(o);
}
if (testClassNames.isEmpty()) {
aggregatedBus.post(new AggregatedQuitEvent());
} else {
start = System.currentTimeMillis();
final int slaveCount = determineSlaveCount(testClassNames.size());
final List<SlaveInfo> slaveInfos = Lists.newArrayList();
for (int slave = 0; slave < slaveCount; slave++) {
final SlaveInfo slaveInfo = new SlaveInfo(slave, slaveCount);
slaveInfos.add(slaveInfo);
}
// Order test class names identically for balancers.
Collections.sort(testClassNames);
// Prepare a pool of suites dynamically dispatched to slaves as they become idle.
final Deque<String> stealingQueue =
new ArrayDeque<String>(loadBalanceSuites(slaveInfos, testClassNames, balancers));
aggregatedBus.register(new Object() {
@Subscribe @SuppressWarnings("unused")
public void onSlaveIdle(SlaveIdle slave) {
if (stealingQueue.isEmpty()) {
slave.finished();
} else {
String suiteName = stealingQueue.pop();
slave.newSuite(suiteName);
}
}
});
// Create callables for the executor.
final List<Callable<Void>> slaves = Lists.newArrayList();
for (int slave = 0; slave < slaveCount; slave++) {
final SlaveInfo slaveInfo = slaveInfos.get(slave);
slaves.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
executeSlave(slaveInfo, aggregatedBus);
return null;
}
});
}
ExecutorService executor = Executors.newCachedThreadPool();
aggregatedBus.post(new AggregatedStartEvent(slaves.size(), testClassNames.size()));
try {
List<Future<Void>> all = executor.invokeAll(slaves);
executor.shutdown();
for (int i = 0; i < slaves.size(); i++) {
Future<Void> f = all.get(i);
try {
f.get();
} catch (ExecutionException e) {
slaveInfos.get(i).executionError = e.getCause();
}
}
} catch (InterruptedException e) {
log("Master interrupted? Weird.", Project.MSG_ERR);
}
aggregatedBus.post(new AggregatedQuitEvent());
for (SlaveInfo si : slaveInfos) {
if (si.start > 0 && si.end > 0) {
log(String.format(Locale.ENGLISH, "JVM J%d: %8.2f .. %8.2f = %8.2fs",
si.id,