org.apache.hadoop.net.TestDNS.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.net.TestDNS.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.net;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.net.InetAddress;

import javax.naming.CommunicationException;
import javax.naming.NameNotFoundException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.util.Shell;
import org.apache.hadoop.util.Time;

import org.junit.Test;

import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;

/**
 * Test host name and IP resolution and caching.
 */
public class TestDNS {

    private static final Log LOG = LogFactory.getLog(TestDNS.class);
    private static final String DEFAULT = "default";

    // This is not a legal hostname (starts with a hyphen). It will never
    // be returned on any test machine.
    private static final String DUMMY_HOSTNAME = "-DUMMY_HOSTNAME";
    private static final String INVALID_DNS_SERVER = "0.0.0.1";

    /**
     * Test that asking for the default hostname works
     * @throws Exception if hostname lookups fail
     */
    @Test
    public void testGetLocalHost() throws Exception {
        String hostname = DNS.getDefaultHost(DEFAULT);
        assertNotNull(hostname);
    }

    /**
     * Test that repeated calls to getting the local host are fairly fast, and
     * hence that caching is being used
     * @throws Exception if hostname lookups fail
     */
    @Test
    public void testGetLocalHostIsFast() throws Exception {
        String hostname1 = DNS.getDefaultHost(DEFAULT);
        assertNotNull(hostname1);
        String hostname2 = DNS.getDefaultHost(DEFAULT);
        long t1 = Time.now();
        String hostname3 = DNS.getDefaultHost(DEFAULT);
        long t2 = Time.now();
        assertEquals(hostname3, hostname2);
        assertEquals(hostname2, hostname1);
        long interval = t2 - t1;
        assertTrue("Took too long to determine local host - caching is not working", interval < 20000);
    }

    /**
     * Test that our local IP address is not null
     * @throws Exception if something went wrong
     */
    @Test
    public void testLocalHostHasAnAddress() throws Exception {
        assertNotNull(getLocalIPAddr());
    }

    private InetAddress getLocalIPAddr() throws UnknownHostException {
        String hostname = DNS.getDefaultHost(DEFAULT);
        InetAddress localhost = InetAddress.getByName(hostname);
        return localhost;
    }

    /**
     * Test null interface name
     */
    @Test
    public void testNullInterface() throws Exception {
        String host = DNS.getDefaultHost(null); // should work.
        assertThat(host, is(DNS.getDefaultHost(DEFAULT)));
        try {
            String ip = DNS.getDefaultIP(null);
            fail("Expected a NullPointerException, got " + ip);
        } catch (NullPointerException npe) {
            // Expected
        }
    }

    /**
     * Test that 'null' DNS server gives the same result as if no DNS
     * server was passed.
     */
    @Test
    public void testNullDnsServer() throws Exception {
        String host = DNS.getDefaultHost(getLoopbackInterface(), null);
        assertThat(host, is(DNS.getDefaultHost(getLoopbackInterface())));
    }

    /**
     * Test that "default" DNS server gives the same result as if no DNS
     * server was passed.
     */
    @Test
    public void testDefaultDnsServer() throws Exception {
        String host = DNS.getDefaultHost(getLoopbackInterface(), DEFAULT);
        assertThat(host, is(DNS.getDefaultHost(getLoopbackInterface())));
    }

    /**
     * Get the IP addresses of an unknown interface
     */
    @Test
    public void testIPsOfUnknownInterface() throws Exception {
        try {
            DNS.getIPs("name-of-an-unknown-interface");
            fail("Got an IP for a bogus interface");
        } catch (UnknownHostException e) {
            assertEquals("No such interface name-of-an-unknown-interface", e.getMessage());
        }
    }

    /**
     * Test the "default" IP addresses is the local IP addr
     */
    @Test
    public void testGetIPWithDefault() throws Exception {
        String[] ips = DNS.getIPs(DEFAULT);
        assertEquals("Should only return 1 default IP", 1, ips.length);
        assertEquals(getLocalIPAddr().getHostAddress(), ips[0].toString());
        String ip = DNS.getDefaultIP(DEFAULT);
        assertEquals(ip, ips[0].toString());
    }

    /**
     * TestCase: get our local address and reverse look it up
     */
    @Test
    public void testRDNS() throws Exception {
        InetAddress localhost = getLocalIPAddr();
        try {
            String s = DNS.reverseDns(localhost, null);
            LOG.info("Local reverse DNS hostname is " + s);
        } catch (NameNotFoundException | CommunicationException e) {
            if (!localhost.isLinkLocalAddress() || localhost.isLoopbackAddress()) {
                //these addresses probably won't work with rDNS anyway, unless someone
                //has unusual entries in their DNS server mapping 1.0.0.127 to localhost
                LOG.info("Reverse DNS failing as due to incomplete networking", e);
                LOG.info("Address is " + localhost + " Loopback=" + localhost.isLoopbackAddress() + " Linklocal="
                        + localhost.isLinkLocalAddress());
            }
        }
    }

    /**
     * Test that when using an invalid DNS server with hosts file fallback,
     * we are able to get the hostname from the hosts file.
     *
     * This test may fail on some misconfigured test machines that don't have
     * an entry for "localhost" in their hosts file. This entry is correctly
     * configured out of the box on common Linux distributions and OS X.
     *
     * Windows refuses to resolve 127.0.0.1 to "localhost" despite the presence of
     * this entry in the hosts file.  We skip the test on Windows to avoid
     * reporting a spurious failure.
     *
     * @throws Exception
     */
    @Test(timeout = 60000)
    public void testLookupWithHostsFallback() throws Exception {
        assumeTrue(!Shell.WINDOWS);
        final String oldHostname = changeDnsCachedHostname(DUMMY_HOSTNAME);

        try {
            String hostname = DNS.getDefaultHost(getLoopbackInterface(), INVALID_DNS_SERVER, true);

            // Expect to get back something other than the cached host name.
            assertThat(hostname, not(DUMMY_HOSTNAME));
        } finally {
            // Restore DNS#cachedHostname for subsequent tests.
            changeDnsCachedHostname(oldHostname);
        }
    }

    /**
     * Test that when using an invalid DNS server without hosts file
     * fallback, we get back the cached host name.
     *
     * @throws Exception
     */
    @Test(timeout = 60000)
    public void testLookupWithoutHostsFallback() throws Exception {
        final String oldHostname = changeDnsCachedHostname(DUMMY_HOSTNAME);

        try {
            String hostname = DNS.getDefaultHost(getLoopbackInterface(), INVALID_DNS_SERVER, false);

            // Expect to get back the cached host name since there was no hosts
            // file lookup.
            assertThat(hostname, is(DUMMY_HOSTNAME));
        } finally {
            // Restore DNS#cachedHostname for subsequent tests.
            changeDnsCachedHostname(oldHostname);
        }
    }

    private String getLoopbackInterface() throws SocketException {
        return NetworkInterface.getByInetAddress(InetAddress.getLoopbackAddress()).getName();
    }

    /**
     * Change DNS#cachedHostName to something which cannot be a real
     * host name. Uses reflection since it is a 'private final' field.
     */
    private String changeDnsCachedHostname(final String newHostname) throws Exception {
        final String oldCachedHostname = DNS.getDefaultHost(DEFAULT);
        Field field = DNS.class.getDeclaredField("cachedHostname");
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.set(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newHostname);
        return oldCachedHostname;
    }

    /**
     * Test that the name "localhost" resolves to something.
     *
     * If this fails, your machine's network is in a mess, go edit /etc/hosts
     */
    @Test
    public void testLocalhostResolves() throws Exception {
        InetAddress localhost = InetAddress.getByName("localhost");
        assertNotNull("localhost is null", localhost);
        LOG.info("Localhost IPAddr is " + localhost.toString());
    }
}