| /* | |
| * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import java.net.InetAddress; | |
| import java.nio.charset.StandardCharsets; | |
| import java.nio.file.Files; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import java.util.stream.Collectors; | |
| import java.util.stream.Stream; | |
| import jdk.test.lib.net.IPSupport; | |
| import org.testng.annotations.BeforeClass; | |
| import org.testng.annotations.Test; | |
| import org.testng.Assert; | |
| /* @test | |
| * @bug 8244958 | |
| * @library /test/lib | |
| * @build jdk.test.lib.Platform jdk.test.lib.net.IPSupport | |
| * @summary Test that "jdk.net.hosts.file" NameService implementation returns addresses | |
| * with respect to "java.net.preferIPv4Stack" and "java.net.preferIPv6Addresses" system | |
| * property values | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=true HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=system HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=notVALID HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=true HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=false HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=system HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt | |
| * -Djava.net.preferIPv4Stack=false -Djava.net.preferIPv6Addresses=notVALID HostsFileOrderingTest | |
| * @run testng/othervm -Djdk.net.hosts.file=TestHostsFile.txt HostsFileOrderingTest | |
| */ | |
| public class HostsFileOrderingTest { | |
| /* | |
| * Generate hosts file with the predefined list of IP addresses | |
| */ | |
| @BeforeClass | |
| public void generateHostsFile() throws Exception { | |
| String content = ADDRESSES_LIST.stream() | |
| .map(addr -> addr + " " + TEST_HOST_NAME) | |
| .collect( | |
| Collectors.joining(System.lineSeparator(), | |
| "# Generated hosts file"+System.lineSeparator(), | |
| System.lineSeparator()) | |
| ); | |
| Files.write(HOSTS_FILE_PATH, content.getBytes(StandardCharsets.UTF_8)); | |
| } | |
| /* | |
| * Test that HostsFile name service returns addresses in order that complies with the | |
| * 'sun.net.preferIPv4Stack' and 'preferIPv6Addresses' | |
| */ | |
| @Test | |
| public void testOrdering() throws Exception { | |
| String [] resolvedAddresses = Arrays.stream(InetAddress.getAllByName("hostname.test.com")) | |
| .map(InetAddress::getHostAddress).toArray(String[]::new); | |
| String [] expectedAddresses = getExpectedAddressesArray(); | |
| if (Arrays.deepEquals(resolvedAddresses, expectedAddresses)) { | |
| System.err.println("Test passed: The expected list of IP addresses is returned"); | |
| } else { | |
| System.err.printf("Expected addresses:%n%s%n", Arrays.deepToString(expectedAddresses)); | |
| System.err.printf("Resolved addresses:%n%s%n", Arrays.deepToString(resolvedAddresses)); | |
| Assert.fail("Wrong host resolution result is returned"); | |
| } | |
| } | |
| /* | |
| * Calculate expected order of IP addresses based on the "preferIPv6Addresses" and "preferIPv4Stack" | |
| * system property values | |
| */ | |
| static ExpectedOrder getExpectedOrderFromSystemProperties() { | |
| if (PREFER_IPV4_STACK_VALUE != null && | |
| PREFER_IPV4_STACK_VALUE.equalsIgnoreCase("true")) { | |
| return ExpectedOrder.IPV4_ONLY; | |
| } | |
| if (!IPSupport.hasIPv6()) { | |
| return ExpectedOrder.IPV4_ONLY; | |
| } | |
| if (PREFER_IPV6_ADDRESSES_VALUE != null) { | |
| return switch(PREFER_IPV6_ADDRESSES_VALUE.toLowerCase()) { | |
| case "true" -> ExpectedOrder.IPV6_IPV4; | |
| case "system" -> ExpectedOrder.NO_MODIFICATION; | |
| default -> ExpectedOrder.IPV4_IPV6; | |
| }; | |
| } | |
| return ExpectedOrder.IPV4_IPV6; | |
| } | |
| /* | |
| * Return array expected to be returned by InetAddress::getAllByName call | |
| */ | |
| static String[] getExpectedAddressesArray() { | |
| List<String> resList = switch (getExpectedOrderFromSystemProperties()) { | |
| case IPV4_ONLY -> IPV4_LIST; | |
| case IPV6_IPV4 -> IPV6_THEN_IPV4_LIST; | |
| case IPV4_IPV6 -> IPV4_THEN_IPV6_LIST; | |
| case NO_MODIFICATION -> ADDRESSES_LIST; | |
| }; | |
| return resList.toArray(String[]::new); | |
| } | |
| // Possible types of addresses order | |
| enum ExpectedOrder { | |
| IPV4_ONLY, | |
| IPV6_IPV4, | |
| IPV4_IPV6, | |
| NO_MODIFICATION; | |
| } | |
| // Addresses list | |
| private static final List<String> ADDRESSES_LIST = List.of( | |
| "192.168.239.11", | |
| "2001:db8:85a3:0:0:8a2e:370:7334", | |
| "192.168.14.10", | |
| "2001:85a3:db8:0:0:8a2e:7334:370", | |
| "192.168.129.16", | |
| "2001:dead:beef:0:0:8a2e:1239:212" | |
| ); | |
| // List of IPv4 addresses. The order is as in hosts file | |
| private static final List<String> IPV4_LIST = ADDRESSES_LIST.stream() | |
| .filter(ips -> ips.contains(".")) | |
| .collect(Collectors.toUnmodifiableList()); | |
| // List of IPv6 addresses. The order is as in hosts file | |
| private static final List<String> IPV6_LIST = ADDRESSES_LIST.stream() | |
| .filter(ip -> ip.contains(":")) | |
| .collect(Collectors.toUnmodifiableList()); | |
| // List of IPv4 then IPv6 addresses. Orders inside each address type block is the same | |
| // as in hosts file | |
| private static final List<String> IPV4_THEN_IPV6_LIST = Stream.of(IPV4_LIST, IPV6_LIST) | |
| .flatMap(Collection::stream).collect(Collectors.toList()); | |
| // List of IPv6 then IPv4 addresses. Orders inside each address type block is the same | |
| // as in hosts file | |
| private static final List<String> IPV6_THEN_IPV4_LIST = Stream.of(IPV6_LIST, IPV4_LIST) | |
| .flatMap(Collection::stream).collect(Collectors.toList()); | |
| private static final String HOSTS_FILE_NAME = "TestHostsFile.txt"; | |
| private static final Path HOSTS_FILE_PATH = Paths.get( | |
| System.getProperty("user.dir", ".")).resolve(HOSTS_FILE_NAME); | |
| private static final String TEST_HOST_NAME = "hostname.test.com"; | |
| private static final String PREFER_IPV6_ADDRESSES_VALUE = | |
| System.getProperty("java.net.preferIPv6Addresses"); | |
| private static final String PREFER_IPV4_STACK_VALUE = | |
| System.getProperty("java.net.preferIPv4Stack"); | |
| } |