package com.meltmedia.dropwizard.etcd.junit;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.joda.time.DateTime;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.core.type.TypeReference;
import com.meltmedia.dropwizard.etcd.cluster.ClusterNode;
import com.meltmedia.dropwizard.etcd.cluster.ClusterService;
import com.meltmedia.dropwizard.etcd.json.EtcdJson;
import com.meltmedia.dropwizard.etcd.json.EtcdJson.MappedEtcdDirectory;
public class ClusterServiceRule implements TestRule {
public static class Builder {
IntFunction<MetricRegistry> registrySupplier;
ClusterNode clusterNode;
Supplier<EtcdJson> etcdJsonSupplier;
String directory;
int serviceCount;
public Builder withMetricRegistry(IntFunction<MetricRegistry> registrySupplier) {
this.registrySupplier = registrySupplier;
return this;
}
public Builder withServiceCount( int serviceCount ) {
this.serviceCount = serviceCount;
return this;
}
public Builder withEtcdJsonSupplier( Supplier<EtcdJson> etcdJsonSupplier) {
this.etcdJsonSupplier = etcdJsonSupplier;
return this;
}
public Builder withDirectory( String directory ) {
this.directory = directory;
return this;
}
public ClusterServiceRule build() {
if( registrySupplier == null ) registrySupplier = index->new MetricRegistry();
if( directory == null ) directory = "/nodes";
return new ClusterServiceRule(directory, serviceCount, etcdJsonSupplier, registrySupplier);
}
}
public static Builder builder() {
return new Builder();
}
IntFunction<MetricRegistry> registrySupplier;
IntFunction<ClusterNode> clusterNodeFactory = index->new ClusterNode().withId("node"+index).withStartedAt(new DateTime());
Supplier<EtcdJson> etcdJsonSupplier;
String directory;
int serviceCount;
List<ClusterService> services;
public ClusterServiceRule( String directory, int serviceCount, Supplier<EtcdJson> etcdJsonSupplier, IntFunction<MetricRegistry> registrySupplier ) {
this.serviceCount = serviceCount;
this.etcdJsonSupplier = etcdJsonSupplier;
this.registrySupplier = registrySupplier;
this.directory = directory;
}
public List<ClusterService> getServices() {
return Collections.unmodifiableList(services);
}
@Override
public Statement apply( Statement base, Description description ) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
EtcdJson etcdJson = etcdJsonSupplier.get();
services = IntStream.range(0, serviceCount).mapToObj(index->{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
MappedEtcdDirectory<ClusterNode> nodeDir = etcdJson.newDirectory(directory, new TypeReference<ClusterNode>() {});
return ClusterService.builder()
.withEtcdFactory(etcdJson)
.withExecutor(executor)
.withNodesDirectory(nodeDir)
.withThisNode(clusterNodeFactory.apply(index))
.withMetricRegistry(registrySupplier.apply(index))
.build();
}).collect(Collectors.toList());
services.forEach(ClusterService::start);
try {
base.evaluate();
} finally {
services.forEach(ClusterService::stop);
}
}
};
}
}