From 72d0da9899800036be2af7a990fe0505f6e949bf Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 5 Jun 2016 02:20:29 +0900 Subject: [PATCH 1/3] Add a FakeSettingsProvider and use it in ConnectivityServiceTest. This class makes it easier to test code that uses Settings: 1. Real device or emulator settings don't affect the code under test; all settings always start off empty. 2. It's possible to change settings from the test without affecting system settings. 3. No changes are needed to the code under test. The changes to the tests are simple: just add a fake ContentResolver to whatever mock Context is already used by the test, and make that ContentResolver use the fake provider. Bug: 23113288 Change-Id: I5e7e5a87571444ae49ccf551705620675a36cd17 --- .../android/server/ConnectivityServiceTest.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 4fae4a732a..00ba06988d 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; @@ -61,12 +62,15 @@ import android.os.Messenger; import android.os.MessageQueue.IdleHandler; import android.os.Process; import android.os.SystemClock; +import android.provider.Settings; import android.test.AndroidTestCase; +import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; import android.util.Log; import android.util.LogPrinter; +import com.android.internal.util.FakeSettingsProvider; import com.android.internal.util.WakeupMessage; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; @@ -118,8 +122,12 @@ public class ConnectivityServiceTest extends AndroidTestCase { } private class MockContext extends BroadcastInterceptingContext { + private final MockContentResolver mContentResolver; + MockContext(Context base) { super(base); + mContentResolver = new MockContentResolver(); + mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); } @Override @@ -135,10 +143,15 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @Override - public Object getSystemService (String name) { + public Object getSystemService(String name) { if (name == Context.CONNECTIVITY_SERVICE) return mCm; return super.getSystemService(name); } + + @Override + public ContentResolver getContentResolver() { + return mContentResolver; + } } /** From 9fc66e020ac31b932404536754e127930224aae8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 5 Jun 2016 21:00:23 +0900 Subject: [PATCH 2/3] Add a test for mobile data always on. Bug: 23113288 Change-Id: Ia8649061a797367d135bb5576600a7cdc85a822e --- .../android/server/ConnectivityService.java | 11 +++ .../server/ConnectivityServiceTest.java | 67 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5118b3f2ab..7e0e8d4961 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -786,6 +786,17 @@ public class ConnectivityService extends IConnectivityManager.Stub return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId()); } + // Used only for testing. + // TODO: Delete this and either: + // 1. Give Fake SettingsProvider the ability to send settings change notifications (requires + // changing ContentResolver to make registerContentObserver non-final). + // 2. Give FakeSettingsProvider an alternative notification mechanism and have the test use it + // by subclassing SettingsObserver. + @VisibleForTesting + void updateMobileDataAlwaysOn() { + mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON); + } + private void handleMobileDataAlwaysOn() { final boolean enable = (Settings.Global.getInt( mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 0) == 1); diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 00ba06988d..9668d95c3e 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -1490,6 +1490,73 @@ public class ConnectivityServiceTest extends AndroidTestCase { defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent); } + @SmallTest + public void testMobileDataAlwaysOn() throws Exception { + final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); + final NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR).build(); + mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); + + final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory"); + handlerThread.start(); + NetworkCapabilities filter = new NetworkCapabilities() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET); + final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), + mServiceContext, "testFactory", filter); + testFactory.setScoreFilter(40); + + // Register the factory and expect it to start looking for a network. + testFactory.expectAddRequests(1); + testFactory.register(); + testFactory.waitForNetworkRequests(1); + assertTrue(testFactory.getMyStartRequested()); + + // Bring up wifi. The factory stops looking for a network. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + testFactory.expectAddRequests(2); // Because the default request changes score twice. + mWiFiNetworkAgent.connect(true); + testFactory.waitForNetworkRequests(1); + assertFalse(testFactory.getMyStartRequested()); + + ContentResolver cr = mServiceContext.getContentResolver(); + + // Turn on mobile data always on. The factory starts looking again. + testFactory.expectAddRequests(1); + Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1); + mService.updateMobileDataAlwaysOn(); + testFactory.waitForNetworkRequests(2); + assertTrue(testFactory.getMyStartRequested()); + + // Bring up cell data and check that the factory stops looking. + assertEquals(1, mCm.getAllNetworks().length); + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + testFactory.expectAddRequests(2); // Because the cell request changes score twice. + mCellNetworkAgent.connect(true); + cellNetworkCallback.expectCallback(CallbackState.AVAILABLE); + testFactory.waitForNetworkRequests(2); + assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us. + + // Check that cell data stays up. + mService.waitForIdle(); + verifyActiveNetwork(TRANSPORT_WIFI); + assertEquals(2, mCm.getAllNetworks().length); + + // Turn off mobile data always on and expect the request to disappear... + testFactory.expectRemoveRequests(1); + Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0); + mService.updateMobileDataAlwaysOn(); + testFactory.waitForNetworkRequests(1); + + // ... and cell data to be torn down. + cellNetworkCallback.expectCallback(CallbackState.LOST); + assertEquals(1, mCm.getAllNetworks().length); + + testFactory.unregister(); + mCm.unregisterNetworkCallback(cellNetworkCallback); + handlerThread.quit(); + } + private static class TestKeepaliveCallback extends PacketKeepaliveCallback { public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR }; From e9a96608a9d21b8becd94603c3f72d0d28a413d0 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 5 Jun 2016 23:45:25 +0900 Subject: [PATCH 3/3] Don't treat the lingerExpired broadcast specially. NetworkMonitor no longer uses the broadcast for lingering, it uses WakeupMessage instead. Bug: 23113288 Change-Id: Idb0c55fc68cb8f45b3213c7134213904f227852e --- .../com/android/server/ConnectivityServiceTest.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 9668d95c3e..68a35f1b91 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -130,18 +130,6 @@ public class ConnectivityServiceTest extends AndroidTestCase { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); } - @Override - public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { - // PendingIntents sent by the AlarmManager are not intercepted by - // BroadcastInterceptingContext so we must really register the receiver. - // This shouldn't effect the real NetworkMonitors as the action contains a random token. - if (filter.getAction(0).startsWith("android.net.netmon.lingerExpired")) { - return getBaseContext().registerReceiver(receiver, filter); - } else { - return super.registerReceiver(receiver, filter); - } - } - @Override public Object getSystemService(String name) { if (name == Context.CONNECTIVITY_SERVICE) return mCm; @@ -654,7 +642,6 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void waitForIdle() { waitForIdle(TIMEOUT_MS); } - } private interface Criteria {