package com.netflix.eureka.registry;
import java.util.List;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Applications;
import com.netflix.eureka.AbstractTester;
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
/**
* @author Nitesh Kant
*/
public class InstanceRegistryTest extends AbstractTester {
@Test
public void testSoftDepRemoteUp() throws Exception {
Assert.assertTrue("Registry access disallowed when remote region is UP.", registry.shouldAllowAccess(false));
Assert.assertTrue("Registry access disallowed when remote region is UP.", registry.shouldAllowAccess(true));
}
@Test
public void testGetAppsFromAllRemoteRegions() throws Exception {
Applications apps = registry.getApplicationsFromAllRemoteRegions();
List<Application> registeredApplications = apps.getRegisteredApplications();
Assert.assertEquals("Apps size from remote regions do not match", 1, registeredApplications.size());
Application app = registeredApplications.iterator().next();
Assert.assertEquals("Added app did not return from remote registry", REMOTE_REGION_APP_NAME, app.getName());
Assert.assertEquals("Returned app did not have the instance", 1, app.getInstances().size());
}
@Test
public void testGetAppsDeltaFromAllRemoteRegions() throws Exception {
registerInstanceLocally(createLocalInstance(LOCAL_REGION_INSTANCE_2_HOSTNAME)); /// local delta
waitForDeltaToBeRetrieved();
Applications appDelta = registry.getApplicationDeltasFromMultipleRegions(null);
List<Application> registeredApplications = appDelta.getRegisteredApplications();
Assert.assertEquals("Apps size from remote regions do not match", 2, registeredApplications.size());
Application localApplication = null;
Application remApplication = null;
for (Application registeredApplication : registeredApplications) {
if (registeredApplication.getName().equalsIgnoreCase(LOCAL_REGION_APP_NAME)) {
localApplication = registeredApplication;
}
if (registeredApplication.getName().equalsIgnoreCase(REMOTE_REGION_APP_NAME)) {
remApplication = registeredApplication;
}
}
Assert.assertNotNull("Did not find local registry app in delta.", localApplication);
Assert.assertEquals("Local registry app instance count in delta not as expected.", 1,
localApplication.getInstances().size());
Assert.assertNotNull("Did not find remote registry app in delta", remApplication);
Assert.assertEquals("Remote registry app instance count in delta not as expected.", 1,
remApplication.getInstances().size());
}
@Test
public void testAppsHashCodeAfterRefresh() throws InterruptedException {
Assert.assertEquals("UP_1_", registry.getApplicationsFromAllRemoteRegions().getAppsHashCode());
registerInstanceLocally(createLocalInstance(LOCAL_REGION_INSTANCE_2_HOSTNAME));
waitForDeltaToBeRetrieved();
Assert.assertEquals("UP_2_", registry.getApplicationsFromAllRemoteRegions().getAppsHashCode());
}
private void waitForDeltaToBeRetrieved() throws InterruptedException {
int count = 0;
System.out.println("Sleeping up to 35 seconds to let the remote registry fetch delta.");
while (count++ < 35 && !mockRemoteEurekaServer.isSentDelta()) {
Thread.sleep(1000);
}
if (!mockRemoteEurekaServer.isSentDelta()) {
System.out.println("Waited for 35 seconds but remote server did not send delta");
}
// Wait 2 seconds more to be sure the delta was processed
Thread.sleep(2000);
}
@Test
public void testGetAppsFromLocalRegionOnly() throws Exception {
registerInstanceLocally(createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME));
Applications apps = registry.getApplicationsFromLocalRegionOnly();
List<Application> registeredApplications = apps.getRegisteredApplications();
Assert.assertEquals("Apps size from local region do not match", 1, registeredApplications.size());
Application app = registeredApplications.iterator().next();
Assert.assertEquals("Added app did not return from local registry", LOCAL_REGION_APP_NAME, app.getName());
Assert.assertEquals("Returned app did not have the instance", 1, app.getInstances().size());
}
@Test
public void testGetAppsFromBothRegions() throws Exception {
registerInstanceLocally(createRemoteInstance(LOCAL_REGION_INSTANCE_2_HOSTNAME));
registerInstanceLocally(createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME));
Applications apps = registry.getApplicationsFromAllRemoteRegions();
List<Application> registeredApplications = apps.getRegisteredApplications();
Assert.assertEquals("Apps size from both regions do not match", 2, registeredApplications.size());
Application locaApplication = null;
Application remApplication = null;
for (Application registeredApplication : registeredApplications) {
if (registeredApplication.getName().equalsIgnoreCase(LOCAL_REGION_APP_NAME)) {
locaApplication = registeredApplication;
}
if (registeredApplication.getName().equalsIgnoreCase(REMOTE_REGION_APP_NAME)) {
remApplication = registeredApplication;
}
}
Assert.assertNotNull("Did not find local registry app", locaApplication);
Assert.assertEquals("Local registry app instance count not as expected.", 1,
locaApplication.getInstances().size());
Assert.assertNotNull("Did not find remote registry app", remApplication);
Assert.assertEquals("Remote registry app instance count not as expected.", 2,
remApplication.getInstances().size());
}
@Test
public void testStatusOverrideSetAndRemoval() throws Exception {
// Regular registration first
InstanceInfo myInstance = createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registerInstanceLocally(myInstance);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
// Override status
boolean statusResult = registry.statusUpdate(LOCAL_REGION_APP_NAME, myInstance.getId(), InstanceStatus.OUT_OF_SERVICE, "0", false);
assertThat("Couldn't override instance status", statusResult, is(true));
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
// Register again with status UP (this is what health check is doing)
registry.register(createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME), 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
// Now remove override
statusResult = registry.deleteStatusOverride(LOCAL_REGION_APP_NAME, myInstance.getId(), InstanceStatus.DOWN, "0", false);
assertThat("Couldn't remove status override", statusResult, is(true));
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.DOWN);
// Register again with status UP (this is what health check is doing)
registry.register(createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME), 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
}
@Test
public void testStatusOverrideStartingStatus() throws Exception {
// Regular registration first
InstanceInfo myInstance = createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registerInstanceLocally(myInstance);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
// Override status
boolean statusResult = registry.statusUpdate(LOCAL_REGION_APP_NAME, myInstance.getId(), InstanceStatus.OUT_OF_SERVICE, "0", false);
assertThat("Couldn't override instance status", statusResult, is(true));
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
// If we are not UP or OUT_OF_SERVICE, the OUT_OF_SERVICE override does not apply. It gets trumped by the current
// status (STARTING or DOWN). Here we test with STARTING.
myInstance = createLocalStartingInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registerInstanceLocally(myInstance);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.STARTING);
}
@Test
public void testStatusOverrideWithExistingLeaseUp() throws Exception {
// Without an override we expect to get the existing UP lease when we re-register with OUT_OF_SERVICE.
// First, we are "up".
InstanceInfo myInstance = createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registerInstanceLocally(myInstance);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
// Then, we re-register with "out of service".
InstanceInfo sameInstance = createLocalOutOfServiceInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registry.register(sameInstance, 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
// Let's try again. We shouldn't see a difference.
sameInstance = createLocalOutOfServiceInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registry.register(sameInstance, 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.UP);
}
@Test
public void testStatusOverrideWithExistingLeaseOutOfService() throws Exception {
// Without an override we expect to get the existing OUT_OF_SERVICE lease when we re-register with UP.
// First, we are "out of service".
InstanceInfo myInstance = createLocalOutOfServiceInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registerInstanceLocally(myInstance);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
// Then, we re-register with "UP".
InstanceInfo sameInstance = createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registry.register(sameInstance, 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
// Let's try again. We shouldn't see a difference.
sameInstance = createLocalInstance(LOCAL_REGION_INSTANCE_1_HOSTNAME);
registry.register(sameInstance, 10000000, false);
verifyLocalInstanceStatus(myInstance.getId(), InstanceStatus.OUT_OF_SERVICE);
}
@Test
public void testEvictionTaskCompensationTime() throws Exception {
long evictionTaskPeriodNanos = serverConfig.getEvictionIntervalTimerInMs() * 1000000;
AbstractInstanceRegistry.EvictionTask testTask = spy(registry.new EvictionTask());
when(testTask.getCurrentTimeNano())
.thenReturn(1l) // less than the period
.thenReturn(1l + evictionTaskPeriodNanos) // exactly 1 period
.thenReturn(1l + evictionTaskPeriodNanos*2 + 10000000l) // 10ms longer than 1 period
.thenReturn(1l + evictionTaskPeriodNanos*3 - 1l); // less than 1 period
assertThat(testTask.getCompensationTimeMs(), is(0l));
assertThat(testTask.getCompensationTimeMs(), is(0l));
assertThat(testTask.getCompensationTimeMs(), is(10l));
assertThat(testTask.getCompensationTimeMs(), is(0l));
}
}