package com.bazaarvoice.ostrich.pool;
import com.bazaarvoice.ostrich.HostDiscovery;
import com.bazaarvoice.ostrich.HostDiscoverySource;
import com.bazaarvoice.ostrich.LoadBalanceAlgorithm;
import com.bazaarvoice.ostrich.RetryPolicy;
import com.bazaarvoice.ostrich.ServiceFactory;
import com.bazaarvoice.ostrich.loadbalance.RandomAlgorithm;
import com.bazaarvoice.ostrich.partition.IdentityPartitionFilter;
import com.bazaarvoice.ostrich.partition.PartitionFilter;
import com.codahale.metrics.MetricRegistry;
import org.junit.Before;
import org.junit.Test;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
public class ServicePoolBuilderTest {
private ServiceFactory<Service> _serviceFactory;
private ServiceCachingPolicy _cachingPolicy;
private HostDiscovery _hostDiscovery;
private ScheduledExecutorService _healthCheckExecutor;
private ExecutorService _asyncExecutor;
private PartitionFilter _partitionFilter;
private MetricRegistry _metricRegistry;
@SuppressWarnings("unchecked")
@Before
public void setup() {
_serviceFactory = (ServiceFactory<Service>) mock(ServiceFactory.class);
when(_serviceFactory.getServiceName()).thenReturn(Service.class.getSimpleName());
_cachingPolicy = mock(ServiceCachingPolicy.class);
when(_cachingPolicy.getCacheExhaustionAction()).thenReturn(ServiceCachingPolicy.ExhaustionAction.GROW);
_hostDiscovery = mock(HostDiscovery.class);
_healthCheckExecutor = mock(ScheduledExecutorService.class);
_asyncExecutor = mock(ExecutorService.class);
_partitionFilter = mock(PartitionFilter.class);
_metricRegistry = new MetricRegistry(); // A mock registry doesn't work because we have so many interactions
}
@Test(expected = NullPointerException.class)
public void testNullHostDiscovery() {
ServicePoolBuilder.create(Service.class).withHostDiscovery(null);
}
@Test(expected = NullPointerException.class)
public void testNullServiceFactory() {
ServicePoolBuilder.create(Service.class).withServiceFactory(null);
}
@Test(expected = NullPointerException.class)
public void testNullCachingPolicy() {
ServicePoolBuilder.create(Service.class).withCachingPolicy(null);
}
@Test(expected = NullPointerException.class)
public void testNullHealthCheckExecutor() {
ServicePoolBuilder.create(Service.class).withHealthCheckExecutor(null);
}
@Test(expected = NullPointerException.class)
public void testNullAsyncExecutor() {
ServicePoolBuilder.create(Service.class).withAsyncExecutor(null);
}
@Test(expected = NullPointerException.class)
public void testNullMetricRegistry() {
ServicePoolBuilder.create(Service.class).withMetricRegistry(null);
}
@Test(expected = IllegalStateException.class)
public void testBuildWithNoHostDiscoveryAndNoZooKeeperConnection() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test(expected = NullPointerException.class)
public void testBuildWithNoServiceFactory() {
ServicePoolBuilder.create(Service.class)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuildWithNullServiceName() {
when(_serviceFactory.getServiceName()).thenReturn(null);
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testBuildWithEmptyServiceName() {
when(_serviceFactory.getServiceName()).thenReturn("");
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test
public void testBuildWithNullLoadBalanceAlgorithm() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test
public void testHostDiscoveryFromSourceCloses() throws Exception {
HostDiscoverySource closingHostDiscoverySource = mock(HostDiscoverySource.class);
HostDiscovery closedHostDiscovery = mock(HostDiscovery.class);
HostDiscoverySource nonClosingHostDiscoverySource = mock(HostDiscoverySource.class);
HostDiscovery unclosedHostDiscovery = mock(HostDiscovery.class);
when(closingHostDiscoverySource.forService(anyString())).thenReturn(closedHostDiscovery);
when(nonClosingHostDiscoverySource.forService(anyString())).thenReturn(unclosedHostDiscovery);
ServicePool<Service> servicePool = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscoverySource(closingHostDiscoverySource)
.withHostDiscoverySource(nonClosingHostDiscoverySource)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
servicePool.close();
verify(closedHostDiscovery).close();
verify(unclosedHostDiscovery, never()).close();
}
@Test
public void testHostDiscoveryDoesNotClose() throws Exception {
HostDiscovery unclosedHostDiscovery = mock(HostDiscovery.class);
ServicePool<Service> servicePool = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(unclosedHostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
servicePool.close();
verify(unclosedHostDiscovery, never()).close();
}
@Test
public void testHostDiscoverySourceOverride() {
HostDiscovery overrideDiscovery = mock(HostDiscovery.class);
HostDiscoverySource source = mock(HostDiscoverySource.class);
when(source.forService(anyString())).thenReturn(overrideDiscovery);
com.bazaarvoice.ostrich.pool.ServicePool<Service> pool = ServicePoolBuilder.create(Service.class)
.withHostDiscoverySource(source)
.withHostDiscovery(_hostDiscovery)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.buildInternal();
assertSame(overrideDiscovery, pool.getHostDiscovery());
}
@Test
public void testHostDiscoverySourceFallThrough() {
HostDiscoverySource source = mock(HostDiscoverySource.class);
when(source.forService(anyString())).thenReturn(null);
com.bazaarvoice.ostrich.pool.ServicePool<Service> pool = ServicePoolBuilder.create(Service.class)
.withHostDiscoverySource(source)
.withHostDiscovery(_hostDiscovery)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.buildInternal();
assertSame(_hostDiscovery, pool.getHostDiscovery());
}
@Test
public void testBuildWithNoHealthCheckExecutor() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test
public void testBuildWithNoAsyncExecutor() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test
public void testBuildWithNoCachingPolicy() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
}
@Test
public void testBuildWithNoPartitionFilter() throws IOException {
ServicePool<Service> service = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withMetricRegistry(_metricRegistry)
.build();
assertTrue(service.getPartitionFilter() instanceof IdentityPartitionFilter);
}
@Test
public void testBuildWithPartitionFilter() throws IOException {
ServicePool<Service> service = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
assertSame(_partitionFilter, service.getPartitionFilter());
}
@Test
public void testBuildWithNoLoadBalanceAlgorithm() throws IOException {
ServicePool<Service> service = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
assertTrue(service.getLoadBalanceAlgorithm() instanceof RandomAlgorithm);
}
@Test
public void testBuildWithLoadBalanceAlgorithm() throws IOException {
LoadBalanceAlgorithm loadBalanceAlgorithm = mock(LoadBalanceAlgorithm.class);
ServicePool<Service> service = (ServicePool<Service>) ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withLoadBalanceAlgorithm(loadBalanceAlgorithm)
.withHostDiscovery(_hostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
assertEquals(loadBalanceAlgorithm, service.getLoadBalanceAlgorithm());
}
@Test
public void testBuildWithAsyncExecutor() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withAsyncExecutor(_asyncExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.build();
verifyZeroInteractions(_asyncExecutor);
}
@Test
public void testBuildAsyncWithNoAsyncExecutor() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.buildAsync();
}
@Test
public void testBuildAsync() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withHealthCheckExecutor(_healthCheckExecutor)
.withAsyncExecutor(_asyncExecutor)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.buildAsync();
}
@Test
public void testBuildProxy() throws IOException {
Service service = ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionFilter(_partitionFilter)
.withMetricRegistry(_metricRegistry)
.buildProxy(mock(RetryPolicy.class));
assertTrue(service instanceof Closeable);
}
@Test
public void testBuildProxyWithAnnotations() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionContextAnnotations()
.withMetricRegistry(_metricRegistry)
.buildProxy(mock(RetryPolicy.class));
}
@Test(expected = NullPointerException.class)
public void testBuildProxyWithAnnotationsFromNull() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionContextAnnotationsFrom(null)
.withMetricRegistry(_metricRegistry)
.buildProxy(mock(RetryPolicy.class));
}
@Test
public void testBuildProxyWithAnnotationsFrom() {
ServicePoolBuilder.create(Service.class)
.withServiceFactory(_serviceFactory)
.withCachingPolicy(_cachingPolicy)
.withHostDiscovery(_hostDiscovery)
.withPartitionContextAnnotationsFrom(ServiceChild.class)
.withMetricRegistry(_metricRegistry)
.buildProxy(mock(RetryPolicy.class));
}
@Test
public void testServiceFactoryConfigure() {
ServicePoolBuilder<Service> builder = ServicePoolBuilder.create(Service.class);
builder.withServiceFactory(_serviceFactory);
verify(_serviceFactory).configure(builder);
}
// A dummy interface for testing...
private static interface Service {}
private static class ServiceChild implements Service{}
}