View Javadoc

1   package javax.jmdns.test;
2   
3   import static junit.framework.Assert.assertEquals;
4   import static junit.framework.Assert.assertTrue;
5   import static junit.framework.Assert.*;
6   import static org.easymock.EasyMock.capture;
7   import static org.easymock.EasyMock.createMock;
8   import static org.easymock.EasyMock.createNiceMock;
9   import static org.easymock.EasyMock.replay;
10  import static org.easymock.EasyMock.verify;
11  
12  import java.io.IOException;
13  import java.net.DatagramPacket;
14  import java.net.InetAddress;
15  import java.net.Inet6Address;
16  import java.net.MulticastSocket;
17  import java.net.NetworkInterface;
18  import java.net.UnknownHostException;
19  import java.util.Enumeration;
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.logging.ConsoleHandler;
23  import java.util.logging.Level;
24  import java.util.logging.LogManager;
25  import java.util.logging.Logger;
26  
27  import javax.jmdns.JmDNS;
28  import javax.jmdns.ServiceEvent;
29  import javax.jmdns.ServiceInfo;
30  import javax.jmdns.ServiceListener;
31  import javax.jmdns.ServiceTypeListener;
32  import javax.jmdns.impl.constants.DNSConstants;
33  
34  import junit.framework.Assert;
35  
36  import org.easymock.Capture;
37  import org.easymock.EasyMock;
38  import org.junit.Before;
39  import org.junit.Test;
40  
41  public class JmDNSTest {
42  
43      @SuppressWarnings("unused")
44      private ServiceTypeListener typeListenerMock;
45      private ServiceListener     serviceListenerMock;
46      private ServiceInfo         service;
47  
48      private final static String serviceKey = "srvname"; // Max 9 chars
49  
50      @Before
51      public void setup() {
52          boolean log = false;
53          if (log) {
54              ConsoleHandler handler = new ConsoleHandler();
55              handler.setLevel(Level.FINEST);
56              for (Enumeration<String> enumerator = LogManager.getLogManager().getLoggerNames(); enumerator.hasMoreElements();) {
57                  String loggerName = enumerator.nextElement();
58                  Logger logger = Logger.getLogger(loggerName);
59                  logger.addHandler(handler);
60                  logger.setLevel(Level.FINEST);
61              }
62          }
63  
64          String text = "Test hypothetical web server";
65          Map<String, byte[]> properties = new HashMap<String, byte[]>();
66          properties.put(serviceKey, text.getBytes());
67          service = ServiceInfo.create("_html._tcp.local.", "apache-someuniqueid", 80, 0, 0, true, properties);
68          typeListenerMock = createMock(ServiceTypeListener.class);
69          serviceListenerMock = createNiceMock("ServiceListener", ServiceListener.class);
70      }
71  
72      @Test
73      public void testCreate() throws IOException {
74          System.out.println("Unit Test: testCreate()");
75          JmDNS registry = JmDNS.create();
76          registry.close();
77      }
78  
79      @Test
80      public void testCreateINet() throws IOException {
81          System.out.println("Unit Test: testCreateINet()");
82          JmDNS registry = JmDNS.create(InetAddress.getLocalHost());
83          // assertEquals("We did not register on the local host inet:", InetAddress.getLocalHost(), registry.getInterface());
84          registry.close();
85      }
86  
87      @Test
88      public void testRegisterService() throws IOException {
89          System.out.println("Unit Test: testRegisterService()");
90          JmDNS registry = null;
91          try {
92              registry = JmDNS.create();
93              registry.registerService(service);
94          } finally {
95              if (registry != null) registry.close();
96          }
97      }
98  
99      @Test
100     public void testUnregisterService() throws IOException, InterruptedException {
101         System.out.println("Unit Test: testUnregisterService()");
102         JmDNS registry = null;
103         try {
104             registry = JmDNS.create();
105             registry.registerService(service);
106 
107             ServiceInfo[] services = registry.list(service.getType());
108             assertEquals("We should see the service we just registered: ", 1, services.length);
109             assertEquals(service, services[0]);
110 
111             // now unregister and make sure it's gone
112             registry.unregisterService(services[0]);
113 
114             // According to the spec the record disappears from the cache 1s after it has been unregistered
115             // without sleeping for a while, the service would not be unregistered fully
116             Thread.sleep(1500);
117 
118             services = registry.list(service.getType());
119             assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
120         } finally {
121             if (registry != null) registry.close();
122         }
123     }
124 
125     @Test
126     public void testRegisterServiceTwice() throws IOException {
127         System.out.println("Unit Test: testRegisterService()");
128         JmDNS registry = null;
129         try {
130             registry = JmDNS.create();
131             registry.registerService(service);
132             // This should cause an exception
133             registry.registerService(service);
134             fail("Registering the same service info should fail.");
135         } catch (IllegalStateException exception) {
136             // Expected exception.
137         } finally {
138             if (registry != null) registry.close();
139         }
140     }
141 
142     @Test
143     public void testUnregisterAndReregisterService() throws IOException, InterruptedException {
144         System.out.println("Unit Test: testUnregisterAndReregisterService()");
145         JmDNS registry = null;
146         try {
147             registry = JmDNS.create();
148             registry.registerService(service);
149 
150             ServiceInfo[] services = registry.list(service.getType());
151             assertEquals("We should see the service we just registered: ", 1, services.length);
152             assertEquals(service, services[0]);
153 
154             // now unregister and make sure it's gone
155             registry.unregisterService(services[0]);
156 
157             // According to the spec the record disappears from the cache 1s after it has been unregistered
158             // without sleeping for a while, the service would not be unregistered fully
159             Thread.sleep(1500);
160 
161             services = registry.list(service.getType());
162             assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
163 
164             registry.registerService(service);
165             Thread.sleep(5000);
166             services = registry.list(service.getType());
167             assertTrue("We should see the service we just reregistered: ", services != null && services.length > 0);
168         } finally {
169             if (registry != null) registry.close();
170         }
171     }
172 
173     @Test
174     public void testQueryMyService() throws IOException {
175         System.out.println("Unit Test: testQueryMyService()");
176         JmDNS registry = null;
177         try {
178             registry = JmDNS.create();
179             registry.registerService(service);
180             ServiceInfo queriedService = registry.getServiceInfo(service.getType(), service.getName());
181             assertEquals(service, queriedService);
182         } finally {
183             if (registry != null) registry.close();
184         }
185     }
186 
187     @Test
188     public void testListMyService() throws IOException {
189         System.out.println("Unit Test: testListMyService()");
190         JmDNS registry = null;
191         try {
192             registry = JmDNS.create();
193             registry.registerService(service);
194             ServiceInfo[] services = registry.list(service.getType());
195             assertEquals("We should see the service we just registered: ", 1, services.length);
196             assertEquals(service, services[0]);
197         } finally {
198             if (registry != null) registry.close();
199         }
200     }
201 
202     @Test
203     public void testListMyServiceIPV6() throws IOException {
204         System.out.println("Unit Test: testListMyServiceIPV6()");
205         JmDNS registry = null;
206         try {
207             InetAddress address = InetAddress.getLocalHost();
208             NetworkInterface interfaze = NetworkInterface.getByInetAddress(address);
209             for (Enumeration<InetAddress> iaenum = interfaze.getInetAddresses(); iaenum.hasMoreElements();) {
210                 InetAddress interfaceAddress = iaenum.nextElement();
211                 if (interfaceAddress instanceof Inet6Address) {
212                     address = interfaceAddress;
213                 }
214             }
215             registry = JmDNS.create(address);
216             registry.registerService(service);
217             ServiceInfo[] services = registry.list(service.getType());
218             assertEquals("We should see the service we just registered: ", 1, services.length);
219             assertEquals(service, services[0]);
220         } finally {
221             if (registry != null) registry.close();
222         }
223     }
224 
225     @Test
226     public void testListenForMyService() throws IOException {
227         System.out.println("Unit Test: testListenForMyService()");
228         JmDNS registry = null;
229         try {
230             Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
231             Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
232             // Add an expectation that the listener interface will be called once capture the object so I can verify it separately.
233             serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
234             serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
235             EasyMock.replay(serviceListenerMock);
236             // EasyMock.makeThreadSafe(serviceListenerMock, false);
237 
238             registry = JmDNS.create();
239 
240             registry.addServiceListener(service.getType(), serviceListenerMock);
241 
242             registry.registerService(service);
243 
244             // We get the service added event when we register the service. However the service has not been resolved at this point.
245             // The info associated with the event only has the minimum information i.e. name and type.
246             assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
247             ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
248             assertEquals("We did not get the right name for the added service:", service.getName(), info.getName());
249             assertEquals("We did not get the right type for the added service:", service.getType(), info.getType());
250             assertEquals("We did not get the right fully qualified name for the added service:", service.getQualifiedName(), info.getQualifiedName());
251 
252             // assertEquals("We should not get the server for the added service:", "", info.getServer());
253             // assertEquals("We should not get the address for the added service:", null, info.getAddress());
254             // assertEquals("We should not get the HostAddress for the added service:", "", info.getHostAddress());
255             // assertEquals("We should not get the InetAddress for the added service:", null, info.getInetAddress());
256             // assertEquals("We should not get the NiceTextString for the added service:", "", info.getNiceTextString());
257             // assertEquals("We should not get the Priority for the added service:", 0, info.getPriority());
258             // assertFalse("We should not get the PropertyNames for the added service:", info.getPropertyNames().hasMoreElements());
259             // assertEquals("We should not get the TextBytes for the added service:", 0, info.getTextBytes().length);
260             // assertEquals("We should not get the TextString for the added service:", null, info.getTextString());
261             // assertEquals("We should not get the Weight for the added service:", 0, info.getWeight());
262             // assertNotSame("We should not get the URL for the added service:", "", info.getURL());
263 
264             registry.requestServiceInfo(service.getType(), service.getName());
265 
266             assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
267             verify(serviceListenerMock);
268             ServiceInfo resolvedInfo = capServiceResolvedEvent.getValue().getInfo();
269             assertEquals("Did not get the expected service info: ", service, resolvedInfo);
270         } finally {
271             if (registry != null) registry.close();
272         }
273     }
274 
275     @Test
276     public void testListenForMyServiceAndList() throws IOException {
277         System.out.println("Unit Test: testListenForMyServiceAndList()");
278         JmDNS registry = null;
279         try {
280             Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
281             Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
282             // Expect the listener to be called once and capture the result
283             serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
284             serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
285             replay(serviceListenerMock);
286 
287             registry = JmDNS.create();
288             registry.addServiceListener(service.getType(), serviceListenerMock);
289             registry.registerService(service);
290 
291             // We get the service added event when we register the service. However the service has not been resolved at this point.
292             // The info associated with the event only has the minimum information i.e. name and type.
293             assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
294 
295             ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
296             assertEquals("We did not get the right name for the resolved service:", service.getName(), info.getName());
297             assertEquals("We did not get the right type for the resolved service:", service.getType(), info.getType());
298 
299             // This will force the resolution of the service which in turn will get the listener called with a service resolved event.
300             // The info associated with a service resolved event has all the information available.
301             // Which in turn populates the ServiceInfo opbjects returned by JmDNS.list.
302             ServiceInfo[] services = registry.list(info.getType());
303             assertEquals("We did not get the expected number of services: ", 1, services.length);
304             assertEquals("The service returned was not the one expected", service, services[0]);
305 
306             assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
307             verify(serviceListenerMock);
308             ServiceInfo resolvedInfo = capServiceResolvedEvent.getValue().getInfo();
309             assertEquals("Did not get the expected service info: ", service, resolvedInfo);
310         } finally {
311             if (registry != null) registry.close();
312         }
313     }
314 
315     @Test
316     public void testListenForServiceOnOtherRegistry() throws IOException {
317         System.out.println("Unit Test: testListenForServiceOnOtherRegistry()");
318         JmDNS registry = null;
319         JmDNS newServiceRegistry = null;
320         try {
321             Capture<ServiceEvent> capServiceAddedEvent = new Capture<ServiceEvent>();
322             Capture<ServiceEvent> capServiceResolvedEvent = new Capture<ServiceEvent>();
323             // Expect the listener to be called once and capture the result
324             serviceListenerMock.serviceAdded(capture(capServiceAddedEvent));
325             serviceListenerMock.serviceResolved(capture(capServiceResolvedEvent));
326             replay(serviceListenerMock);
327 
328             registry = JmDNS.create();
329             registry.addServiceListener(service.getType(), serviceListenerMock);
330             //
331             newServiceRegistry = JmDNS.create();
332             newServiceRegistry.registerService(service);
333 
334             // We get the service added event when we register the service. However the service has not been resolved at this point.
335             // The info associated with the event only has the minimum information i.e. name and type.
336             assertTrue("We did not get the service added event.", capServiceAddedEvent.hasCaptured());
337             ServiceInfo info = capServiceAddedEvent.getValue().getInfo();
338             assertEquals("We did not get the right name for the resolved service:", service.getName(), info.getName());
339             assertEquals("We did not get the right type for the resolved service:", service.getType(), info.getType());
340             // We get the service added event when we register the service. However the service has not been resolved at this point.
341             // The info associated with the event only has the minimum information i.e. name and type.
342             assertTrue("We did not get the service resolved event.", capServiceResolvedEvent.hasCaptured());
343             verify(serviceListenerMock);
344             Object result = capServiceResolvedEvent.getValue().getInfo();
345             assertEquals("Did not get the expected service info: ", service, result);
346         } finally {
347             if (registry != null) registry.close();
348             if (newServiceRegistry != null) newServiceRegistry.close();
349         }
350     }
351 
352     @Test
353     public void testWaitAndQueryForServiceOnOtherRegistry() throws IOException {
354         System.out.println("Unit Test: testWaitAndQueryForServiceOnOtherRegistry()");
355         JmDNS registry = null;
356         JmDNS newServiceRegistry = null;
357         try {
358             newServiceRegistry = JmDNS.create();
359             registry = JmDNS.create();
360 
361             registry.registerService(service);
362 
363             ServiceInfo fetchedService = newServiceRegistry.getServiceInfo(service.getType(), service.getName());
364 
365             assertEquals("Did not get the expected service info: ", service, fetchedService);
366         } finally {
367             if (registry != null) registry.close();
368             if (newServiceRegistry != null) newServiceRegistry.close();
369         }
370     }
371 
372     @Test
373     public void testRegisterAndListServiceOnOtherRegistry() throws IOException, InterruptedException {
374         System.out.println("Unit Test: testRegisterAndListServiceOnOtherRegistry()");
375         JmDNS registry = null;
376         JmDNS newServiceRegistry = null;
377         try {
378             registry = JmDNS.create("Registry");
379             registry.registerService(service);
380 
381             newServiceRegistry = JmDNS.create("Listener");
382             Thread.sleep(6000);
383             ServiceInfo[] fetchedServices = newServiceRegistry.list(service.getType());
384             assertEquals("Did not get the expected services listed:", 1, fetchedServices.length);
385             assertEquals("Did not get the expected service type:", service.getType(), fetchedServices[0].getType());
386             assertEquals("Did not get the expected service name:", service.getName(), fetchedServices[0].getName());
387             assertEquals("Did not get the expected service fully qualified name:", service.getQualifiedName(), fetchedServices[0].getQualifiedName());
388             newServiceRegistry.getServiceInfo(service.getType(), service.getName());
389 
390             assertEquals("Did not get the expected service info: ", service, fetchedServices[0]);
391             registry.close();
392             registry = null;
393             // According to the spec the record disappears from the cache 1s after it has been unregistered
394             // without sleeping for a while, the service would not be unregistered fully
395             Thread.sleep(1500);
396             fetchedServices = newServiceRegistry.list(service.getType());
397             assertEquals("The service was not cancelled after the close:", 0, fetchedServices.length);
398         } finally {
399             if (registry != null) registry.close();
400             if (newServiceRegistry != null) newServiceRegistry.close();
401         }
402     }
403 
404     public static final class Receive extends Thread {
405         MulticastSocket _socket;
406         DatagramPacket  _in;
407 
408         public Receive(MulticastSocket socket, DatagramPacket in) {
409             super("Test Receive Multicast");
410             _socket = socket;
411             _in = in;
412         }
413 
414         @Override
415         public void run() {
416             try {
417                 _socket.receive(_in);
418             } catch (IOException exception) {
419                 // Ignore
420             }
421         }
422 
423         public boolean waitForReceive() {
424             try {
425                 this.join(1000);
426             } catch (InterruptedException exception) {
427                 // Ignore
428             }
429             return this.isAlive();
430         }
431 
432     }
433 
434     private final static int MPORT = 8053;
435 
436     @Test
437     public void testTwoMulticastPortsAtOnce() throws UnknownHostException, IOException {
438         System.out.println("Unit Test: testTwoMulticastPortsAtOnce()");
439         MulticastSocket firstSocket = null;
440         MulticastSocket secondSocket = null;
441         try {
442             String firstMessage = "ping";
443             String secondMessage = "pong";
444             InetAddress someInet = InetAddress.getByName(DNSConstants.MDNS_GROUP);
445             firstSocket = new MulticastSocket(MPORT);
446             secondSocket = new MulticastSocket(MPORT);
447 
448             firstSocket.joinGroup(someInet);
449             secondSocket.joinGroup(someInet);
450             //
451             DatagramPacket out = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
452             DatagramPacket inFirst = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
453             DatagramPacket inSecond = new DatagramPacket(firstMessage.getBytes("UTF-8"), firstMessage.length(), someInet, MPORT);
454             Receive receiveSecond = new Receive(secondSocket, inSecond);
455             receiveSecond.start();
456             Receive receiveFirst = new Receive(firstSocket, inSecond);
457             receiveFirst.start();
458             firstSocket.send(out);
459             if (receiveSecond.waitForReceive()) {
460                 Assert.fail("We did not receive the data in the second socket");
461             }
462             String fromFirst = new String(inSecond.getData(), "UTF-8");
463             assertEquals("Expected the second socket to recieve the same message the first socket sent", firstMessage, fromFirst);
464             // Make sure the first socket had read its own message
465             if (receiveSecond.waitForReceive()) {
466                 Assert.fail("We did not receive the data in the first socket");
467             }
468             // Reverse the roles
469             out = new DatagramPacket(secondMessage.getBytes("UTF-8"), secondMessage.length(), someInet, MPORT);
470             inFirst = new DatagramPacket(secondMessage.getBytes("UTF-8"), secondMessage.length(), someInet, MPORT);
471             receiveFirst = new Receive(firstSocket, inSecond);
472             receiveFirst.start();
473 
474             secondSocket.send(out);
475             if (receiveFirst.waitForReceive()) {
476                 Assert.fail("We did not receive the data in the first socket");
477             }
478             String fromSecond = new String(inFirst.getData(), "UTF-8");
479             assertEquals("Expected the first socket to recieve the same message the second socket sent", secondMessage, fromSecond);
480         } finally {
481             if (firstSocket != null) firstSocket.close();
482             if (secondSocket != null) secondSocket.close();
483         }
484     }
485 
486     @Test
487     public void testListMyServiceWithToLowerCase() throws IOException, InterruptedException {
488         System.out.println("Unit Test: testListMyServiceWithToLowerCase()");
489         String text = "Test hypothetical web server";
490         Map<String, byte[]> properties = new HashMap<String, byte[]>();
491         properties.put(serviceKey, text.getBytes());
492         service = ServiceInfo.create("_HtmL._TcP.lOcAl.", "apache-someUniqueid", 80, 0, 0, true, properties);
493         JmDNS registry = null;
494         try {
495             registry = JmDNS.create();
496             registry.registerService(service);
497 
498             // with toLowerCase
499             ServiceInfo[] services = registry.list(service.getType().toLowerCase());
500             assertEquals("We should see the service we just registered: ", 1, services.length);
501             assertEquals(service, services[0]);
502             // now unregister and make sure it's gone
503             registry.unregisterService(services[0]);
504             // According to the spec the record disappears from the cache 1s after it has been unregistered
505             // without sleeping for a while, the service would not be unregistered fully
506             Thread.sleep(1500);
507             services = registry.list(service.getType().toLowerCase());
508             assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
509         } finally {
510             if (registry != null) registry.close();
511         }
512     }
513 
514     @Test
515     public void testListMyServiceWithoutLowerCase() throws IOException, InterruptedException {
516         System.out.println("Unit Test: testListMyServiceWithoutLowerCase()");
517         String text = "Test hypothetical web server";
518         Map<String, byte[]> properties = new HashMap<String, byte[]>();
519         properties.put(serviceKey, text.getBytes());
520         service = ServiceInfo.create("_HtmL._TcP.lOcAl.", "apache-someUniqueid", 80, 0, 0, true, properties);
521         JmDNS registry = null;
522         try {
523             registry = JmDNS.create();
524             registry.registerService(service);
525 
526             // without toLowerCase
527             ServiceInfo[] services = registry.list(service.getType());
528             assertEquals("We should see the service we just registered: ", 1, services.length);
529             assertEquals(service, services[0]);
530             // now unregister and make sure it's gone
531             registry.unregisterService(services[0]);
532             // According to the spec the record disappears from the cache 1s after it has been unregistered
533             // without sleeping for a while, the service would not be unregistered fully
534             Thread.sleep(1500);
535             services = registry.list(service.getType());
536             assertTrue("We should not see the service we just unregistered: ", services == null || services.length == 0);
537         } finally {
538             if (registry != null) registry.close();
539         }
540     }
541 }