package javax.jmdns.test;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.*;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.ServiceTypeListener;
import javax.jmdns.impl.constants.DNSConstants;
import junit.framework.Assert;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
public class JmDNSTest {
@SuppressWarnings("unused")
private ServiceTypeListener typeListenerMock;
private ServiceListener serviceListenerMock;
private ServiceInfo service;
private final static String serviceKey = "srvname"; // Max 9 chars
@Before
public void setup() {
boolean log = false;
if (log) {
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
for (Enumeration<String> enumerator = LogManager.getLogManager().getLoggerNames(); enumerator.hasMoreElements();) {
String loggerName = enumerator.nextElement();
Logger logger = Logger.getLogger(loggerName);
logger.addHandler(handler);
logger.setLevel(Level.FINEST);
}
}
String text = "Test hypothetical web server";
Map<String, byte[]> properties = new HashMap<String, byte[]>();
properties.put(serviceKey, text.getBytes());
service = ServiceInfo.create("_html._tcp.local.", "apache-someuniqueid", 80, 0, 0, true, properties);
typeListenerMock = createMock(ServiceTypeListener.class);
serviceListenerMock = createNiceMock("ServiceListener", ServiceListener.class);
}
@Test
public void testCreate() throws IOException {
System.out.println("Unit Test: testCreate()");
JmDNS registry = JmDNS.create();
registry.close();
}
@Test
public void testCreateINet() throws IOException {
System.out.println("Unit Test: testCreateINet()");
JmDNS registry = JmDNS.create(InetAddress.getLocalHost());
// assertEquals("We did not register on the local host inet:", InetAddress.getLocalHost(), registry.getInterface());
registry.close();
}
@Test
public void testRegisterService() throws IOException {
System.out.println("Unit Test: testRegisterService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testUnregisterService() throws IOException, InterruptedException {
System.out.println("Unit Test: testUnregisterService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
ServiceInfo[] services = registry.list(service.getType());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
// now unregister and make sure it's gone
registry.unregisterService(services[0]);
// According to the spec the record disappears from the cache 1s after it has been unregistered
// without sleeping for a while, the service would not be unregistered fully
Thread.sleep(1500);
services = registry.list(service.getType());
assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testRegisterServiceTwice() throws IOException {
System.out.println("Unit Test: testRegisterService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
// This should cause an exception
registry.registerService(service);
fail("Registering the same service info should fail.");
} catch (IllegalStateException exception) {
// Expected exception.
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testUnregisterAndReregisterService() throws IOException, InterruptedException {
System.out.println("Unit Test: testUnregisterAndReregisterService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
ServiceInfo[] services = registry.list(service.getType());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
// now unregister and make sure it's gone
registry.unregisterService(services[0]);
// According to the spec the record disappears from the cache 1s after it has been unregistered
// without sleeping for a while, the service would not be unregistered fully
Thread.sleep(1500);
services = registry.list(service.getType());
assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
registry.registerService(service);
Thread.sleep(5000);
services = registry.list(service.getType());
assertTrue("We should see the service we just reregistered: ", services != null && services.length > 0);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testQueryMyService() throws IOException {
System.out.println("Unit Test: testQueryMyService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
ServiceInfo queriedService = registry.getServiceInfo(service.getType(), service.getName());
assertEquals(service, queriedService);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListMyService() throws IOException {
System.out.println("Unit Test: testListMyService()");
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
ServiceInfo[] services = registry.list(service.getType());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListMyServiceIPV6() throws IOException {
System.out.println("Unit Test: testListMyServiceIPV6()");
JmDNS registry = null;
try {
InetAddress address = InetAddress.getLocalHost();
NetworkInterface interfaze = NetworkInterface.getByInetAddress(address);
for (Enumeration<InetAddress> iaenum = interfaze.getInetAddresses(); iaenum.hasMoreElements();) {
InetAddress interfaceAddress = iaenum.nextElement();
if (interfaceAddress instanceof Inet6Address) {
address = interfaceAddress;
}
}
registry = JmDNS.create(address);
registry.registerService(service);
ServiceInfo[] services = registry.list(service.getType());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListenForMyService() throws IOException {
System.out.println("Unit Test: testListenForMyService()");
JmDNS registry = null;
try {
Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
// Add an expectation that the listener interface will be called once capture the object so I can verify it separately.
serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
EasyMock.replay(serviceListenerMock);
// EasyMock.makeThreadSafe(serviceListenerMock, false);
registry = JmDNS.create();
registry.addServiceListener(service.getType(), serviceListenerMock);
registry.registerService(service);
// We get the service added event when we register the service. However the service has not been resolved at this point.
// The info associated with the event only has the minimum information i.e. name and type.
assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
assertEquals("We did not get the right name for the added service:", service.getName(), info.getName());
assertEquals("We did not get the right type for the added service:", service.getType(), info.getType());
assertEquals("We did not get the right fully qualified name for the added service:", service.getQualifiedName(), info.getQualifiedName());
// assertEquals("We should not get the server for the added service:", "", info.getServer());
// assertEquals("We should not get the address for the added service:", null, info.getAddress());
// assertEquals("We should not get the HostAddress for the added service:", "", info.getHostAddress());
// assertEquals("We should not get the InetAddress for the added service:", null, info.getInetAddress());
// assertEquals("We should not get the NiceTextString for the added service:", "", info.getNiceTextString());
// assertEquals("We should not get the Priority for the added service:", 0, info.getPriority());
// assertFalse("We should not get the PropertyNames for the added service:", info.getPropertyNames().hasMoreElements());
// assertEquals("We should not get the TextBytes for the added service:", 0, info.getTextBytes().length);
// assertEquals("We should not get the TextString for the added service:", null, info.getTextString());
// assertEquals("We should not get the Weight for the added service:", 0, info.getWeight());
// assertNotSame("We should not get the URL for the added service:", "", info.getURL());
registry.requestServiceInfo(service.getType(), service.getName());
assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
verify(serviceListenerMock);
ServiceInfo resolvedInfo = capServiceResolvedEvent.getValue().getInfo();
assertEquals("Did not get the expected service info: ", service, resolvedInfo);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListenForMyServiceAndList() throws IOException {
System.out.println("Unit Test: testListenForMyServiceAndList()");
JmDNS registry = null;
try {
Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
// Expect the listener to be called once and capture the result
serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
replay(serviceListenerMock);
registry = JmDNS.create();
registry.addServiceListener(service.getType(), serviceListenerMock);
registry.registerService(service);
// We get the service added event when we register the service. However the service has not been resolved at this point.
// The info associated with the event only has the minimum information i.e. name and type.
assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
assertEquals("We did not get the right name for the resolved service:", service.getName(), info.getName());
assertEquals("We did not get the right type for the resolved service:", service.getType(), info.getType());
// This will force the resolution of the service which in turn will get the listener called with a service resolved event.
// The info associated with a service resolved event has all the information available.
// Which in turn populates the ServiceInfo opbjects returned by JmDNS.list.
ServiceInfo[] services = registry.list(info.getType());
assertEquals("We did not get the expected number of services: ", 1, services.length);
assertEquals("The service returned was not the one expected", service, services[0]);
assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
verify(serviceListenerMock);
ServiceInfo resolvedInfo = capServiceResolvedEvent.getValue().getInfo();
assertEquals("Did not get the expected service info: ", service, resolvedInfo);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListenForServiceOnOtherRegistry() throws IOException {
System.out.println("Unit Test: testListenForServiceOnOtherRegistry()");
JmDNS registry = null;
JmDNS newServiceRegistry = null;
try {
Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
// Expect the listener to be called once and capture the result
serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
replay(serviceListenerMock);
registry = JmDNS.create();
registry.addServiceListener(service.getType(), serviceListenerMock);
//
newServiceRegistry = JmDNS.create();
newServiceRegistry.registerService(service);
// We get the service added event when we register the service. However the service has not been resolved at this point.
// The info associated with the event only has the minimum information i.e. name and type.
assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
assertEquals("We did not get the right name for the resolved service:", service.getName(), info.getName());
assertEquals("We did not get the right type for the resolved service:", service.getType(), info.getType());
// We get the service added event when we register the service. However the service has not been resolved at this point.
// The info associated with the event only has the minimum information i.e. name and type.
assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
verify(serviceListenerMock);
Object result = capServiceResolvedEvent.getValue().getInfo();
assertEquals("Did not get the expected service info: ", service, result);
} finally {
if (registry != null) registry.close();
if (newServiceRegistry != null) newServiceRegistry.close();
}
}
@Test
public void testWaitAndQueryForServiceOnOtherRegistry() throws IOException {
System.out.println("Unit Test: testWaitAndQueryForServiceOnOtherRegistry()");
JmDNS registry = null;
JmDNS newServiceRegistry = null;
try {
newServiceRegistry = JmDNS.create();
registry = JmDNS.create();
registry.registerService(service);
ServiceInfo fetchedService = newServiceRegistry.getServiceInfo(service.getType(), service.getName());
assertEquals("Did not get the expected service info: ", service, fetchedService);
} finally {
if (registry != null) registry.close();
if (newServiceRegistry != null) newServiceRegistry.close();
}
}
@Test
public void testRegisterAndListServiceOnOtherRegistry() throws IOException, InterruptedException {
System.out.println("Unit Test: testRegisterAndListServiceOnOtherRegistry()");
JmDNS registry = null;
JmDNS newServiceRegistry = null;
try {
registry = JmDNS.create("Registry");
registry.registerService(service);
newServiceRegistry = JmDNS.create("Listener");
Thread.sleep(6000);
ServiceInfo[] fetchedServices = newServiceRegistry.list(service.getType());
assertEquals("Did not get the expected services listed:", 1, fetchedServices.length);
assertEquals("Did not get the expected service type:", service.getType(), fetchedServices[0].getType());
assertEquals("Did not get the expected service name:", service.getName(), fetchedServices[0].getName());
assertEquals("Did not get the expected service fully qualified name:", service.getQualifiedName(), fetchedServices[0].getQualifiedName());
newServiceRegistry.getServiceInfo(service.getType(), service.getName());
assertEquals("Did not get the expected service info: ", service, fetchedServices[0]);
registry.close();
registry = null;
// According to the spec the record disappears from the cache 1s after it has been unregistered
// without sleeping for a while, the service would not be unregistered fully
Thread.sleep(1500);
fetchedServices = newServiceRegistry.list(service.getType());
assertEquals("The service was not cancelled after the close:", 0, fetchedServices.length);
} finally {
if (registry != null) registry.close();
if (newServiceRegistry != null) newServiceRegistry.close();
}
}
public static final class Receive extends Thread {
MulticastSocket _socket;
DatagramPacket _in;
public Receive(MulticastSocket socket, DatagramPacket in) {
super("Test Receive Multicast");
_socket = socket;
_in = in;
}
@Override
public void run() {
try {
_socket.receive(_in);
} catch (IOException exception) {
// Ignore
}
}
public boolean waitForReceive() {
try {
this.join(1000);
} catch (InterruptedException exception) {
// Ignore
}
return this.isAlive();
}
}
private final static int MPORT = 8053;
@Test
public void testTwoMulticastPortsAtOnce() throws UnknownHostException, IOException {
System.out.println("Unit Test: testTwoMulticastPortsAtOnce()");
MulticastSocket firstSocket = null;
MulticastSocket secondSocket = null;
try {
String firstMessage = "ping";
String secondMessage = "pong";
InetAddress someInet = InetAddress.getByName(DNSConstants.MDNS_GROUP);
firstSocket = new MulticastSocket(MPORT);
secondSocket = new MulticastSocket(MPORT);
firstSocket.joinGroup(someInet);
secondSocket.joinGroup(someInet);
//
DatagramPacket out = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
DatagramPacket inFirst = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
DatagramPacket inSecond = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
Receive receiveSecond = new Receive(secondSocket, inSecond);
receiveSecond.start();
Receive receiveFirst = new Receive(firstSocket, inSecond);
receiveFirst.start();
firstSocket.send(out);
if (receiveSecond.waitForReceive()) {
Assert.fail("We did not receive the data in the second socket");
}
String fromFirst = new String(inSecond.getData(), "UTF-8");
assertEquals("Expected the second socket to recieve the same message the first socket sent", firstMessage, fromFirst);
// Make sure the first socket had read its own message
if (receiveSecond.waitForReceive()) {
Assert.fail("We did not receive the data in the first socket");
}
// Reverse the roles
out = new DatagramPacket(secondMessage.getBytes("UTF-8"), secondMessage.length(), someInet, MPORT);
inFirst = new DatagramPacket(secondMessage.getBytes("UTF-8"), secondMessage.length(), someInet, MPORT);
receiveFirst = new Receive(firstSocket, inSecond);
receiveFirst.start();
secondSocket.send(out);
if (receiveFirst.waitForReceive()) {
Assert.fail("We did not receive the data in the first socket");
}
String fromSecond = new String(inFirst.getData(), "UTF-8");
assertEquals("Expected the first socket to recieve the same message the second socket sent", secondMessage, fromSecond);
} finally {
if (firstSocket != null) firstSocket.close();
if (secondSocket != null) secondSocket.close();
}
}
@Test
public void testListMyServiceWithToLowerCase() throws IOException, InterruptedException {
System.out.println("Unit Test: testListMyServiceWithToLowerCase()");
String text = "Test hypothetical web server";
Map<String, byte[]> properties = new HashMap<String, byte[]>();
properties.put(serviceKey, text.getBytes());
service = ServiceInfo.create("_HtmL._TcP.lOcAl.", "apache-someUniqueid", 80, 0, 0, true, properties);
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
// with toLowerCase
ServiceInfo[] services = registry.list(service.getType().toLowerCase());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
// now unregister and make sure it's gone
registry.unregisterService(services[0]);
// According to the spec the record disappears from the cache 1s after it has been unregistered
// without sleeping for a while, the service would not be unregistered fully
Thread.sleep(1500);
services = registry.list(service.getType().toLowerCase());
assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
} finally {
if (registry != null) registry.close();
}
}
@Test
public void testListMyServiceWithoutLowerCase() throws IOException, InterruptedException {
System.out.println("Unit Test: testListMyServiceWithoutLowerCase()");
String text = "Test hypothetical web server";
Map<String, byte[]> properties = new HashMap<String, byte[]>();
properties.put(serviceKey, text.getBytes());
service = ServiceInfo.create("_HtmL._TcP.lOcAl.", "apache-someUniqueid", 80, 0, 0, true, properties);
JmDNS registry = null;
try {
registry = JmDNS.create();
registry.registerService(service);
// without toLowerCase
ServiceInfo[] services = registry.list(service.getType());
assertEquals("We should see the service we just registered: ", 1, services.length);
assertEquals(service, services[0]);
// now unregister and make sure it's gone
registry.unregisterService(services[0]);
// According to the spec the record disappears from the cache 1s after it has been unregistered
// without sleeping for a while, the service would not be unregistered fully
Thread.sleep(1500);
services = registry.list(service.getType());
assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
} finally {
if (registry != null) registry.close();
}
}
}