package com.connectsdk.discovery.provider; import static org.mockito.Matchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.net.InetAddress; import javax.jmdns.JmDNS; import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceListener; import javax.jmdns.impl.JmDNSImpl; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import android.content.Context; import com.connectsdk.discovery.DiscoveryFilter; import com.connectsdk.discovery.DiscoveryManager; import com.connectsdk.discovery.DiscoveryProvider; import com.connectsdk.discovery.DiscoveryProviderListener; import com.connectsdk.service.config.ServiceDescription; import com.connectsdk.shadow.WifiInfoShadow; @RunWith(RobolectricTestRunner.class) @Config(manifest = Config.NONE, shadows = { WifiInfoShadow.class }) public class ZeroConfDiscoveryPrividerTest { private ZeroconfDiscoveryProvider dp; private JmDNS mDNS; private ServiceEvent eventMock; // stub classes are used to allow mocking inside Robolectric test class StubJmDNS extends JmDNSImpl { public StubJmDNS() throws IOException { this(null, null); } public StubJmDNS(InetAddress address, String name) throws IOException { super(address, name); } } abstract class StubServiceEvent extends ServiceEvent { public StubServiceEvent(Object eventSource) { super(eventSource); } } abstract class StubServiceInfo extends javax.jmdns.ServiceInfo {} class StubZeroConfDiscoveryProvider extends ZeroconfDiscoveryProvider { public StubZeroConfDiscoveryProvider(Context context) { super(context); } @Override protected JmDNS createJmDNS() { return mDNS; } } @Before public void setUp() { dp = new StubZeroConfDiscoveryProvider(Robolectric.application); mDNS = mock(StubJmDNS.class); eventMock = mock(StubServiceEvent.class); dp.jmdns = mDNS; } @Test public void testStartShouldAddDeviceFilter() throws Exception { DiscoveryFilter filter = new DiscoveryFilter("Apple TV", "_testservicetype._tcp.local."); dp.addDeviceFilter(filter); dp.start(); Thread.sleep(500); verify(mDNS).addServiceListener(filter.getServiceFilter(), dp.jmdnsListener); } @Test public void testStartShouldCancelPreviousSearch() throws Exception { DiscoveryFilter filter = new DiscoveryFilter("Apple TV", "_testservicetype._tcp.local."); dp.addDeviceFilter(filter); dp.stop(); verify(mDNS).removeServiceListener(filter.getServiceFilter(), dp.jmdnsListener); } @Test public void testJmdnsServiceAdded() throws Exception { // Test Desc.: Verify when service added to the JmdnsServiceListener // then "service information is queried from registry with injected // event mock object. dp.jmdnsListener.serviceAdded(eventMock); dp.start(); verify(eventMock, atLeastOnce()).getType(); verify(eventMock, atLeastOnce()).getName(); verify(mDNS, timeout(100)).requestServiceInfo(eventMock.getType(), eventMock.getName(), 1); } @Test public void testAddListener() throws Exception { // Test Desc.: Verify ZeroConfDiscoveryProvider addListener - Adds a // DiscoveryProviderListener instance which is the DiscoveryManager Impl // to ServiceListeners List. DiscoveryManager listenerMock = mock(DiscoveryManager.class); Assert.assertFalse(dp.serviceListeners.contains(listenerMock)); dp.addListener(listenerMock); Assert.assertTrue(dp.serviceListeners.contains(listenerMock)); } @Test public void testRemoveListener() throws Exception { // Test Desc.: Verify ZeroConfDiscoveryProvider RemoveListener - Removes // a DiscoveryProviderListener instance which is the DiscoveryManager // Impl from ServiceListeners List. DiscoveryManager listenerMock = mock(DiscoveryManager.class); Assert.assertFalse(dp.serviceListeners.contains(listenerMock)); dp.serviceListeners.add(listenerMock); Assert.assertTrue(dp.serviceListeners.contains(listenerMock)); dp.removeListener(listenerMock); Assert.assertFalse(dp.serviceListeners.contains(listenerMock)); } @Test public void testFiltersAreEmptyByDefault() throws Exception { // Test Desc.: Verify if the serviceFilters is empty prior to calling // the scheduled timer task start() which adds the searchTarget as // filter into the ServiceFilters. DiscoveryFilter filter = new DiscoveryFilter("Apple TV", "_testservicetype._tcp.local."); Assert.assertTrue(dp.isEmpty()); dp.serviceFilters.add(filter); Assert.assertFalse(dp.isEmpty()); } @Test public void testStopZeroConfService() throws Exception { // Test Desc. : Verify if on stop() of ZeroConfDiscoveryProvider // Service, implicitly invoke the removeServiceListener() on JmDns // instance, DiscoveryFilter filter = new DiscoveryFilter("Apple TV", "_testservicetype._tcp.local."); dp.serviceFilters.add(filter); ServiceListener listener = dp.jmdnsListener; verify(mDNS, Mockito.never()).removeServiceListener( filter.getServiceFilter(), listener); dp.stop(); verify(mDNS, Mockito.times(1)).removeServiceListener( filter.getServiceFilter(), listener); } @Test public void testReset() throws Exception { // Test Desc. : Verify if JmdnsRegistry reset the services found for // ZeroConfDiscoveryProvider. ServiceDescription serviceDesc = new ServiceDescription(); dp.foundServices.put("service", serviceDesc); Assert.assertFalse(dp.foundServices.isEmpty()); dp.reset(); Assert.assertTrue(dp.foundServices.isEmpty()); } @Test public void testAddDeviceFilter() throws Exception { // Test Desc. : Verify if ZeroConfDiscoveryProvider. AddDeviceFilter // adds the specified device filter to serviceFilters list. DiscoveryFilter filter = new DiscoveryFilter("Test TV", "_testservicetype._tcp.local."); Assert.assertFalse(dp.serviceFilters.contains(filter)); dp.addDeviceFilter(filter); Assert.assertTrue(dp.serviceFilters.contains(filter)); } @Test public void testRemoveDeviceFilter() throws Exception { // Test Desc. : Verify if ZeroConfDiscoveryProvider. removeDeviceFilter // removes the entry specified device filter from to serviceFilters // list. DiscoveryFilter filter = new DiscoveryFilter("Test TV", "_testservicetype._tcp.local."); dp.serviceFilters.add(filter); Assert.assertFalse(dp.serviceFilters.isEmpty()); dp.removeDeviceFilter(filter); Assert.assertTrue(dp.serviceFilters.isEmpty()); } @Test public void testServiceIdForFilter() throws Exception { // Test Desc. : Verify if ZeroConfDiscoveryProvider. serviceIdForFilter // returns the serviceId for the specified filter added in // ServiceFilters list. DiscoveryFilter filter = new DiscoveryFilter("Test TV", "_testservicetype._tcp.local."); dp.serviceFilters.add(filter); String serviceId = dp.serviceIdForFilter(filter.getServiceFilter()); Assert.assertEquals("Test TV", serviceId); } private ServiceEvent createMockedServiceEvent(String ip, String name) { ServiceEvent event = mock(StubServiceEvent.class); ServiceInfo info = mock(StubServiceInfo.class); when(event.getInfo()).thenReturn(info); when(info.getHostAddress()).thenReturn(ip); when(info.getPort()).thenReturn(7000); when(info.getName()).thenReturn(name); return event; } @Test public void testServiceResolveEvent() throws Exception { // given ServiceEvent event = createMockedServiceEvent("192.168.0.1", "Test TV"); DiscoveryProviderListener listener = mock(DiscoveryProviderListener.class); dp.addListener(listener); // when dp.jmdnsListener.serviceResolved(event); // then verify(listener).onServiceAdded(any(DiscoveryProvider.class), any(ServiceDescription.class)); } @Test public void testServiceResolveEventWhenThereIsFoundService() throws Exception { // given String uuid = "192.168.0.1"; String name = "Test TV"; ServiceDescription serviceDescription = new ServiceDescription("_testservicetype._tcp.local.", uuid, uuid); serviceDescription.setFriendlyName(name); ServiceEvent event = createMockedServiceEvent(uuid, name); dp.foundServices.put(uuid, serviceDescription); DiscoveryProviderListener listener = mock(DiscoveryProviderListener.class); dp.addListener(listener); // when dp.jmdnsListener.serviceResolved(event); // then verify(listener, never()).onServiceAdded(any(DiscoveryProvider.class), any(ServiceDescription.class)); } @Test public void testServiceRemoveEvent() throws Exception { // given String uuid = "192.168.0.1"; String name = "Test TV"; ServiceDescription serviceDescription = new ServiceDescription("_testservicetype._tcp.local.", uuid, uuid); serviceDescription.setFriendlyName(name); ServiceEvent event = createMockedServiceEvent(uuid, name); DiscoveryProviderListener listener = mock(DiscoveryProviderListener.class); dp.addListener(listener); dp.foundServices.put(uuid, serviceDescription); // when dp.jmdnsListener.serviceRemoved(event); Robolectric.runUiThreadTasksIncludingDelayedTasks(); // then verify(listener).onServiceRemoved(any(DiscoveryProvider.class), any(ServiceDescription.class)); } @Test public void testStateAfterConstruction() { Assert.assertNotNull(dp.foundServices); Assert.assertNotNull(dp.serviceFilters); Assert.assertNotNull(dp.serviceListeners); Assert.assertTrue(dp.foundServices.isEmpty()); Assert.assertTrue(dp.serviceFilters.isEmpty()); Assert.assertTrue(dp.serviceListeners.isEmpty()); Assert.assertNotNull(dp.srcAddress); } }