package com.netflix.eureka.cluster; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.discovery.DefaultEurekaClientConfig; import com.netflix.discovery.shared.transport.ClusterSampleData; import com.netflix.eureka.EurekaServerConfig; import com.netflix.eureka.registry.PeerAwareInstanceRegistry; import com.netflix.eureka.resources.DefaultServerCodecs; import org.junit.Test; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * @author Tomasz Bak */ public class PeerEurekaNodesTest { private static final String PEER_EUREKA_URL_A = "http://a.eureka.test"; private static final String PEER_EUREKA_URL_B = "http://b.eureka.test"; private static final String PEER_EUREKA_URL_C = "http://c.eureka.test"; private final PeerAwareInstanceRegistry registry = mock(PeerAwareInstanceRegistry.class); private final TestablePeerEurekaNodes peerEurekaNodes = new TestablePeerEurekaNodes(registry, ClusterSampleData.newEurekaServerConfig()); @Test public void testInitialStartupShutdown() throws Exception { peerEurekaNodes.withPeerUrls(PEER_EUREKA_URL_A); // Start peerEurekaNodes.start(); PeerEurekaNode peerNode = getPeerNode(PEER_EUREKA_URL_A); assertThat(peerNode, is(notNullValue())); // Shutdown peerEurekaNodes.shutdown(); verify(peerNode, times(1)).shutDown(); } @Test public void testReloadWithNoPeerChange() throws Exception { // Start peerEurekaNodes.withPeerUrls(PEER_EUREKA_URL_A); peerEurekaNodes.start(); PeerEurekaNode peerNode = getPeerNode(PEER_EUREKA_URL_A); assertThat(peerEurekaNodes.awaitNextReload(60, TimeUnit.SECONDS), is(true)); assertThat(getPeerNode(PEER_EUREKA_URL_A), is(equalTo(peerNode))); } @Test public void testReloadWithPeerUpdates() throws Exception { // Start peerEurekaNodes.withPeerUrls(PEER_EUREKA_URL_A); peerEurekaNodes.start(); PeerEurekaNode peerNodeA = getPeerNode(PEER_EUREKA_URL_A); // Add one more peer peerEurekaNodes.withPeerUrls(PEER_EUREKA_URL_A, PEER_EUREKA_URL_B); assertThat(peerEurekaNodes.awaitNextReload(60, TimeUnit.SECONDS), is(true)); assertThat(getPeerNode(PEER_EUREKA_URL_A), is(notNullValue())); assertThat(getPeerNode(PEER_EUREKA_URL_B), is(notNullValue())); // Remove first peer, and add yet another one peerEurekaNodes.withPeerUrls(PEER_EUREKA_URL_B, PEER_EUREKA_URL_C); assertThat(peerEurekaNodes.awaitNextReload(60, TimeUnit.SECONDS), is(true)); assertThat(getPeerNode(PEER_EUREKA_URL_A), is(nullValue())); assertThat(getPeerNode(PEER_EUREKA_URL_B), is(notNullValue())); assertThat(getPeerNode(PEER_EUREKA_URL_C), is(notNullValue())); verify(peerNodeA, times(1)).shutDown(); } private PeerEurekaNode getPeerNode(String peerEurekaUrl) { for (PeerEurekaNode node : peerEurekaNodes.getPeerEurekaNodes()) { if (node.getServiceUrl().equals(peerEurekaUrl)) { return node; } } return null; } static class TestablePeerEurekaNodes extends PeerEurekaNodes { private AtomicReference<List<String>> peerUrlsRef = new AtomicReference<>(Collections.<String>emptyList()); private final ConcurrentHashMap<String, PeerEurekaNode> peerEurekaNodeByUrl = new ConcurrentHashMap<>(); private final AtomicInteger reloadCounter = new AtomicInteger(); TestablePeerEurekaNodes(PeerAwareInstanceRegistry registry, EurekaServerConfig serverConfig) { super(registry, serverConfig, new DefaultEurekaClientConfig(), new DefaultServerCodecs(serverConfig), mock(ApplicationInfoManager.class) ); } void withPeerUrls(String... peerUrls) { this.peerUrlsRef.set(Arrays.asList(peerUrls)); } boolean awaitNextReload(long timeout, TimeUnit timeUnit) throws InterruptedException { int lastReloadCounter = reloadCounter.get(); long endTime = System.currentTimeMillis() + timeUnit.toMillis(timeout); while (endTime > System.currentTimeMillis() && lastReloadCounter == reloadCounter.get()) { Thread.sleep(10); } return lastReloadCounter != reloadCounter.get(); } @Override protected void updatePeerEurekaNodes(List<String> newPeerUrls) { super.updatePeerEurekaNodes(newPeerUrls); reloadCounter.incrementAndGet(); } @Override protected List<String> resolvePeerUrls() { return peerUrlsRef.get(); } @Override protected PeerEurekaNode createPeerEurekaNode(String peerEurekaNodeUrl) { if (peerEurekaNodeByUrl.containsKey(peerEurekaNodeUrl)) { throw new IllegalStateException("PeerEurekaNode for URL " + peerEurekaNodeUrl + " is already created"); } PeerEurekaNode peerEurekaNode = mock(PeerEurekaNode.class); when(peerEurekaNode.getServiceUrl()).thenReturn(peerEurekaNodeUrl); return peerEurekaNode; } } }