• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
20 import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.fail;
25 import static org.mockito.Mockito.any;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.reset;
29 import static org.mockito.Mockito.spy;
30 import static org.mockito.Mockito.timeout;
31 import static org.mockito.Mockito.verify;
32 
33 import android.compat.testing.PlatformCompatChangeRule;
34 import android.content.Context;
35 import android.os.Build;
36 import android.os.Handler;
37 import android.os.HandlerThread;
38 import android.os.Looper;
39 import android.os.Message;
40 import android.os.Messenger;
41 
42 import androidx.test.filters.SmallTest;
43 
44 import com.android.internal.util.AsyncChannel;
45 import com.android.testutils.DevSdkIgnoreRule;
46 import com.android.testutils.DevSdkIgnoreRunner;
47 import com.android.testutils.HandlerUtils;
48 
49 import org.junit.After;
50 import org.junit.Before;
51 import org.junit.Rule;
52 import org.junit.Test;
53 import org.junit.rules.TestRule;
54 import org.junit.runner.RunWith;
55 import org.mockito.Mock;
56 import org.mockito.MockitoAnnotations;
57 
58 @RunWith(DevSdkIgnoreRunner.class)
59 @SmallTest
60 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
61 public class NsdManagerTest {
62 
63     static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
64 
65     @Rule
66     public TestRule compatChangeRule = new PlatformCompatChangeRule();
67 
68     @Mock Context mContext;
69     @Mock INsdManager mService;
70     MockServiceHandler mServiceHandler;
71 
72     NsdManager mManager;
73 
74     long mTimeoutMs = 200; // non-final so that tests can adjust the value.
75 
76     @Before
setUp()77     public void setUp() throws Exception {
78         MockitoAnnotations.initMocks(this);
79 
80         mServiceHandler = spy(MockServiceHandler.create(mContext));
81         doReturn(new Messenger(mServiceHandler)).when(mService).getMessenger();
82     }
83 
84     @After
tearDown()85     public void tearDown() throws Exception {
86         HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
87         mServiceHandler.chan.disconnect();
88         mServiceHandler.stop();
89         if (mManager != null) {
90             mManager.disconnect();
91         }
92     }
93 
94     @Test
95     @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testResolveServiceS()96     public void testResolveServiceS() {
97         mManager = makeNsdManagerS();
98         doTestResolveService();
99     }
100 
101     @Test
102     @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testResolveServicePreS()103     public void testResolveServicePreS() {
104         mManager = makeNsdManagerPreS();
105         doTestResolveService();
106     }
107 
108     @Test
109     @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testDiscoverServiceS()110     public void testDiscoverServiceS() {
111         mManager = makeNsdManagerS();
112         doTestDiscoverService();
113     }
114 
115     @Test
116     @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testDiscoverServicePreS()117     public void testDiscoverServicePreS() {
118         mManager = makeNsdManagerPreS();
119         doTestDiscoverService();
120     }
121 
122     @Test
123     @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testParallelResolveServiceS()124     public void testParallelResolveServiceS() {
125         mManager = makeNsdManagerS();
126         doTestParallelResolveService();
127     }
128 
129     @Test
130     @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testParallelResolveServicePreS()131     public void testParallelResolveServicePreS() {
132         mManager = makeNsdManagerPreS();
133         doTestParallelResolveService();
134     }
135 
136     @Test
137     @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testInvalidCallsS()138     public void testInvalidCallsS() {
139         mManager = makeNsdManagerS();
140         doTestInvalidCalls();
141     }
142 
143     @Test
144     @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testInvalidCallsPreS()145     public void testInvalidCallsPreS() {
146         mManager = makeNsdManagerPreS();
147         doTestInvalidCalls();
148     }
149 
150     @Test
151     @EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testRegisterServiceS()152     public void testRegisterServiceS() {
153         mManager = makeNsdManagerS();
154         doTestRegisterService();
155     }
156 
157     @Test
158     @DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
testRegisterServicePreS()159     public void testRegisterServicePreS() {
160         mManager = makeNsdManagerPreS();
161         doTestRegisterService();
162     }
163 
doTestResolveService()164     public void doTestResolveService() {
165         NsdManager manager = mManager;
166 
167         NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
168         NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
169         NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
170 
171         manager.resolveService(request, listener);
172         int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
173         int err = 33;
174         sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
175         verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
176 
177         manager.resolveService(request, listener);
178         int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
179         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
180         verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
181     }
182 
doTestParallelResolveService()183     public void doTestParallelResolveService() {
184         NsdManager manager = mManager;
185 
186         NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
187         NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
188 
189         NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
190         NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
191 
192         manager.resolveService(request, listener1);
193         int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
194 
195         manager.resolveService(request, listener2);
196         int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
197 
198         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
199         sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
200 
201         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
202         verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
203     }
204 
doTestRegisterService()205     public void doTestRegisterService() {
206         NsdManager manager = mManager;
207 
208         NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
209         NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
210         request1.setPort(2201);
211         request2.setPort(2202);
212         NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
213         NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
214 
215         // Register two services
216         manager.registerService(request1, PROTOCOL, listener1);
217         int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
218 
219         manager.registerService(request2, PROTOCOL, listener2);
220         int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
221 
222         // First reques fails, second request succeeds
223         sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
224         verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
225 
226         int err = 1;
227         sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
228         verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
229 
230         // Client retries first request, it succeeds
231         manager.registerService(request1, PROTOCOL, listener1);
232         int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
233 
234         sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
235         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
236 
237         // First request is unregistered, it succeeds
238         manager.unregisterService(listener1);
239         int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
240         assertEquals(key3, key3again);
241 
242         sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
243         verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
244 
245         // Second request is unregistered, it fails
246         manager.unregisterService(listener2);
247         int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
248         assertEquals(key2, key2again);
249 
250         sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
251         verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
252 
253         // TODO: do not unregister listener until service is unregistered
254         // Client retries unregistration of second request, it succeeds
255         //manager.unregisterService(listener2);
256         //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
257         //assertEquals(key2, key2yetAgain);
258 
259         //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
260         //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
261     }
262 
doTestDiscoverService()263     public void doTestDiscoverService() {
264         NsdManager manager = mManager;
265 
266         NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
267         NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
268         NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
269 
270         NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
271 
272         // Client registers for discovery, request fails
273         manager.discoverServices("a_type", PROTOCOL, listener);
274         int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
275 
276         int err = 1;
277         sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
278         verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
279 
280         // Client retries, request succeeds
281         manager.discoverServices("a_type", PROTOCOL, listener);
282         int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
283 
284         sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
285         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
286 
287 
288         // mdns notifies about services
289         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
290         verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
291 
292         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
293         verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
294 
295         sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
296         verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
297 
298 
299         // Client unregisters its listener
300         manager.stopServiceDiscovery(listener);
301         int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
302         assertEquals(key2, key2again);
303 
304         // TODO: unregister listener immediately and stop notifying it about services
305         // Notifications are still passed to the client's listener
306         sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
307         verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
308 
309         // Client is notified of complete unregistration
310         sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
311         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
312 
313         // Notifications are not passed to the client anymore
314         sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
315         verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
316 
317 
318         // Client registers for service discovery
319         reset(listener);
320         manager.discoverServices("a_type", PROTOCOL, listener);
321         int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
322 
323         sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
324         verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
325 
326         // Client unregisters immediately, it fails
327         manager.stopServiceDiscovery(listener);
328         int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
329         assertEquals(key3, key3again);
330 
331         err = 2;
332         sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
333         verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
334 
335         // New notifications are not passed to the client anymore
336         sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
337         verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
338     }
339 
doTestInvalidCalls()340     public void doTestInvalidCalls() {
341         NsdManager manager = mManager;
342 
343         NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
344         NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
345         NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
346 
347         NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
348         NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
349         validService.setPort(2222);
350 
351         // Service registration
352         //  - invalid arguments
353         mustFail(() -> { manager.unregisterService(null); });
354         mustFail(() -> { manager.registerService(null, -1, null); });
355         mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
356         mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
357         mustFail(() -> { manager.registerService(validService, -1, listener1); });
358         mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
359         manager.registerService(validService, PROTOCOL, listener1);
360         //  - listener already registered
361         mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
362         manager.unregisterService(listener1);
363         // TODO: make listener immediately reusable
364         //mustFail(() -> { manager.unregisterService(listener1); });
365         //manager.registerService(validService, PROTOCOL, listener1);
366 
367         // Discover service
368         //  - invalid arguments
369         mustFail(() -> { manager.stopServiceDiscovery(null); });
370         mustFail(() -> { manager.discoverServices(null, -1, null); });
371         mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
372         mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
373         mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
374         manager.discoverServices("a_service", PROTOCOL, listener2);
375         //  - listener already registered
376         mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
377         manager.stopServiceDiscovery(listener2);
378         // TODO: make listener immediately reusable
379         //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
380         //manager.discoverServices("another_service", PROTOCOL, listener2);
381 
382         // Resolver service
383         //  - invalid arguments
384         mustFail(() -> { manager.resolveService(null, null); });
385         mustFail(() -> { manager.resolveService(null, listener3); });
386         mustFail(() -> { manager.resolveService(invalidService, listener3); });
387         mustFail(() -> { manager.resolveService(validService, null); });
388         manager.resolveService(validService, listener3);
389         //  - listener already registered:w
390         mustFail(() -> { manager.resolveService(validService, listener3); });
391     }
392 
mustFail(Runnable fn)393     public void mustFail(Runnable fn) {
394         try {
395             fn.run();
396             fail();
397         } catch (Exception expected) {
398         }
399     }
400 
makeNsdManagerS()401     NsdManager makeNsdManagerS() {
402         // Expect we'll get 2 AsyncChannel related msgs.
403         return makeManager(2);
404     }
405 
makeNsdManagerPreS()406     NsdManager makeNsdManagerPreS() {
407         // Expect we'll get 3 msgs. 2 AsyncChannel related msgs + 1 additional daemon startup msg.
408         return makeManager(3);
409     }
410 
makeManager(int expectedMsgCount)411     NsdManager makeManager(int expectedMsgCount) {
412         NsdManager manager = new NsdManager(mContext, mService);
413         // Acknowledge first two messages connecting the AsyncChannel.
414         verify(mServiceHandler, timeout(mTimeoutMs).times(expectedMsgCount)).handleMessage(any());
415 
416         reset(mServiceHandler);
417         assertNotNull(mServiceHandler.chan);
418         return manager;
419     }
420 
verifyRequest(int expectedMessageType)421     int verifyRequest(int expectedMessageType) {
422         HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
423         verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
424         reset(mServiceHandler);
425         Message received = mServiceHandler.getLastMessage();
426         assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
427         return received.arg2;
428     }
429 
sendResponse(int replyType, int arg, int key, Object obj)430     void sendResponse(int replyType, int arg, int key, Object obj) {
431         mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
432     }
433 
434     // Implements the server side of AsyncChannel connection protocol
435     public static class MockServiceHandler extends Handler {
436         public final Context context;
437         public AsyncChannel chan;
438         public Message lastMessage;
439 
MockServiceHandler(Looper l, Context c)440         MockServiceHandler(Looper l, Context c) {
441             super(l);
442             context = c;
443         }
444 
getLastMessage()445         synchronized Message getLastMessage() {
446             return lastMessage;
447         }
448 
setLastMessage(Message msg)449         synchronized void setLastMessage(Message msg) {
450             lastMessage = obtainMessage();
451             lastMessage.copyFrom(msg);
452         }
453 
454         @Override
handleMessage(Message msg)455         public void handleMessage(Message msg) {
456             setLastMessage(msg);
457             if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
458                 chan = new AsyncChannel();
459                 chan.connect(context, this, msg.replyTo);
460                 chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
461             }
462         }
463 
stop()464         void stop() {
465             getLooper().quitSafely();
466         }
467 
create(Context context)468         static MockServiceHandler create(Context context) {
469             HandlerThread t = new HandlerThread("mock-service-handler");
470             t.start();
471             return new MockServiceHandler(t.getLooper(), context);
472         }
473     }
474 }
475