package com.alibaba.dcm;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static java.lang.System.currentTimeMillis;
import static java.lang.Thread.sleep;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Jerry Lee (oldratlee at gmail dot com)
*/
public class DnsCacheManipulatorTest {
private static final String DOMAIN1 = "www.hello1.com";
private static final String IP1 = "42.42.41.41";
private static final String DOMAIN2 = "www.hello2.com";
private static final String IP2 = "42.42.41.42";
private static final String IP3 = "42.42.43.43";
private static final String DOMAIN_CUSTOMIZED = "www.customized.com";
private static final String IP_CUSTOMIZED = "42.42.42.42";
private static final String DOMAIN_NOT_EXISTED = "www.domain-not-existed-7352jt-12559-AZ-7524087.com";
@BeforeClass
public static void beforeClass() throws Exception {
// System Properties
// https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.printf("Env info:\njava home: %s\njdk version: %s\n",
System.getProperty("java.home"),
System.getProperty("java.version"));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
}
@Before
public void before() throws Exception {
DnsCacheManipulator.clearDnsCache();
assertTrue(DnsCacheManipulator.getAllDnsCache().isEmpty());
assertTrue(DnsCacheManipulator.getWholeDnsCache().getNegativeCache().isEmpty());
}
@Test
public void test_loadDnsCacheConfig() throws Exception {
DnsCacheManipulator.loadDnsCacheConfig();
final String ip = InetAddress.getByName(DOMAIN1).getHostAddress();
assertEquals(IP1, ip);
}
@Test
public void test_loadDnsCacheConfig_from_D_Option() throws Exception {
final String key = "dcm.config.filename";
System.setProperty(key, "customized-dns-cache.properties");
DnsCacheManipulator.loadDnsCacheConfig();
final String ip = InetAddress.getByName(DOMAIN_CUSTOMIZED).getHostAddress();
assertEquals(IP_CUSTOMIZED, ip);
System.clearProperty(key);
}
@Test
public void test_loadDnsCacheConfig_fromMyConfig() throws Exception {
DnsCacheManipulator.loadDnsCacheConfig("my-dns-cache.properties");
final String ip = InetAddress.getByName(DOMAIN2).getHostAddress();
assertEquals(IP2, ip);
}
@Test
public void test_setMultiIp() throws Exception {
DnsCacheManipulator.setDnsCache("multi.ip.com", "1.1.1.1", "2.2.2.2");
String ip = InetAddress.getByName("multi.ip.com").getHostAddress();
assertEquals("1.1.1.1", ip);
InetAddress[] all = InetAddress.getAllByName("multi.ip.com");
assertEquals(2, all.length);
String[] ips = {all[0].getHostAddress(), all[1].getHostAddress()};
assertArrayEquals(new String[]{"1.1.1.1", "2.2.2.2"}, ips);
}
@Test
public void test_configNotFound() throws Exception {
try {
DnsCacheManipulator.loadDnsCacheConfig("not-existed.properties");
fail();
} catch (DnsCacheManipulatorException expected) {
assertEquals("Fail to find not-existed.properties on classpath!", expected.getMessage());
}
}
@Test
public void test_setDnsCache_getAllDnsCache() throws Exception {
final String host = "www.test_setDnsCache_getAllDnsCache.com";
DnsCacheManipulator.setDnsCache(host, IP3);
final List<DnsCacheEntry> allDnsCacheEntries = DnsCacheManipulator.getAllDnsCache();
final List<DnsCacheEntry> expected = Arrays.asList(
new DnsCacheEntry(host.toLowerCase(), new String[]{IP3}, new Date(Long.MAX_VALUE)));
assertEquals(expected, allDnsCacheEntries);
assertTrue(DnsCacheManipulator.getWholeDnsCache().getNegativeCache().isEmpty());
}
@Test
public void test_canSetExistedDomain_canExpire_thenReLookupBack() throws Exception {
final String domain = "github.com";
Set<String> expected = getAllHostAddresses(domain);
DnsCacheManipulator.setDnsCache(30, domain, IP3);
assertEquals(IP3, InetAddress.getByName(domain).getHostAddress());
sleep(32);
assertEquals(expected, getAllHostAddresses(domain));
}
private static Set<String> getAllHostAddresses(String domain) throws Exception {
final InetAddress[] allByName = InetAddress.getAllByName(domain);
Set<String> all = new HashSet<String>();
for (InetAddress inetAddress : allByName) {
all.add(inetAddress.getHostAddress());
}
return all;
}
@Test
public void test_setNotExistedDomain_RemoveThenReLookupAndNotExisted() throws Exception {
System.out.printf("%s(%s) test_setNotExistedDomain_RemoveThenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
DnsCacheManipulator.setDnsCache(DOMAIN_NOT_EXISTED, IP3);
System.out.printf("%s(%s) test_setNotExistedDomain_RemoveThenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
final String ip = InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
assertEquals(IP3, ip);
DnsCacheManipulator.removeDnsCache(DOMAIN_NOT_EXISTED);
assertDomainNotExisted();
System.out.printf("%s(%s) test_setNotExistedDomain_RemoveThenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
final List<DnsCacheEntry> cache = DnsCacheManipulator.listDnsCache();
assertTrue(cache.isEmpty());
final List<DnsCacheEntry> negativeCache = DnsCacheManipulator.getWholeDnsCache().getNegativeCache();
assertEquals(1, negativeCache.size());
assertEquals(DOMAIN_NOT_EXISTED.toLowerCase(), negativeCache.get(0).getHost());
}
private static void assertDomainNotExisted() {
try {
InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
fail();
} catch (UnknownHostException expected) {
System.out.println(expected.toString());
assertTrue(true);
}
}
@Test
public void test_setNotExistedDomain_canExpire_thenReLookupAndNotExisted() throws Exception {
System.out.printf("%s(%s) test_setNotExistedDomain_canExpire_thenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
DnsCacheManipulator.setDnsCache(100, DOMAIN_NOT_EXISTED, IP3);
System.out.printf("%s(%s) test_setNotExistedDomain_canExpire_thenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
final String ip = InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
assertEquals(IP3, ip);
sleep(100);
assertDomainNotExisted();
System.out.printf("%s(%s) test_setNotExistedDomain_canExpire_thenReLookupAndNotExisted %s\n",
new Date(), currentTimeMillis(), DnsCacheManipulator.getWholeDnsCache());
final List<DnsCacheEntry> cache = DnsCacheManipulator.listDnsCache();
assertTrue(cache.isEmpty());
final List<DnsCacheEntry> negativeCache = DnsCacheManipulator.getWholeDnsCache().getNegativeCache();
assertEquals(1, negativeCache.size());
assertEquals(DOMAIN_NOT_EXISTED.toLowerCase(), negativeCache.get(0).getHost());
}
@Test
public void test_multi_ips_in_config_file() throws Exception {
DnsCacheManipulator.loadDnsCacheConfig("dns-cache-multi-ips.properties");
final String host = "www.hello-multi-ips.com";
DnsCacheEntry entry = new DnsCacheEntry(host,
new String[]{"42.42.41.1", "42.42.41.2"}, new Date(Long.MAX_VALUE));
assertEquals(entry, DnsCacheManipulator.getDnsCache(host));
final String hostLoose = "www.hello-multi-ips-loose.com";
DnsCacheEntry entryLoose = new DnsCacheEntry(hostLoose,
new String[]{"42.42.41.1", "42.42.41.2", "42.42.41.3", "42.42.41.4"}, new Date(Long.MAX_VALUE));
assertEquals(entryLoose, DnsCacheManipulator.getDnsCache(hostLoose));
}
@Test
public void test_nullSafeForGetDnsCache() throws Exception {
final DnsCacheEntry dnsCache = DnsCacheManipulator.getDnsCache(DOMAIN_NOT_EXISTED);
assertNull(dnsCache);
}
@Test
public void test_setDnsCachePolicy() throws Exception {
final String host = "baidu.com";
DnsCacheManipulator.setDnsCachePolicy(2);
assertEquals(2, DnsCacheManipulator.getDnsCachePolicy());
InetAddress.getByName(host).getHostAddress();
final long tick = currentTimeMillis();
sleep(1000);
InetAddress.getByName(host).getHostAddress();
final DnsCacheEntry dnsCache = DnsCacheManipulator.getDnsCache(host);
assertBetween(dnsCache.getExpiration().getTime(), tick, tick + 2001);
sleep(1001);
// return expired entry, because of no dns cache touch by external related operation!
final DnsCacheEntry next = DnsCacheManipulator.getDnsCache(host);
assertNotSame(dnsCache, next);
assertEquals(dnsCache, next);
// touch dns cache with external other host operation
InetAddress.getByName("www.baidu.com").getHostAddress();
assertNull(DnsCacheManipulator.getDnsCache(host));
// relookup
InetAddress.getByName(host).getHostAddress();
final DnsCacheEntry relookup = DnsCacheManipulator.getDnsCache(host);
final long relookupTick = currentTimeMillis();
assertBetween(relookup.getExpiration().getTime(), relookupTick, relookupTick + 2001);
}
@Test
public void test_setNegativeDnsCachePolicy() throws Exception {
DnsCacheManipulator.setDnsNegativeCachePolicy(2);
assertEquals(2, DnsCacheManipulator.getDnsNegativeCachePolicy());
try {
InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
fail();
} catch (UnknownHostException expected) {
assertTrue(true);
}
final long tick = currentTimeMillis();
final List<DnsCacheEntry> negativeCache = DnsCacheManipulator.getWholeDnsCache().getNegativeCache();
assertEquals(1, negativeCache.size());
final DnsCacheEntry dnsCache = negativeCache.get(0);
assertBetween(dnsCache.getExpiration().getTime(), tick, tick + 2001);
sleep(1000);
try {
InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
fail();
} catch (UnknownHostException expected) {
assertTrue(true);
}
assertEquals(dnsCache, DnsCacheManipulator.getWholeDnsCache().getNegativeCache().get(0));
sleep(1001);
try {
InetAddress.getByName(DOMAIN_NOT_EXISTED).getHostAddress();
fail();
} catch (UnknownHostException expected) {
assertTrue(true);
}
final long relookupTick = currentTimeMillis();
final List<DnsCacheEntry> relookupNegativeCache = DnsCacheManipulator.getWholeDnsCache().getNegativeCache();
assertEquals(1, relookupNegativeCache.size());
final DnsCacheEntry relookup = relookupNegativeCache.get(0);
assertBetween(relookup.getExpiration().getTime(), relookupTick, relookupTick + 2001);
}
static void assertBetween(long actual, long start, long end) {
final boolean ok = (start <= actual) && (actual <= end);
if (!ok) {
fail(start + " <= " + actual + " <= " + end + ", failed!");
}
}
}