Author: pmouawad
Date: Sun Jan 29 20:35:59 2017
New Revision: 1780852
URL: http://svn.apache.org/viewvc?rev=1780852&view=rev
Log:
Avoid NPE if init of resolver fails
Add Test cases
Modified:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/DNSCacheManager.java
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/control/TestDNSCacheManager.java
Modified:
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/DNSCacheManager.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/DNSCacheManager.java?rev=1780852&r1=1780851&r2=1780852&view=diff
==============================================================================
---
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/DNSCacheManager.java
(original)
+++
jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/control/DNSCacheManager.java
Sun Jan 29 20:35:59 2017
@@ -61,34 +61,36 @@ public class DNSCacheManager extends Con
private static final Logger log = LoggingManager.getLoggerForClass();
- private transient SystemDefaultDnsResolver systemDefaultDnsResolver = null;
-
- private Map<String, InetAddress[]> cache = null;
-
- private transient Resolver resolver = null;
+ public static final boolean DEFAULT_CLEAR_CACHE_EACH_ITER = false;
//++ JMX tag values
- public static final String CLEAR_CACHE_EACH_ITER =
"DNSCacheManager.clearEachIteration"; // $NON-NLS-1$
+ private static final String CLEAR_CACHE_EACH_ITER =
"DNSCacheManager.clearEachIteration"; // $NON-NLS-1$
- public static final String SERVERS = "DNSCacheManager.servers"; //
$NON-NLS-1$
+ private static final String SERVERS = "DNSCacheManager.servers"; //
$NON-NLS-1$
- public static final String IS_CUSTOM_RESOLVER =
"DNSCacheManager.isCustomResolver"; // $NON-NLS-1$
+ private static final String IS_CUSTOM_RESOLVER =
"DNSCacheManager.isCustomResolver"; // $NON-NLS-1$
//-- JMX tag values
- public static final boolean DEFAULT_CLEAR_CACHE_EACH_ITER = false;
+ private static final boolean DEFAULT_IS_CUSTOM_RESOLVER = false;
- public static final String DEFAULT_SERVERS = ""; // $NON-NLS-1$
+ private final transient Cache lookupCache;
- public static final boolean DEFAULT_IS_CUSTOM_RESOLVER = false;
+ private final transient SystemDefaultDnsResolver systemDefaultDnsResolver;
- private final transient Cache lookupCache;
+ private final Map<String, InetAddress[]> cache;
+
+ transient Resolver resolver;
private transient int timeoutMs;
+ transient boolean initFailed;
+
// ensure that the initial DNSServers are copied to the per-thread
instances
public DNSCacheManager() {
setProperty(new CollectionProperty(SERVERS, new ArrayList<String>()));
+ this.systemDefaultDnsResolver = new SystemDefaultDnsResolver();
+ this.cache = new LinkedHashMap<>();
//disabling cache
lookupCache = new Cache();
lookupCache.setMaxCache(0);
@@ -101,8 +103,14 @@ public class DNSCacheManager extends Con
@Override
public Object clone() {
DNSCacheManager clone = (DNSCacheManager) super.clone();
- clone.systemDefaultDnsResolver = new SystemDefaultDnsResolver();
- clone.cache = new LinkedHashMap<>();
+ clone.resolver = createResolver();
+ return clone;
+ }
+
+ /**
+ * @return {@link Resolver}
+ */
+ private Resolver createResolver() {
CollectionProperty dnsServers = getServers();
try {
String[] serverNames = new String[dnsServers.size()];
@@ -111,16 +119,20 @@ public class DNSCacheManager extends Con
serverNames[index] = jMeterProperty.getStringValue();
index++;
}
- clone.resolver = new ExtendedResolver(serverNames);
- log.debug("Using DNS Resolvers: "
- + Arrays.asList(((ExtendedResolver) clone.resolver)
- .getResolvers()));
+ ExtendedResolver resolver = new ExtendedResolver(serverNames);
+ if(log.isDebugEnabled()) {
+ log.debug("Using DNS Resolvers: "
+ + Arrays.asList(((ExtendedResolver) resolver)
+ .getResolvers()));
+ }
// resolvers will be chosen via round-robin
- ((ExtendedResolver) clone.resolver).setLoadBalance(true);
+ resolver.setLoadBalance(true);
+ return resolver;
} catch (UnknownHostException uhe) {
+ this.initFailed = true;
log.warn("Failed to create Extended resolver: " +
uhe.getMessage());
+ return null;
}
- return clone;
}
/**
@@ -129,12 +141,19 @@ public class DNSCacheManager extends Con
*/
@Override
public InetAddress[] resolve(String host) throws UnknownHostException {
- if (cache.containsKey(host)) {
+ InetAddress[] result = cache.get(host);
+ // cache may contain
+ // A return value of null does not necessarily
+ // indicate that the map contains no mapping
+ // for the key; it's also possible that the map
+ // explicitly maps the key to null
+ //
https://docs.oracle.com/javase/8/docs/api/java/util/LinkedHashMap.html
+ if (result != null || cache.containsKey(host)) {
if (log.isDebugEnabled()) {
log.debug("Cache hit thr#" +
JMeterContextService.getContext().getThreadNum() + ": " + host + "=>"
- + Arrays.toString(cache.get(host)));
+ + Arrays.toString(result));
}
- return cache.get(host);
+ return result;
} else {
InetAddress[] addresses = requestLookup(host);
if (log.isDebugEnabled()) {
@@ -148,39 +167,60 @@ public class DNSCacheManager extends Con
/**
* Sends DNS request via system or custom DNS resolver
+ * @param host
+ * @return array of {@link InetAddress} or null if lookup did not return
result
*/
private InetAddress[] requestLookup(String host) throws
UnknownHostException {
InetAddress[] addresses = null;
- if (isCustomResolver() && ((ExtendedResolver)
resolver).getResolvers().length > 0) {
- try {
- Lookup lookup = new Lookup(host, Type.A);
- lookup.setCache(lookupCache);
- if (timeoutMs > 0) {
- resolver.setTimeout(timeoutMs / 1000, timeoutMs % 1000);
- }
- lookup.setResolver(resolver);
- Record[] records = lookup.run();
- if (records == null || records.length == 0) {
- throw new UnknownHostException("Failed to resolve host
name: " + host);
- }
- addresses = new InetAddress[records.length];
- for (int i = 0; i < records.length; i++) {
- addresses[i] = ((ARecord) records[i]).getAddress();
+ if (isCustomResolver()) {
+ if (getResolver() != null) {
+ if(getResolver().getResolvers().length > 0) {
+ try {
+ Lookup lookup = new Lookup(host, Type.A);
+ lookup.setCache(lookupCache);
+ if (timeoutMs > 0) {
+ resolver.setTimeout(timeoutMs / 1000, timeoutMs %
1000);
+ }
+ lookup.setResolver(resolver);
+ Record[] records = lookup.run();
+ if (records == null || records.length == 0) {
+ throw new UnknownHostException("Failed to resolve
host name: " + host);
+ }
+ addresses = new InetAddress[records.length];
+ for (int i = 0; i < records.length; i++) {
+ addresses[i] = ((ARecord) records[i]).getAddress();
+ }
+ } catch (TextParseException tpe) {
+ log.debug("Failed to create Lookup object: " + tpe);
+ }
+ return addresses;
}
- } catch (TextParseException tpe) {
- log.debug("Failed to create Lookup object: " + tpe);
- }
- } else {
- addresses = systemDefaultDnsResolver.resolve(host);
- if (log.isDebugEnabled()) {
- log.debug("Cache miss: " + host + " Thread #" +
JMeterContextService.getContext().getThreadNum()
- + ", resolved with system resolver into " +
Arrays.toString(addresses));
+ } else {
+ throw new UnknownHostException("Could not resolve host:"+host
+ +", failed to initialize resolver"
+ + " or no resolver found");
}
}
+ addresses = systemDefaultDnsResolver.resolve(host);
+ if (log.isDebugEnabled()) {
+ log.debug("Cache miss: " + host + " Thread #" +
JMeterContextService.getContext().getThreadNum()
+ + ", resolved with system resolver into " +
Arrays.toString(addresses));
+ }
return addresses;
}
/**
+ * Tries to initialize resolver , otherwise sets initFailed to true
+ * @return ExtendedResolver if init succeeded or null otherwise
+ */
+ private ExtendedResolver getResolver() {
+ if(resolver == null && !initFailed) {
+ resolver = createResolver();
+ }
+ return (ExtendedResolver) resolver;
+ }
+
+ /**
* {@inheritDoc} Clean DNS cache if appropriate check-box was selected
*/
@Override
@@ -197,6 +237,9 @@ public class DNSCacheManager extends Con
public void clear() {
super.clear();
clearServers(); // ensure data is set up OK initially
+ this.cache.clear();
+ this.initFailed = false;
+ this.resolver = null;
}
/**
Modified:
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/control/TestDNSCacheManager.java
URL:
http://svn.apache.org/viewvc/jmeter/trunk/test/src/org/apache/jmeter/protocol/http/control/TestDNSCacheManager.java?rev=1780852&r1=1780851&r2=1780852&view=diff
==============================================================================
---
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/control/TestDNSCacheManager.java
(original)
+++
jmeter/trunk/test/src/org/apache/jmeter/protocol/http/control/TestDNSCacheManager.java
Sun Jan 29 20:35:59 2017
@@ -20,18 +20,92 @@ package org.apache.jmeter.protocol.http.
import static org.junit.Assert.fail;
+import java.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.jmeter.junit.JMeterTestCase;
+import org.junit.Assert;
import org.junit.Test;
+import org.xbill.DNS.ExtendedResolver;
public class TestDNSCacheManager extends JMeterTestCase {
-
+ private static final String INVALID_DNS_SERVER = "8.8.8.8.9"; //$NON-NLS-1$
+
+ private static final String VALID_DNS_SERVER = "8.8.8.8"; //$NON-NLS-1$
+ @Test
+ public void testWithCustomResolverAnd1WrongServer() throws
UnknownHostException {
+ DNSCacheManager original = new DNSCacheManager();
+ original.addServer(INVALID_DNS_SERVER);
+ original.setCustomResolver(true);
+ original.setTimeoutMs(100);
+ try {
+ original.resolve("jmeter.apache.org");
+ fail("Should have failed as DNS server does not exist");
+ } catch (UnknownHostException e) {
+ Assert.assertNull(original.resolver);
+ Assert.assertTrue(original.initFailed);
+ }
+
+ try {
+ original.resolve("www.apache.org");
+ fail("Should have failed as DNS server does not exist");
+ // OK
+ } catch (UnknownHostException e) {
+ Assert.assertNull(original.resolver);
+ Assert.assertTrue(original.initFailed);
+ }
+ }
+
+ @Test
+ public void testWithCustomResolverAnd1Server() throws UnknownHostException
{
+ DNSCacheManager original = new DNSCacheManager();
+ original.addServer(VALID_DNS_SERVER);
+ original.setCustomResolver(true);
+ original.setTimeoutMs(100);
+ try {
+ original.resolve("jmeter.apache.org");
+ Assert.assertNotNull(original.resolver);
+
Assert.assertTrue(((ExtendedResolver)original.resolver).getResolvers().length==1);
+ // OK
+ } catch (UnknownHostException e) {
+ fail("System DNS server should have been used");
+ }
+ }
+
+ @Test
+ public void testWithCustomResolverAndNoServer() throws
UnknownHostException {
+ DNSCacheManager original = new DNSCacheManager();
+ original.setCustomResolver(true);
+ original.setTimeoutMs(100);
+ try {
+ // This will use Default System DNS resolver
+ original.resolve("jmeter.apache.org");
+ Assert.assertNotNull(original.resolver);
+
Assert.assertTrue(((ExtendedResolver)original.resolver).getResolvers().length==0);
+ } catch (UnknownHostException e) {
+ fail("Should have failed as no DNS server provided");
+ }
+ }
+
+ @Test
+ public void testWithCustomResolverAndInvalidNameserver() throws
UnknownHostException {
+ DNSCacheManager original = new DNSCacheManager();
+ original.setCustomResolver(true);
+ original.addServer(INVALID_DNS_SERVER);
+ original.setTimeoutMs(100);
+ try {
+ original.resolve("jmeter.apache.org");
+ fail();
+ } catch (UnknownHostException e) {
+ // OK
+ }
+ }
+
@Test
public void testCloneWithCustomResolverAndInvalidNameserver() throws
UnknownHostException {
DNSCacheManager original = new DNSCacheManager();
original.setCustomResolver(true);
- original.addServer("127.0.0.99");
+ original.addServer(INVALID_DNS_SERVER);
DNSCacheManager clone = (DNSCacheManager) original.clone();
clone.setTimeoutMs(100);
try {
@@ -41,5 +115,32 @@ public class TestDNSCacheManager extends
// OK
}
}
-
+
+ @Test
+ public void testResolveExistingHostWithSystemDefaultDnsServer() throws
UnknownHostException {
+ DNSCacheManager original = new DNSCacheManager();
+ original.setCustomResolver(false);
+ try {
+ InetAddress[] result = original.resolve("www.example.org");
+ Assert.assertNotNull(result);
+ Assert.assertNull(original.resolver);
+ // IPv4 and IPv6
+ Assert.assertTrue(result.length == 2);
+ } catch (UnknownHostException e) {
+ Assert.fail("Should not have failed");
+ }
+ }
+
+ @Test
+ public void testResolveNonExistingHostWithSystemDefaultDnsServer() throws
UnknownHostException {
+ DNSCacheManager original = new DNSCacheManager();
+ original.setCustomResolver(false);
+ try {
+ original.resolve("jmeterxxx.apache.org");
+ fail();
+ } catch (UnknownHostException e) {
+ Assert.assertNull(original.resolver);
+ // OK
+ }
+ }
}