package com.twitter.common.application.modules; import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.inject.Provider; import org.junit.Before; import org.junit.Test; import com.twitter.common.application.ShutdownRegistry; import com.twitter.common.application.modules.LifecycleModule.LaunchException; import com.twitter.common.application.modules.LifecycleModule.ServiceRunner; import com.twitter.common.application.modules.LocalServiceRegistry.LocalService; import com.twitter.common.base.Commands; import com.twitter.common.testing.EasyMockTest; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; /** * @author William Farner */ public class LocalServiceRegistryTest extends EasyMockTest { private static final Function<InetSocketAddress, Integer> INET_TO_PORT = new Function<InetSocketAddress, Integer>() { @Override public Integer apply(InetSocketAddress address) { return address.getPort(); } }; private static final String A = "a"; private static final String B = "b"; private ServiceRunner runner1; private ServiceRunner runner2; private Provider<Set<ServiceRunner>> serviceProvider; private ShutdownRegistry shutdownRegistry; private LocalServiceRegistry registry; @Before public void setUp() { runner1 = createMock(ServiceRunner.class); runner2 = createMock(ServiceRunner.class); serviceProvider = createMock(new Clazz<Provider<Set<ServiceRunner>>>() { }); shutdownRegistry = createMock(ShutdownRegistry.class); registry = new LocalServiceRegistry(serviceProvider, shutdownRegistry); } @Test public void testCreate() throws LaunchException { expect(serviceProvider.get()).andReturn(ImmutableSet.of(runner1, runner2)); expect(runner1.launch()).andReturn(primary(1)); expect(runner2.launch()).andReturn(auxiliary(A, 2)); shutdownRegistry.addAction(Commands.NOOP); expectLastCall().times(2); control.replay(); checkPorts(Optional.of(1), ImmutableMap.of(A, 2)); } private LocalService primary(int port) { return LocalService.primaryService(port, Commands.NOOP); } private LocalService auxiliary(String name, int port) { return LocalService.auxiliaryService(name, port, Commands.NOOP); } @Test public void testNoPrimary() throws LaunchException { expect(serviceProvider.get()).andReturn(ImmutableSet.of(runner1)); expect(runner1.launch()).andReturn(auxiliary(A, 2)); shutdownRegistry.addAction(Commands.NOOP); expectLastCall().times(1); control.replay(); assertFalse(registry.getPrimarySocket().isPresent()); } @Test(expected = IllegalArgumentException.class) public void testMultiplePrimaries() throws LaunchException { expect(serviceProvider.get()).andReturn(ImmutableSet.of(runner1, runner2)); expect(runner1.launch()).andReturn(primary(1)); expect(runner2.launch()).andReturn(primary(2)); shutdownRegistry.addAction(Commands.NOOP); expectLastCall().times(2); control.replay(); registry.getPrimarySocket(); } @Test(expected = IllegalArgumentException.class) public void testDuplicateName() throws LaunchException { expect(serviceProvider.get()).andReturn(ImmutableSet.of(runner1, runner2)); expect(runner1.launch()).andReturn(auxiliary(A, 1)); expect(runner2.launch()).andReturn(auxiliary(A, 2)); shutdownRegistry.addAction(Commands.NOOP); expectLastCall().times(2); control.replay(); registry.getPrimarySocket(); } @Test public void testAllowsPortReuse() throws LaunchException { expect(serviceProvider.get()).andReturn(ImmutableSet.of(runner1, runner2)); expect(runner1.launch()).andReturn(auxiliary(A, 2)); expect(runner2.launch()).andReturn(auxiliary(B, 2)); shutdownRegistry.addAction(Commands.NOOP); expectLastCall().times(2); control.replay(); checkPorts(Optional.<Integer>absent(), ImmutableMap.of(A, 2, B, 2)); } private void checkPorts(Optional<Integer> primary, Map<String, Integer> expected) { Optional<InetSocketAddress> registeredSocket = registry.getPrimarySocket(); Optional<Integer> registeredPort = registeredSocket.isPresent() ? Optional.of(registeredSocket.get().getPort()) : Optional.<Integer>absent(); assertEquals(primary, registeredPort); assertEquals(expected, Maps.transformValues(registry.getAuxiliarySockets(), INET_TO_PORT)); } }