Make Multicast tests more robust (#9053)

Motivation:

86dd388637 reverted the usage of IPv6 Multicast test. This commit makes the whole multicast testing a lot more robust by selecting the correct interface in any case and also reverts the `@Ignore`

Modifications:

- More robust multicast testing by selecting the right NetworkInterface
- Remove the `@Ignore` again for the IPv6 test

Result:

More robust multicast testing
This commit is contained in:
Norman Maurer 2019-04-15 21:39:31 +02:00
parent 635fc9eae0
commit 438a4d5467
2 changed files with 70 additions and 31 deletions

View File

@ -16,16 +16,9 @@
package io.netty.testsuite.transport.socket;
import io.netty.channel.socket.InternetProtocolFamily;
import org.junit.Ignore;
public class DatagramMulticastIPv6Test extends DatagramMulticastTest {
@Ignore("Fails on some systems")
@Override
public void testMulticast() throws Throwable {
super.testMulticast();
}
@Override
protected InternetProtocolFamily internetProtocolFamily() {
return InternetProtocolFamily.IPv6;

View File

@ -31,10 +31,15 @@ import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@ -50,6 +55,10 @@ public class DatagramMulticastTest extends AbstractDatagramTest {
}
public void testMulticast(Bootstrap sb, Bootstrap cb) throws Throwable {
NetworkInterface iface = multicastNetworkInterface();
Assume.assumeNotNull("No NetworkInterface found that supports multicast and " +
internetProtocolFamily(), iface);
MulticastTestHandler mhandler = new MulticastTestHandler();
sb.handler(new SimpleChannelInboundHandler<Object>() {
@ -61,29 +70,27 @@ public class DatagramMulticastTest extends AbstractDatagramTest {
cb.handler(mhandler);
sb.option(ChannelOption.IP_MULTICAST_IF, NetUtil.LOOPBACK_IF);
sb.option(ChannelOption.IP_MULTICAST_IF, iface);
sb.option(ChannelOption.SO_REUSEADDR, true);
cb.option(ChannelOption.IP_MULTICAST_IF, NetUtil.LOOPBACK_IF);
cb.option(ChannelOption.IP_MULTICAST_IF, iface);
cb.option(ChannelOption.SO_REUSEADDR, true);
Channel sc = sb.bind(newSocketAddress()).sync().channel();
Channel sc = sb.bind(newSocketAddress(iface)).sync().channel();
InetSocketAddress addr = (InetSocketAddress) sc.localAddress();
cb.localAddress(addr.getPort());
DatagramChannel cc = (DatagramChannel) cb.bind().sync().channel();
String group = internetProtocolFamily() == InternetProtocolFamily.IPv4 ?
"230.0.0.1" : "FF01:0:0:0:0:0:0:101";
InetSocketAddress groupAddress = SocketUtils.socketAddress(group, addr.getPort());
InetSocketAddress groupAddress = SocketUtils.socketAddress(groupAddress(), addr.getPort());
cc.joinGroup(groupAddress, NetUtil.LOOPBACK_IF).sync();
cc.joinGroup(groupAddress, iface).sync();
sc.writeAndFlush(new DatagramPacket(Unpooled.copyInt(1), groupAddress)).sync();
assertTrue(mhandler.await());
// leave the group
cc.leaveGroup(groupAddress, NetUtil.LOOPBACK_IF).sync();
cc.leaveGroup(groupAddress, iface).sync();
// sleep a second to make sure we left the group
Thread.sleep(1000);
@ -126,24 +133,63 @@ public class DatagramMulticastTest extends AbstractDatagramTest {
}
}
@Before
public void assumeInternetProtocolFamilySupported() {
Assume.assumeTrue(isSupported(internetProtocolFamily() == InternetProtocolFamily.IPv4 ?
Inet4Address.class : Inet6Address.class));
}
private static boolean isSupported(Class<? extends InetAddress> addressType) {
Enumeration<InetAddress> addresses = NetUtil.LOOPBACK_IF.getInetAddresses();
while (addresses.hasMoreElements()) {
if (addressType.isAssignableFrom(addresses.nextElement().getClass())) {
return true;
}
}
return false;
}
@Override
protected List<TestsuitePermutation.BootstrapComboFactory<Bootstrap, Bootstrap>> newFactories() {
return SocketTestPermutation.INSTANCE.datagram(internetProtocolFamily());
}
private InetSocketAddress newAnySocketAddress() throws UnknownHostException {
switch (internetProtocolFamily()) {
case IPv4:
return new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0);
case IPv6:
return new InetSocketAddress(InetAddress.getByName("::"), 0);
default:
throw new AssertionError();
}
}
private InetSocketAddress newSocketAddress(NetworkInterface iface) {
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (internetProtocolFamily().addressType().isAssignableFrom(address.getClass())) {
return new InetSocketAddress(address, 0);
}
}
throw new AssertionError();
}
private NetworkInterface multicastNetworkInterface() throws IOException {
Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
if (iface.isUp() && iface.supportsMulticast()) {
Enumeration<InetAddress> addresses = iface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress address = addresses.nextElement();
if (internetProtocolFamily().addressType().isAssignableFrom(address.getClass())) {
MulticastSocket socket = new MulticastSocket(newAnySocketAddress());
socket.setReuseAddress(true);
socket.setNetworkInterface(iface);
try {
socket.send(new java.net.DatagramPacket(new byte[] { 1, 2, 3, 4 }, 4,
new InetSocketAddress(groupAddress(), 12345)));
return iface;
} catch (IOException ignore) {
// Try the next interface
} finally {
socket.close();
}
}
}
}
}
return null;
}
private String groupAddress() {
return internetProtocolFamily() == InternetProtocolFamily.IPv4 ?
"230.0.0.1" : "FF01:0:0:0:0:0:0:101";
}
}