Home | History | Annotate | Download | only in nsd
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.net.nsd;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotNull;
     21 import static org.junit.Assert.fail;
     22 import static org.mockito.Mockito.any;
     23 import static org.mockito.Mockito.mock;
     24 import static org.mockito.Mockito.never;
     25 import static org.mockito.Mockito.reset;
     26 import static org.mockito.Mockito.spy;
     27 import static org.mockito.Mockito.timeout;
     28 import static org.mockito.Mockito.times;
     29 import static org.mockito.Mockito.verify;
     30 import static org.mockito.Mockito.when;
     31 import static com.android.internal.util.TestUtils.waitForIdleHandler;
     32 
     33 import android.os.HandlerThread;
     34 import android.os.Handler;
     35 import android.os.Looper;
     36 import android.content.Context;
     37 import android.support.test.filters.SmallTest;
     38 import android.support.test.runner.AndroidJUnit4;
     39 import android.os.Message;
     40 import android.os.Messenger;
     41 import com.android.internal.util.AsyncChannel;
     42 import org.junit.After;
     43 import org.junit.Before;
     44 import org.junit.Test;
     45 import org.junit.runner.RunWith;
     46 import org.mockito.Mock;
     47 import org.mockito.MockitoAnnotations;
     48 
     49 import java.util.function.Consumer;
     50 
     51 @RunWith(AndroidJUnit4.class)
     52 @SmallTest
     53 public class NsdManagerTest {
     54 
     55     static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
     56 
     57     @Mock Context mContext;
     58     @Mock INsdManager mService;
     59     MockServiceHandler mServiceHandler;
     60 
     61     NsdManager mManager;
     62 
     63     long mTimeoutMs = 200; // non-final so that tests can adjust the value.
     64 
     65     @Before
     66     public void setUp() throws Exception {
     67         MockitoAnnotations.initMocks(this);
     68 
     69         mServiceHandler = spy(MockServiceHandler.create(mContext));
     70         when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
     71 
     72         mManager = makeManager();
     73     }
     74 
     75     @After
     76     public void tearDown() throws Exception {
     77         mServiceHandler.waitForIdle(mTimeoutMs);
     78         mServiceHandler.chan.disconnect();
     79         mServiceHandler.stop();
     80         if (mManager != null) {
     81             mManager.disconnect();
     82         }
     83     }
     84 
     85     @Test
     86     public void testResolveService() {
     87         NsdManager manager = mManager;
     88 
     89         NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
     90         NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
     91         NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
     92 
     93         manager.resolveService(request, listener);
     94         int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
     95         int err = 33;
     96         sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
     97         verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
     98 
     99         manager.resolveService(request, listener);
    100         int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
    101         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
    102         verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
    103     }
    104 
    105     @Test
    106     public void testParallelResolveService() {
    107         NsdManager manager = mManager;
    108 
    109         NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
    110         NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
    111 
    112         NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
    113         NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
    114 
    115         manager.resolveService(request, listener1);
    116         int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
    117 
    118         manager.resolveService(request, listener2);
    119         int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
    120 
    121         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
    122         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
    123 
    124         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
    125         verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
    126     }
    127 
    128     @Test
    129     public void testRegisterService() {
    130         NsdManager manager = mManager;
    131 
    132         NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
    133         NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
    134         request1.setPort(2201);
    135         request2.setPort(2202);
    136         NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
    137         NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
    138 
    139         // Register two services
    140         manager.registerService(request1, PROTOCOL, listener1);
    141         int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
    142 
    143         manager.registerService(request2, PROTOCOL, listener2);
    144         int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
    145 
    146         // First reques fails, second request succeeds
    147         sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
    148         verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
    149 
    150         int err = 1;
    151         sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
    152         verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
    153 
    154         // Client retries first request, it succeeds
    155         manager.registerService(request1, PROTOCOL, listener1);
    156         int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
    157 
    158         sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
    159         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
    160 
    161         // First request is unregistered, it succeeds
    162         manager.unregisterService(listener1);
    163         int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
    164         assertEquals(key3, key3again);
    165 
    166         sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
    167         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
    168 
    169         // Second request is unregistered, it fails
    170         manager.unregisterService(listener2);
    171         int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
    172         assertEquals(key2, key2again);
    173 
    174         sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
    175         verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
    176 
    177         // TODO: do not unregister listener until service is unregistered
    178         // Client retries unregistration of second request, it succeeds
    179         //manager.unregisterService(listener2);
    180         //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
    181         //assertEquals(key2, key2yetAgain);
    182 
    183         //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
    184         //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
    185     }
    186 
    187     @Test
    188     public void testDiscoverService() {
    189         NsdManager manager = mManager;
    190 
    191         NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
    192         NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
    193         NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
    194 
    195         NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
    196 
    197         // Client registers for discovery, request fails
    198         manager.discoverServices("a_type", PROTOCOL, listener);
    199         int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
    200 
    201         int err = 1;
    202         sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
    203         verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
    204 
    205         // Client retries, request succeeds
    206         manager.discoverServices("a_type", PROTOCOL, listener);
    207         int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
    208 
    209         sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
    210         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
    211 
    212 
    213         // mdns notifies about services
    214         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
    215         verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
    216 
    217         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
    218         verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
    219 
    220         sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
    221         verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
    222 
    223 
    224         // Client unregisters its listener
    225         manager.stopServiceDiscovery(listener);
    226         int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
    227         assertEquals(key2, key2again);
    228 
    229         // TODO: unregister listener immediately and stop notifying it about services
    230         // Notifications are still passed to the client's listener
    231         sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
    232         verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
    233 
    234         // Client is notified of complete unregistration
    235         sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
    236         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
    237 
    238         // Notifications are not passed to the client anymore
    239         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
    240         verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
    241 
    242 
    243         // Client registers for service discovery
    244         reset(listener);
    245         manager.discoverServices("a_type", PROTOCOL, listener);
    246         int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
    247 
    248         sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
    249         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
    250 
    251         // Client unregisters immediately, it fails
    252         manager.stopServiceDiscovery(listener);
    253         int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
    254         assertEquals(key3, key3again);
    255 
    256         err = 2;
    257         sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
    258         verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
    259 
    260         // New notifications are not passed to the client anymore
    261         sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
    262         verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
    263     }
    264 
    265     @Test
    266     public void testInvalidCalls() {
    267         NsdManager manager = mManager;
    268 
    269         NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
    270         NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
    271         NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
    272 
    273         NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
    274         NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
    275         validService.setPort(2222);
    276 
    277         // Service registration
    278         //  - invalid arguments
    279         mustFail(() -> { manager.unregisterService(null); });
    280         mustFail(() -> { manager.registerService(null, -1, null); });
    281         mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
    282         mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
    283         mustFail(() -> { manager.registerService(validService, -1, listener1); });
    284         mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
    285         manager.registerService(validService, PROTOCOL, listener1);
    286         //  - listener already registered
    287         mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
    288         manager.unregisterService(listener1);
    289         // TODO: make listener immediately reusable
    290         //mustFail(() -> { manager.unregisterService(listener1); });
    291         //manager.registerService(validService, PROTOCOL, listener1);
    292 
    293         // Discover service
    294         //  - invalid arguments
    295         mustFail(() -> { manager.stopServiceDiscovery(null); });
    296         mustFail(() -> { manager.discoverServices(null, -1, null); });
    297         mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
    298         mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
    299         mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
    300         manager.discoverServices("a_service", PROTOCOL, listener2);
    301         //  - listener already registered
    302         mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
    303         manager.stopServiceDiscovery(listener2);
    304         // TODO: make listener immediately reusable
    305         //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
    306         //manager.discoverServices("another_service", PROTOCOL, listener2);
    307 
    308         // Resolver service
    309         //  - invalid arguments
    310         mustFail(() -> { manager.resolveService(null, null); });
    311         mustFail(() -> { manager.resolveService(null, listener3); });
    312         mustFail(() -> { manager.resolveService(invalidService, listener3); });
    313         mustFail(() -> { manager.resolveService(validService, null); });
    314         manager.resolveService(validService, listener3);
    315         //  - listener already registered:w
    316         mustFail(() -> { manager.resolveService(validService, listener3); });
    317     }
    318 
    319     public void mustFail(Runnable fn) {
    320         try {
    321             fn.run();
    322             fail();
    323         } catch (Exception expected) {
    324         }
    325     }
    326 
    327     NsdManager makeManager() {
    328         NsdManager manager = new NsdManager(mContext, mService);
    329         // Acknowledge first two messages connecting the AsyncChannel.
    330         verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
    331         reset(mServiceHandler);
    332         assertNotNull(mServiceHandler.chan);
    333         return manager;
    334     }
    335 
    336     int verifyRequest(int expectedMessageType) {
    337         mServiceHandler.waitForIdle(mTimeoutMs);
    338         verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
    339         reset(mServiceHandler);
    340         Message received = mServiceHandler.getLastMessage();
    341         assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
    342         return received.arg2;
    343     }
    344 
    345     void sendResponse(int replyType, int arg, int key, Object obj) {
    346         mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
    347     }
    348 
    349     // Implements the server side of AsyncChannel connection protocol
    350     public static class MockServiceHandler extends Handler {
    351         public final Context context;
    352         public AsyncChannel chan;
    353         public Message lastMessage;
    354 
    355         MockServiceHandler(Looper l, Context c) {
    356             super(l);
    357             context = c;
    358         }
    359 
    360         synchronized Message getLastMessage() {
    361             return lastMessage;
    362         }
    363 
    364         synchronized void setLastMessage(Message msg) {
    365             lastMessage = obtainMessage();
    366             lastMessage.copyFrom(msg);
    367         }
    368 
    369         void waitForIdle(long timeoutMs) {
    370             waitForIdleHandler(this, timeoutMs);
    371         }
    372 
    373         @Override
    374         public void handleMessage(Message msg) {
    375             setLastMessage(msg);
    376             if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
    377                 chan = new AsyncChannel();
    378                 chan.connect(context, this, msg.replyTo);
    379                 chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
    380             }
    381         }
    382 
    383         void stop() {
    384             getLooper().quitSafely();
    385         }
    386 
    387         static MockServiceHandler create(Context context) {
    388             HandlerThread t = new HandlerThread("mock-service-handler");
    389             t.start();
    390             return new MockServiceHandler(t.getLooper(), context);
    391         }
    392     }
    393 }
    394