Merge "Update NSD tests without AsyncChannel"
This commit is contained in:
@@ -20,38 +20,32 @@ import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChange
|
||||
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.timeout;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.compat.testing.PlatformCompatChangeRule;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
import com.android.testutils.DevSdkIgnoreRule;
|
||||
import com.android.testutils.DevSdkIgnoreRunner;
|
||||
import com.android.testutils.HandlerUtils;
|
||||
import com.android.testutils.ExceptionUtils;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@@ -67,9 +61,10 @@ public class NsdManagerTest {
|
||||
|
||||
@Mock Context mContext;
|
||||
@Mock INsdManager mService;
|
||||
MockServiceHandler mServiceHandler;
|
||||
@Mock INsdServiceConnector mServiceConn;
|
||||
|
||||
NsdManager mManager;
|
||||
INsdManagerCallback mCallback;
|
||||
|
||||
long mTimeoutMs = 200; // non-final so that tests can adjust the value.
|
||||
|
||||
@@ -77,91 +72,85 @@ public class NsdManagerTest {
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mServiceHandler = spy(MockServiceHandler.create(mContext));
|
||||
doReturn(new Messenger(mServiceHandler)).when(mService).getMessenger();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
|
||||
mServiceHandler.chan.disconnect();
|
||||
mServiceHandler.stop();
|
||||
if (mManager != null) {
|
||||
mManager.disconnect();
|
||||
}
|
||||
doReturn(mServiceConn).when(mService).connect(any());
|
||||
mManager = new NsdManager(mContext, mService);
|
||||
final ArgumentCaptor<INsdManagerCallback> cbCaptor = ArgumentCaptor.forClass(
|
||||
INsdManagerCallback.class);
|
||||
verify(mService).connect(cbCaptor.capture());
|
||||
mCallback = cbCaptor.getValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testResolveServiceS() {
|
||||
mManager = makeNsdManagerS();
|
||||
public void testResolveServiceS() throws Exception {
|
||||
verify(mServiceConn, never()).startDaemon();
|
||||
doTestResolveService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testResolveServicePreS() {
|
||||
mManager = makeNsdManagerPreS();
|
||||
public void testResolveServicePreS() throws Exception {
|
||||
verify(mServiceConn).startDaemon();
|
||||
doTestResolveService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testDiscoverServiceS() {
|
||||
mManager = makeNsdManagerS();
|
||||
public void testDiscoverServiceS() throws Exception {
|
||||
verify(mServiceConn, never()).startDaemon();
|
||||
doTestDiscoverService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testDiscoverServicePreS() {
|
||||
mManager = makeNsdManagerPreS();
|
||||
public void testDiscoverServicePreS() throws Exception {
|
||||
verify(mServiceConn).startDaemon();
|
||||
doTestDiscoverService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testParallelResolveServiceS() {
|
||||
mManager = makeNsdManagerS();
|
||||
public void testParallelResolveServiceS() throws Exception {
|
||||
verify(mServiceConn, never()).startDaemon();
|
||||
doTestParallelResolveService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testParallelResolveServicePreS() {
|
||||
mManager = makeNsdManagerPreS();
|
||||
public void testParallelResolveServicePreS() throws Exception {
|
||||
verify(mServiceConn).startDaemon();
|
||||
doTestParallelResolveService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testInvalidCallsS() {
|
||||
mManager = makeNsdManagerS();
|
||||
public void testInvalidCallsS() throws Exception {
|
||||
verify(mServiceConn, never()).startDaemon();
|
||||
doTestInvalidCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testInvalidCallsPreS() {
|
||||
mManager = makeNsdManagerPreS();
|
||||
public void testInvalidCallsPreS() throws Exception {
|
||||
verify(mServiceConn).startDaemon();
|
||||
doTestInvalidCalls();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testRegisterServiceS() {
|
||||
mManager = makeNsdManagerS();
|
||||
public void testRegisterServiceS() throws Exception {
|
||||
verify(mServiceConn, never()).startDaemon();
|
||||
doTestRegisterService();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testRegisterServicePreS() {
|
||||
mManager = makeNsdManagerPreS();
|
||||
public void testRegisterServicePreS() throws Exception {
|
||||
verify(mServiceConn).startDaemon();
|
||||
doTestRegisterService();
|
||||
}
|
||||
|
||||
public void doTestResolveService() {
|
||||
private void doTestResolveService() throws Exception {
|
||||
NsdManager manager = mManager;
|
||||
|
||||
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
|
||||
@@ -169,18 +158,19 @@ public class NsdManagerTest {
|
||||
NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
|
||||
|
||||
manager.resolveService(request, listener);
|
||||
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||
int key1 = getRequestKey(req -> verify(mServiceConn).resolveService(req.capture(), any()));
|
||||
int err = 33;
|
||||
sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
|
||||
mCallback.onResolveServiceFailed(key1, err);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
|
||||
|
||||
manager.resolveService(request, listener);
|
||||
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
|
||||
int key2 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).resolveService(req.capture(), any()));
|
||||
mCallback.onResolveServiceSucceeded(key2, reply);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||
}
|
||||
|
||||
public void doTestParallelResolveService() {
|
||||
private void doTestParallelResolveService() throws Exception {
|
||||
NsdManager manager = mManager;
|
||||
|
||||
NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
|
||||
@@ -190,19 +180,20 @@ public class NsdManagerTest {
|
||||
NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
|
||||
|
||||
manager.resolveService(request, listener1);
|
||||
int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||
int key1 = getRequestKey(req -> verify(mServiceConn).resolveService(req.capture(), any()));
|
||||
|
||||
manager.resolveService(request, listener2);
|
||||
int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
|
||||
int key2 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).resolveService(req.capture(), any()));
|
||||
|
||||
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
|
||||
sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
|
||||
mCallback.onResolveServiceSucceeded(key2, reply);
|
||||
mCallback.onResolveServiceSucceeded(key1, reply);
|
||||
|
||||
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
|
||||
}
|
||||
|
||||
public void doTestRegisterService() {
|
||||
private void doTestRegisterService() throws Exception {
|
||||
NsdManager manager = mManager;
|
||||
|
||||
NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
|
||||
@@ -214,40 +205,43 @@ public class NsdManagerTest {
|
||||
|
||||
// Register two services
|
||||
manager.registerService(request1, PROTOCOL, listener1);
|
||||
int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||
int key1 = getRequestKey(req -> verify(mServiceConn).registerService(req.capture(), any()));
|
||||
|
||||
manager.registerService(request2, PROTOCOL, listener2);
|
||||
int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||
int key2 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).registerService(req.capture(), any()));
|
||||
|
||||
// First reques fails, second request succeeds
|
||||
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
|
||||
mCallback.onRegisterServiceSucceeded(key2, request2);
|
||||
verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
|
||||
|
||||
int err = 1;
|
||||
sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
|
||||
mCallback.onRegisterServiceFailed(key1, err);
|
||||
verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
|
||||
|
||||
// Client retries first request, it succeeds
|
||||
manager.registerService(request1, PROTOCOL, listener1);
|
||||
int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
|
||||
int key3 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(3)).registerService(req.capture(), any()));
|
||||
|
||||
sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
|
||||
mCallback.onRegisterServiceSucceeded(key3, request1);
|
||||
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
|
||||
|
||||
// First request is unregistered, it succeeds
|
||||
manager.unregisterService(listener1);
|
||||
int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
|
||||
int key3again = getRequestKey(req -> verify(mServiceConn).unregisterService(req.capture()));
|
||||
assertEquals(key3, key3again);
|
||||
|
||||
sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
|
||||
mCallback.onUnregisterServiceSucceeded(key3again);
|
||||
verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
|
||||
|
||||
// Second request is unregistered, it fails
|
||||
manager.unregisterService(listener2);
|
||||
int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
|
||||
int key2again = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).unregisterService(req.capture()));
|
||||
assertEquals(key2, key2again);
|
||||
|
||||
sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
|
||||
mCallback.onUnregisterServiceFailed(key2again, err);
|
||||
verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
|
||||
|
||||
// TODO: do not unregister listener until service is unregistered
|
||||
@@ -260,7 +254,7 @@ public class NsdManagerTest {
|
||||
//verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
|
||||
}
|
||||
|
||||
public void doTestDiscoverService() {
|
||||
private void doTestDiscoverService() throws Exception {
|
||||
NsdManager manager = mManager;
|
||||
|
||||
NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
|
||||
@@ -271,69 +265,73 @@ public class NsdManagerTest {
|
||||
|
||||
// Client registers for discovery, request fails
|
||||
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||
int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||
int key1 = getRequestKey(req ->
|
||||
verify(mServiceConn).discoverServices(req.capture(), any()));
|
||||
|
||||
int err = 1;
|
||||
sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
|
||||
mCallback.onDiscoverServicesFailed(key1, err);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
|
||||
|
||||
// Client retries, request succeeds
|
||||
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||
int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||
int key2 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).discoverServices(req.capture(), any()));
|
||||
|
||||
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
|
||||
mCallback.onDiscoverServicesStarted(key2, reply1);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
|
||||
|
||||
|
||||
// mdns notifies about services
|
||||
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
|
||||
mCallback.onServiceFound(key2, reply1);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
|
||||
|
||||
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
|
||||
mCallback.onServiceFound(key2, reply2);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
|
||||
|
||||
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
|
||||
mCallback.onServiceLost(key2, reply2);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
|
||||
|
||||
|
||||
// Client unregisters its listener
|
||||
manager.stopServiceDiscovery(listener);
|
||||
int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
|
||||
int key2again = getRequestKey(req -> verify(mServiceConn).stopDiscovery(req.capture()));
|
||||
assertEquals(key2, key2again);
|
||||
|
||||
// TODO: unregister listener immediately and stop notifying it about services
|
||||
// Notifications are still passed to the client's listener
|
||||
sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
|
||||
mCallback.onServiceLost(key2, reply1);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
|
||||
|
||||
// Client is notified of complete unregistration
|
||||
sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
|
||||
mCallback.onStopDiscoverySucceeded(key2again);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
|
||||
|
||||
// Notifications are not passed to the client anymore
|
||||
sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
|
||||
mCallback.onServiceFound(key2, reply3);
|
||||
verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
|
||||
|
||||
|
||||
// Client registers for service discovery
|
||||
reset(listener);
|
||||
manager.discoverServices("a_type", PROTOCOL, listener);
|
||||
int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
|
||||
int key3 = getRequestKey(req ->
|
||||
verify(mServiceConn, times(3)).discoverServices(req.capture(), any()));
|
||||
|
||||
sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
|
||||
mCallback.onDiscoverServicesStarted(key3, reply1);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
|
||||
|
||||
// Client unregisters immediately, it fails
|
||||
manager.stopServiceDiscovery(listener);
|
||||
int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
|
||||
int key3again = getRequestKey(req ->
|
||||
verify(mServiceConn, times(2)).stopDiscovery(req.capture()));
|
||||
assertEquals(key3, key3again);
|
||||
|
||||
err = 2;
|
||||
sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
|
||||
mCallback.onStopDiscoveryFailed(key3again, err);
|
||||
verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
|
||||
|
||||
// New notifications are not passed to the client anymore
|
||||
sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
|
||||
mCallback.onServiceFound(key3, reply1);
|
||||
verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
|
||||
}
|
||||
|
||||
@@ -398,77 +396,10 @@ public class NsdManagerTest {
|
||||
}
|
||||
}
|
||||
|
||||
NsdManager makeNsdManagerS() {
|
||||
// Expect we'll get 2 AsyncChannel related msgs.
|
||||
return makeManager(2);
|
||||
}
|
||||
|
||||
NsdManager makeNsdManagerPreS() {
|
||||
// Expect we'll get 3 msgs. 2 AsyncChannel related msgs + 1 additional daemon startup msg.
|
||||
return makeManager(3);
|
||||
}
|
||||
|
||||
NsdManager makeManager(int expectedMsgCount) {
|
||||
NsdManager manager = new NsdManager(mContext, mService);
|
||||
// Acknowledge first two messages connecting the AsyncChannel.
|
||||
verify(mServiceHandler, timeout(mTimeoutMs).times(expectedMsgCount)).handleMessage(any());
|
||||
|
||||
reset(mServiceHandler);
|
||||
assertNotNull(mServiceHandler.chan);
|
||||
return manager;
|
||||
}
|
||||
|
||||
int verifyRequest(int expectedMessageType) {
|
||||
HandlerUtils.waitForIdle(mServiceHandler, mTimeoutMs);
|
||||
verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
|
||||
reset(mServiceHandler);
|
||||
Message received = mServiceHandler.getLastMessage();
|
||||
assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
|
||||
return received.arg2;
|
||||
}
|
||||
|
||||
void sendResponse(int replyType, int arg, int key, Object obj) {
|
||||
mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
|
||||
}
|
||||
|
||||
// Implements the server side of AsyncChannel connection protocol
|
||||
public static class MockServiceHandler extends Handler {
|
||||
public final Context context;
|
||||
public AsyncChannel chan;
|
||||
public Message lastMessage;
|
||||
|
||||
MockServiceHandler(Looper l, Context c) {
|
||||
super(l);
|
||||
context = c;
|
||||
}
|
||||
|
||||
synchronized Message getLastMessage() {
|
||||
return lastMessage;
|
||||
}
|
||||
|
||||
synchronized void setLastMessage(Message msg) {
|
||||
lastMessage = obtainMessage();
|
||||
lastMessage.copyFrom(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
setLastMessage(msg);
|
||||
if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
|
||||
chan = new AsyncChannel();
|
||||
chan.connect(context, this, msg.replyTo);
|
||||
chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
void stop() {
|
||||
getLooper().quitSafely();
|
||||
}
|
||||
|
||||
static MockServiceHandler create(Context context) {
|
||||
HandlerThread t = new HandlerThread("mock-service-handler");
|
||||
t.start();
|
||||
return new MockServiceHandler(t.getLooper(), context);
|
||||
}
|
||||
int getRequestKey(ExceptionUtils.ThrowingConsumer<ArgumentCaptor<Integer>> verifier)
|
||||
throws Exception {
|
||||
final ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);
|
||||
verifier.accept(captor);
|
||||
return captor.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import static libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChange
|
||||
import static libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -33,14 +34,19 @@ import static org.mockito.Mockito.when;
|
||||
import android.compat.testing.PlatformCompatChangeRule;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.net.nsd.INsdManagerCallback;
|
||||
import android.net.nsd.INsdServiceConnector;
|
||||
import android.net.nsd.NsdManager;
|
||||
import android.net.nsd.NsdServiceInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.NsdService.DaemonConnection;
|
||||
@@ -56,11 +62,15 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.AdditionalAnswers;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
// TODOs:
|
||||
// - test client can send requests and receive replies
|
||||
// - test NSD_ON ENABLE/DISABLED listening
|
||||
@@ -73,6 +83,11 @@ public class NsdServiceTest {
|
||||
private static final long CLEANUP_DELAY_MS = 500;
|
||||
private static final long TIMEOUT_MS = 500;
|
||||
|
||||
// Records INsdManagerCallback created when NsdService#connect is called.
|
||||
// Only accessed on the test thread, since NsdService#connect is called by the NsdManager
|
||||
// constructor called on the test thread.
|
||||
private final Queue<INsdManagerCallback> mCreatedCallbacks = new LinkedList<>();
|
||||
|
||||
@Rule
|
||||
public TestRule compatChangeRule = new PlatformCompatChangeRule();
|
||||
@Mock Context mContext;
|
||||
@@ -83,6 +98,16 @@ public class NsdServiceTest {
|
||||
HandlerThread mThread;
|
||||
TestHandler mHandler;
|
||||
|
||||
private static class LinkToDeathRecorder extends Binder {
|
||||
IBinder.DeathRecipient mDr;
|
||||
|
||||
@Override
|
||||
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {
|
||||
super.linkToDeath(recipient, flags);
|
||||
mDr = recipient;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -103,26 +128,30 @@ public class NsdServiceTest {
|
||||
|
||||
@Test
|
||||
@DisableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testPreSClients() {
|
||||
public void testPreSClients() throws Exception {
|
||||
when(mSettings.isEnabled()).thenReturn(true);
|
||||
NsdService service = makeService();
|
||||
|
||||
// Pre S client connected, the daemon should be started.
|
||||
NsdManager client1 = connectClient(service);
|
||||
connectClient(service);
|
||||
waitForIdle();
|
||||
final INsdManagerCallback cb1 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
|
||||
verify(mDaemon, times(1)).maybeStart();
|
||||
verifyDaemonCommands("start-service");
|
||||
|
||||
NsdManager client2 = connectClient(service);
|
||||
connectClient(service);
|
||||
waitForIdle();
|
||||
final INsdManagerCallback cb2 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
|
||||
verify(mDaemon, times(1)).maybeStart();
|
||||
|
||||
client1.disconnect();
|
||||
deathRecipient1.binderDied();
|
||||
// Still 1 client remains, daemon shouldn't be stopped.
|
||||
waitForIdle();
|
||||
verify(mDaemon, never()).maybeStop();
|
||||
|
||||
client2.disconnect();
|
||||
deathRecipient2.binderDied();
|
||||
// All clients are disconnected, the daemon should be stopped.
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
verifyDaemonCommands("stop-service");
|
||||
@@ -130,43 +159,51 @@ public class NsdServiceTest {
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testNoDaemonStartedWhenClientsConnect() {
|
||||
public void testNoDaemonStartedWhenClientsConnect() throws Exception {
|
||||
when(mSettings.isEnabled()).thenReturn(true);
|
||||
|
||||
NsdService service = makeService();
|
||||
final NsdService service = makeService();
|
||||
|
||||
// Creating an NsdManager will not cause any cmds executed, which means
|
||||
// no daemon is started.
|
||||
NsdManager client1 = connectClient(service);
|
||||
connectClient(service);
|
||||
waitForIdle();
|
||||
verify(mDaemon, never()).execute(any());
|
||||
final INsdManagerCallback cb1 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient1 = verifyLinkToDeath(cb1);
|
||||
|
||||
// Creating another NsdManager will not cause any cmds executed.
|
||||
NsdManager client2 = connectClient(service);
|
||||
connectClient(service);
|
||||
waitForIdle();
|
||||
verify(mDaemon, never()).execute(any());
|
||||
final INsdManagerCallback cb2 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient2 = verifyLinkToDeath(cb2);
|
||||
|
||||
// If there is no active request, try to clean up the daemon
|
||||
// every time the client disconnects.
|
||||
client1.disconnect();
|
||||
deathRecipient1.binderDied();
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
reset(mDaemon);
|
||||
client2.disconnect();
|
||||
deathRecipient2.binderDied();
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
}
|
||||
|
||||
client1.disconnect();
|
||||
client2.disconnect();
|
||||
private IBinder.DeathRecipient verifyLinkToDeath(INsdManagerCallback cb)
|
||||
throws Exception {
|
||||
final IBinder.DeathRecipient dr = ((LinkToDeathRecorder) cb.asBinder()).mDr;
|
||||
assertNotNull(dr);
|
||||
return dr;
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testClientRequestsAreGCedAtDisconnection() {
|
||||
public void testClientRequestsAreGCedAtDisconnection() throws Exception {
|
||||
when(mSettings.isEnabled()).thenReturn(true);
|
||||
|
||||
NsdService service = makeService();
|
||||
NsdManager client = connectClient(service);
|
||||
|
||||
NsdManager client = connectClient(service);
|
||||
waitForIdle();
|
||||
final INsdManagerCallback cb1 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
|
||||
verify(mDaemon, never()).maybeStart();
|
||||
verify(mDaemon, never()).execute(any());
|
||||
|
||||
@@ -195,18 +232,16 @@ public class NsdServiceTest {
|
||||
verifyDaemonCommand("resolve 4 a_name a_type local.");
|
||||
|
||||
// Client disconnects, stop the daemon after CLEANUP_DELAY_MS.
|
||||
client.disconnect();
|
||||
deathRecipient.binderDied();
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
// checks that request are cleaned
|
||||
verifyDaemonCommands("stop-register 2", "stop-discover 3",
|
||||
"stop-resolve 4", "stop-service");
|
||||
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges(NsdManager.RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)
|
||||
public void testCleanupDelayNoRequestActive() {
|
||||
public void testCleanupDelayNoRequestActive() throws Exception {
|
||||
when(mSettings.isEnabled()).thenReturn(true);
|
||||
|
||||
NsdService service = makeService();
|
||||
@@ -218,6 +253,8 @@ public class NsdServiceTest {
|
||||
client.registerService(request, PROTOCOL, listener1);
|
||||
waitForIdle();
|
||||
verify(mDaemon, times(1)).maybeStart();
|
||||
final INsdManagerCallback cb1 = getCallback();
|
||||
final IBinder.DeathRecipient deathRecipient = verifyLinkToDeath(cb1);
|
||||
verifyDaemonCommands("start-service", "register 2 a_name a_type 2201");
|
||||
|
||||
client.unregisterService(listener1);
|
||||
@@ -226,7 +263,7 @@ public class NsdServiceTest {
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
verifyDaemonCommand("stop-service");
|
||||
reset(mDaemon);
|
||||
client.disconnect();
|
||||
deathRecipient.binderDied();
|
||||
// Client disconnects, after CLEANUP_DELAY_MS, maybeStop the daemon.
|
||||
verifyDelayMaybeStopDaemon(CLEANUP_DELAY_MS);
|
||||
}
|
||||
@@ -240,12 +277,29 @@ public class NsdServiceTest {
|
||||
mDaemonCallback = callback;
|
||||
return mDaemon;
|
||||
};
|
||||
NsdService service = new NsdService(mContext, mSettings,
|
||||
mHandler, supplier, CLEANUP_DELAY_MS);
|
||||
final NsdService service = new NsdService(mContext, mSettings,
|
||||
mHandler, supplier, CLEANUP_DELAY_MS) {
|
||||
@Override
|
||||
public INsdServiceConnector connect(INsdManagerCallback baseCb) {
|
||||
// Wrap the callback in a transparent mock, to mock asBinder returning a
|
||||
// LinkToDeathRecorder. This will allow recording the binder death recipient
|
||||
// registered on the callback. Use a transparent mock and not a spy as the actual
|
||||
// implementation class is not public and cannot be spied on by Mockito.
|
||||
final INsdManagerCallback cb = mock(INsdManagerCallback.class,
|
||||
AdditionalAnswers.delegatesTo(baseCb));
|
||||
doReturn(new LinkToDeathRecorder()).when(cb).asBinder();
|
||||
mCreatedCallbacks.add(cb);
|
||||
return super.connect(cb);
|
||||
}
|
||||
};
|
||||
verify(mDaemon, never()).execute(any(String.class));
|
||||
return service;
|
||||
}
|
||||
|
||||
private INsdManagerCallback getCallback() {
|
||||
return mCreatedCallbacks.remove();
|
||||
}
|
||||
|
||||
NsdManager connectClient(NsdService service) {
|
||||
return new NsdManager(mContext, service);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user