/*
* 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.brooklyn.util.net;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.javalang.JavaClassNames;
import org.apache.brooklyn.util.net.Networking;
import org.apache.brooklyn.util.text.Identifiers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.base.Stopwatch;
import com.google.common.net.HostAndPort;
public class NetworkingUtilsTest {
private static final Logger log = LoggerFactory.getLogger(NetworkingUtilsTest.class);
@Test
public void testValidIp() throws Exception {
assertTrue(Networking.isValidIp4("127.0.0.1"));
assertTrue(Networking.isValidIp4("0.0.0.0"));
assertFalse(Networking.isValidIp4("foo"));
assertTrue(Networking.isValidIp4(Networking.LOOPBACK.getHostName()));
assertTrue(Networking.isValidIp4("0.0.0.00"));
assertTrue(Networking.isValidIp4("127.0.0.000001"));
assertFalse(Networking.isValidIp4("127.0.0.256"));
assertFalse(Networking.isValidIp4("127.0.0."));
assertFalse(Networking.isValidIp4("127.0.0.9f"));
assertFalse(Networking.isValidIp4("127.0.0.1."));
}
@Test
public void testGetInetAddressWithFixedNameByIpBytes() throws Exception {
InetAddress addr = Networking.getInetAddressWithFixedName(new byte[] {1,2,3,4});
assertEquals(addr.getAddress(), new byte[] {1,2,3,4});
assertEquals(addr.getHostName(), "1.2.3.4");
}
@Test
public void testGetInetAddressWithFixedNameByIp() throws Exception {
InetAddress addr = Networking.getInetAddressWithFixedName("1.2.3.4");
assertEquals(addr.getAddress(), new byte[] {1,2,3,4});
assertEquals(addr.getHostName(), "1.2.3.4");
InetAddress addr2 = Networking.getInetAddressWithFixedName("255.255.255.255");
assertEquals(addr2.getAddress(), new byte[] {(byte)(int)255,(byte)(int)255,(byte)(int)255,(byte)(int)255});
assertEquals(addr2.getHostName(), "255.255.255.255");
InetAddress addr3 = Networking.getInetAddressWithFixedName("localhost");
assertEquals(addr3.getHostName(), "localhost");
}
@Test(groups="Integration")
public void testGetInetAddressWithFixedNameButInvalidIpThrowsException() throws Exception {
// as with ByonLocationResolverTest.testNiceError
// some DNS servers give an IP for this "hostname"
// so test is marked as integration now
try {
Networking.getInetAddressWithFixedName("1.2.3.400");
fail();
} catch (Exception e) {
if (Exceptions.getFirstThrowableOfType(e, UnknownHostException.class) == null) throw e;
}
}
@Test
public void testIsPortAvailableReportsTrueWhenPortIsFree() throws Exception {
final int MIN_FREE = 5;
int port = 58769;
int numFree = 0;
for (int i = 0; i < 50 && numFree < MIN_FREE; i++) {
if (Networking.isPortAvailable(port+i))
numFree++;
}
if (numFree < MIN_FREE)
fail("This test requires that at least some ports near "+port+"+ not be in use.");
}
@Test
public void testIsPortAvailableReportsFalseWhenPortIsInUse() throws Exception {
int port = 58767;
ServerSocket ss = null;
do {
port ++;
if (Networking.isPortAvailable(port)) {
try {
ss = new ServerSocket(port);
log.info("acquired port on "+port+" for test "+JavaClassNames.niceClassAndMethod());
assertFalse(Networking.isPortAvailable(port), "port mistakenly reported as available");
} finally {
if (ss != null) {
ss.close();
}
}
}
// repeat until we can get a port
} while (ss == null && port < 60000);
Assert.assertNotNull(ss, "could not get a port");
final int portF = port;
Asserts.succeedsEventually(new Runnable() {
@Override public void run() {
assertTrue(Networking.isPortAvailable(portF), "port "+portF+" not made available afterwards");
}});
}
@Test
public void testIsPortAvailableReportsPromptly() throws Exception {
// repeat until we can get an available port
int port = 58767;
boolean available = false;
do {
port++;
Stopwatch watch = Stopwatch.createStarted();
if (Networking.isPortAvailable(null, port)) {
available = true;
}
long elapsedMillis = watch.elapsed(TimeUnit.MILLISECONDS);
assertTrue(elapsedMillis < 5000, "elapsedMillis="+elapsedMillis+" for isPortAvailable(null, "+port+")");
} while (!available && port < 60000);
Assert.assertTrue(available);
}
@Test
public void testIsPortAvailableValidatesAddress() throws Exception {
ServerSocket ss = new ServerSocket();
ss.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
int boundPort = ss.getLocalPort();
assertTrue(ss.isBound());
assertNotEquals(boundPort, 0);
//will run isAddressValid before returning
assertFalse(Networking.isPortAvailable(boundPort));
ss.close();
}
//just some system health-checks... localhost may not resolve properly elsewhere
//(e.g. in geobytes, AddressableLocation, etc) if this does not work
@Test
public void testLocalhostIpLookup() throws UnknownHostException {
InetAddress address = InetAddress.getByName("127.0.0.1");
Assert.assertEquals(127, address.getAddress()[0]);
Assert.assertTrue(Networking.isPrivateSubnet(address));
}
@Test
public void testLocalhostLookup() throws UnknownHostException {
InetAddress address = InetAddress.getByName("localhost");
Assert.assertEquals(127, address.getAddress()[0]);
Assert.assertTrue(Networking.isPrivateSubnet(address));
Assert.assertEquals("127.0.0.1", address.getHostAddress());
}
@Test
public void test10_x_x_xSubnetPrivate() throws UnknownHostException {
InetAddress address = InetAddress.getByAddress(new byte[] { 10, 0, 0, 1 });
Assert.assertTrue(Networking.isPrivateSubnet(address));
}
@Test
public void test172_16_x_xSubnetPrivate() throws UnknownHostException {
InetAddress address = InetAddress.getByAddress(new byte[] { (byte)172, 31, (byte)255, (byte)255 });
Assert.assertTrue(Networking.isPrivateSubnet(address));
}
@Test(groups="Integration")
public void testBogusHostnameUnresolvable() {
Assert.assertEquals(Networking.resolve("bogus-hostname-"+Identifiers.makeRandomId(8)), null);
}
@Test(groups="Integration")
public void testIsReachable() throws Exception {
ServerSocket serverSocket = null;
for (int i = 40000; i < 40100; i++) {
try {
serverSocket = new ServerSocket(i);
} catch (IOException e) {
// try next number
}
}
assertNotNull(serverSocket, "No ports available in range!");
try {
HostAndPort hostAndPort = HostAndPort.fromParts(serverSocket.getInetAddress().getHostAddress(), serverSocket.getLocalPort());
assertTrue(Networking.isReachable(hostAndPort));
serverSocket.close();
assertFalse(Networking.isReachable(hostAndPort));
} finally {
serverSocket.close();
}
}
}