diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 4405c1b6135a9..97f913e69d952 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -49,7 +49,6 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; -import android.os.IBinder; import android.os.IDeviceIdleController; import android.os.IMaintenanceActivityListener; import android.os.Looper; @@ -1238,7 +1237,7 @@ public class DeviceIdleController extends SystemService } } - public final class LocalService { + public class LocalService { public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync, String reason) { addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason); diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 8d36ac993e527..d8904448ae19e 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -16,17 +16,12 @@ package com.android.server; -import static android.content.Intent.ACTION_UID_REMOVED; -import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.NetworkPolicy.CYCLE_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; -import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; -import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.computeNextCycleBoundary; import static android.net.TrafficStats.KB_IN_BYTES; @@ -34,28 +29,36 @@ import static android.net.TrafficStats.MB_IN_BYTES; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.Time.TIMEZONE_UTC; + import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT; import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED; import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING; -import static org.easymock.EasyMock.anyInt; -import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.aryEq; -import static org.easymock.EasyMock.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.isA; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; import android.app.IActivityManager; import android.app.INotificationManager; -import android.app.IProcessObserver; +import android.app.IUidObserver; import android.app.Notification; +import android.app.usage.UsageStatsManagerInternal; +import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.Signature; -import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; @@ -69,39 +72,40 @@ import android.net.NetworkStats; import android.net.NetworkTemplate; import android.os.Binder; import android.os.INetworkManagementService; -import android.os.MessageQueue.IdleHandler; +import android.os.PowerManagerInternal; import android.os.UserHandle; import android.test.AndroidTestCase; -import android.test.mock.MockPackageManager; -import android.test.suitebuilder.annotation.LargeTest; -import android.test.suitebuilder.annotation.Suppress; import android.text.format.Time; +import android.util.Log; import android.util.TrustedTime; import com.android.internal.util.test.BroadcastInterceptingContext; +import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.net.NetworkPolicyManagerService; + +import libcore.io.IoUtils; + import com.google.common.util.concurrent.AbstractFuture; -import org.easymock.Capture; -import org.easymock.EasyMock; -import org.easymock.IAnswer; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.io.File; -import java.util.Calendar; +import java.util.ArrayList; import java.util.LinkedHashSet; -import java.util.TimeZone; +import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.logging.Handler; - -import libcore.io.IoUtils; /** * Tests for {@link NetworkPolicyManagerService}. */ -@LargeTest public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private static final String TAG = "NetworkPolicyManagerServiceTest"; @@ -113,20 +117,22 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private BroadcastInterceptingContext mServiceContext; private File mPolicyDir; + private List> mLocalServices = new ArrayList<>(); - private IActivityManager mActivityManager; - private INetworkStatsService mStatsService; - private INetworkManagementService mNetworkManager; - private INetworkPolicyListener mPolicyListener; - private TrustedTime mTime; - private IConnectivityManager mConnManager; - private INotificationManager mNotifManager; + private @Mock IActivityManager mActivityManager; + private @Mock INetworkStatsService mStatsService; + private @Mock INetworkManagementService mNetworkManager; + private @Mock TrustedTime mTime; + private @Mock IConnectivityManager mConnManager; + private @Mock INotificationManager mNotifManager; + private @Mock UsageStatsManagerInternal mUsageStats; + private @Mock PackageManager mPackageManager; - private NetworkPolicyManagerService mService; - private IProcessObserver mProcessObserver; + private IUidObserver mUidObserver; private INetworkManagementEventObserver mNetworkObserver; - private Binder mStubBinder = new Binder(); + private NetworkPolicyListenerAnswer mPolicyListener; + private NetworkPolicyManagerService mService; private long mStartTime; private long mElapsedRealtime; @@ -139,39 +145,22 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private static final int UID_A = UserHandle.getUid(USER_ID, APP_ID_A); private static final int UID_B = UserHandle.getUid(USER_ID, APP_ID_B); - private static final int PID_1 = 400; - private static final int PID_2 = 401; - private static final int PID_3 = 402; + private static final String PKG_NAME_A = "name.is.A,pkg.A"; - public void _setUp() throws Exception { + public void setUp() throws Exception { super.setUp(); + MockitoAnnotations.initMocks(this); + + final Context context = getContext(); + setCurrentTimeMillis(TEST_START); // intercept various broadcasts, and pretend that uids have packages - mServiceContext = new BroadcastInterceptingContext(getContext()) { + mServiceContext = new BroadcastInterceptingContext(context) { @Override public PackageManager getPackageManager() { - return new MockPackageManager() { - @Override - public String[] getPackagesForUid(int uid) { - return new String[] { "com.example" }; - } - - @Override - public PackageInfo getPackageInfo(String packageName, int flags) { - final PackageInfo info = new PackageInfo(); - final Signature signature; - if ("android".equals(packageName)) { - signature = new Signature("F00D"); - } else { - signature = new Signature("DEAD"); - } - info.signatures = new Signature[] { signature }; - return info; - } - - }; + return mPackageManager; } @Override @@ -180,54 +169,69 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } }; - mPolicyDir = getContext().getFilesDir(); + mPolicyDir = context.getFilesDir(); if (mPolicyDir.exists()) { IoUtils.deleteContents(mPolicyDir); } - mActivityManager = createMock(IActivityManager.class); - mStatsService = createMock(INetworkStatsService.class); - mNetworkManager = createMock(INetworkManagementService.class); - mPolicyListener = createMock(INetworkPolicyListener.class); - mTime = createMock(TrustedTime.class); - mConnManager = createMock(IConnectivityManager.class); - mNotifManager = createMock(INotificationManager.class); + doAnswer(new Answer() { - mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, - mStatsService, mNetworkManager, mTime, mPolicyDir, true); + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + mUidObserver = (IUidObserver) invocation.getArguments()[0]; + Log.d(TAG, "set mUidObserver to " + mUidObserver); + return null; + } + }).when(mActivityManager).registerUidObserver(any(), anyInt()); + + addLocalServiceMock(PowerManagerInternal.class); + addLocalServiceMock(DeviceIdleController.LocalService.class); + addLocalServiceMock(UsageStatsManagerInternal.class, mUsageStats); + + mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService, + mNetworkManager, mTime, mPolicyDir, true); mService.bindConnectivityManager(mConnManager); mService.bindNotificationManager(mNotifManager); + mPolicyListener = new NetworkPolicyListenerAnswer(mService); - // RemoteCallbackList needs a binder to use as key - expect(mPolicyListener.asBinder()).andReturn(mStubBinder).atLeastOnce(); - replay(); - mService.registerListener(mPolicyListener); - verifyAndReset(); + // Sets some common expectations. + when(mPackageManager.getPackageInfo(anyString(), anyInt())).thenAnswer( + new Answer() { - // catch IProcessObserver during systemReady() - final Capture processObserver = new Capture(); - mActivityManager.registerProcessObserver(capture(processObserver)); - expectLastCall().atLeastOnce(); - - // catch INetworkManagementEventObserver during systemReady() - final Capture networkObserver = new Capture< - INetworkManagementEventObserver>(); - mNetworkManager.registerObserver(capture(networkObserver)); - expectLastCall().atLeastOnce(); - - expect(mNetworkManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce(); + @Override + public PackageInfo answer(InvocationOnMock invocation) throws Throwable { + final String packageName = (String) invocation.getArguments()[0]; + final PackageInfo info = new PackageInfo(); + final Signature signature; + if ("android".equals(packageName)) { + signature = new Signature("F00D"); + } else { + signature = new Signature("DEAD"); + } + info.signatures = new Signature[] { + signature + }; + return info; + } + }); + when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(new ApplicationInfo()); + when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A}); + when(mUsageStats.getIdleUidsForUser(anyInt())).thenReturn(new int[]{}); + when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true); expectCurrentTime(); - replay(); + // Prepare NPMS. mService.systemReady(); - verifyAndReset(); - mProcessObserver = processObserver.getValue(); + // catch INetworkManagementEventObserver during systemReady() + ArgumentCaptor networkObserver = + ArgumentCaptor.forClass(INetworkManagementEventObserver.class); + verify(mNetworkManager).registerObserver(networkObserver.capture()); mNetworkObserver = networkObserver.getValue(); - } - public void _tearDown() throws Exception { + public void tearDown() throws Exception { for (File file : mPolicyDir.listFiles()) { file.delete(); } @@ -237,170 +241,51 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mActivityManager = null; mStatsService = null; - mPolicyListener = null; mTime = null; mService = null; - mProcessObserver = null; + + // TODO: must remove services, otherwise next test will fail. + // JUnit4 would avoid that hack by using a static setup. + removeLocalServiceMocks(); + + // Added by NetworkPolicyManagerService's constructor. + LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); super.tearDown(); } - @Suppress - public void testPolicyChangeTriggersBroadcast() throws Exception { + // NOTE: testPolicyChangeTriggersListener() and testUidForeground() are too superficial, they + // don't check for side-effects (like calls to NetworkManagementService) neither cover all + // different modes (Data Saver, Battery Saver, Doze, App idle, etc...). + // These scenarios are extensively tested on CTS' HostsideRestrictBackgroundNetworkTests. + + public void testPolicyChangeTriggersListener() throws Exception { + mPolicyListener.expect().onRestrictBackgroundBlacklistChanged(anyInt(), anyBoolean()); + mService.setUidPolicy(APP_ID_A, POLICY_NONE); - - // change background policy and expect broadcast - final Future backgroundChanged = mServiceContext.nextBroadcastIntent( - ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED); - mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); - backgroundChanged.get(); + mPolicyListener.waitAndVerify().onRestrictBackgroundBlacklistChanged(APP_ID_A, true); } - @Suppress - public void testPidForegroundCombined() throws Exception { - IdleFuture idle; - - // push all uid into background - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); - mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); - mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false); - idle.get(); + public void testUidForeground() throws Exception { + // push all uids into background + mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); + mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_SERVICE); assertFalse(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); - // push one of the shared pids into foreground - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true); - idle.get(); + // push one of the uids into foreground + mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_TOP); assertTrue(mService.isUidForeground(UID_A)); assertFalse(mService.isUidForeground(UID_B)); // and swap another uid into foreground - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); - mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true); - idle.get(); + mUidObserver.onUidStateChanged(UID_A, ActivityManager.PROCESS_STATE_SERVICE); + mUidObserver.onUidStateChanged(UID_B, ActivityManager.PROCESS_STATE_TOP); assertFalse(mService.isUidForeground(UID_A)); assertTrue(mService.isUidForeground(UID_B)); - - // push both pid into foreground - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); - mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true); - idle.get(); - assertTrue(mService.isUidForeground(UID_A)); - - // pull one out, should still be foreground - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); - idle.get(); - assertTrue(mService.isUidForeground(UID_A)); - - // pull final pid out, should now be background - idle = expectIdle(); - mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false); - idle.get(); - assertFalse(mService.isUidForeground(UID_A)); - } - - @Suppress - public void testPolicyNone() throws Exception { - Future future; - - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, true); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); - future.get(); - verifyAndReset(); - - // POLICY_NONE should RULE_ALLOW in foreground - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, true); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mService.setUidPolicy(APP_ID_A, POLICY_NONE); - future.get(); - verifyAndReset(); - - // POLICY_NONE should RULE_ALLOW in background - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); - future.get(); - verifyAndReset(); - } - - @Suppress - public void testPolicyReject() throws Exception { - Future future; - - // POLICY_REJECT should RULE_ALLOW in background - expectSetUidMeteredNetworkBlacklist(UID_A, true); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_REJECT_METERED); - replay(); - mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); - future.get(); - verifyAndReset(); - - // POLICY_REJECT should RULE_ALLOW in foreground - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, true); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true); - future.get(); - verifyAndReset(); - - // POLICY_REJECT should RULE_REJECT in background - expectSetUidMeteredNetworkBlacklist(UID_A, true); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_REJECT_METERED); - replay(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); - future.get(); - verifyAndReset(); - } - - @Suppress - public void testPolicyRejectAddRemove() throws Exception { - Future future; - - // POLICY_NONE should have RULE_ALLOW in background - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false); - mService.setUidPolicy(APP_ID_A, POLICY_NONE); - future.get(); - verifyAndReset(); - - // adding POLICY_REJECT should cause RULE_REJECT - expectSetUidMeteredNetworkBlacklist(UID_A, true); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_REJECT_METERED); - replay(); - mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); - future.get(); - verifyAndReset(); - - // removing POLICY_REJECT should return us to RULE_ALLOW - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - mService.setUidPolicy(APP_ID_A, POLICY_NONE); - future.get(); - verifyAndReset(); } public void testLastCycleBoundaryThisMonth() throws Exception { @@ -545,11 +430,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { assertTimeEquals(expectedCycle, actualCycle); } - @Suppress public void testNetworkPolicyAppliedCycleLastMonth() throws Exception { NetworkState[] state = null; NetworkStats stats = null; - Future future; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -560,75 +443,39 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // first, pretend that wifi network comes online. no policy active, // which means we shouldn't push limit to interface. state = new NetworkState[] { buildWifi() }; - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + when(mConnManager.getAllNetworkState()).thenReturn(state); expectCurrentTime(); - expectClearNotifications(); - expectAdvisePersistThreshold(); - future = expectMeteredIfacesChanged(); - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - future.get(); - verifyAndReset(); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); // now change cycle to be on 15th, and test in early march, to verify we // pick cycle day in previous month. - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + when(mConnManager.getAllNetworkState()).thenReturn(state); expectCurrentTime(); // pretend that 512 bytes total have happened stats = new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) + .thenReturn(stats.getTotalBytes()); - // TODO: consider making strongly ordered mock - expectRemoveInterfaceQuota(TEST_IFACE); - expectSetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512); - - expectClearNotifications(); - expectAdvisePersistThreshold(); - future = expectMeteredIfacesChanged(TEST_IFACE); - - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); setNetworkPolicies(new NetworkPolicy( sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); - future.get(); - verifyAndReset(); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + + // TODO: consider making strongly ordered mock + verifyPolicyDataEnable(TYPE_WIFI, true); + verifyRemoveInterfaceQuota(TEST_IFACE); + verifySetInterfaceQuota(TEST_IFACE, (2 * MB_IN_BYTES) - 512); } - @Suppress - public void testUidRemovedPolicyCleared() throws Exception { - Future future; - - // POLICY_REJECT should RULE_REJECT in background - expectSetUidMeteredNetworkBlacklist(UID_A, true); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_REJECT_METERED); - replay(); - mService.setUidPolicy(APP_ID_A, POLICY_REJECT_METERED_BACKGROUND); - future.get(); - verifyAndReset(); - - // uninstall should clear RULE_REJECT - expectSetUidMeteredNetworkBlacklist(UID_A, false); - expectSetUidForeground(UID_A, false); - future = expectRulesChanged(UID_A, RULE_ALLOW_ALL); - replay(); - final Intent intent = new Intent(ACTION_UID_REMOVED); - intent.putExtra(EXTRA_UID, UID_A); - mServiceContext.sendBroadcast(intent); - future.get(); - verifyAndReset(); - } - - @Suppress public void testOverWarningLimitNotification() throws Exception { NetworkState[] state = null; NetworkStats stats = null; - Future future; - Future tagFuture; + Future tagFuture = null; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -643,20 +490,15 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); + when(mConnManager.getAllNetworkState()).thenReturn(state); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); - expectClearNotifications(); - expectAdvisePersistThreshold(); - future = expectMeteredIfacesChanged(); - - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false)); - future.get(); - verifyAndReset(); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(any()); + verifyPolicyDataEnable(TYPE_WIFI, true); } // bring up wifi network @@ -667,22 +509,17 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); + when(mConnManager.getAllNetworkState()).thenReturn(state); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); - expectRemoveInterfaceQuota(TEST_IFACE); - expectSetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES); - - expectClearNotifications(); - expectAdvisePersistThreshold(); - future = expectMeteredIfacesChanged(TEST_IFACE); - - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION)); - future.get(); - verifyAndReset(); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + + verifyPolicyDataEnable(TYPE_WIFI, true); + verifyRemoveInterfaceQuota(TEST_IFACE); + verifySetInterfaceQuota(TEST_IFACE, 2 * MB_IN_BYTES); } // go over warning, which should kick notification @@ -692,18 +529,15 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); - - expectForceUpdate(); - expectClearNotifications(); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); tagFuture = expectEnqueueNotification(); - replay(); mNetworkObserver.limitReached(null, TEST_IFACE); + assertNotificationType(TYPE_WARNING, tagFuture.get()); - verifyAndReset(); + verifyPolicyDataEnable(TYPE_WIFI, true); + } // go over limit, which should kick notification and dialog @@ -713,18 +547,14 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, false); - - expectForceUpdate(); - expectClearNotifications(); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); tagFuture = expectEnqueueNotification(); - replay(); mNetworkObserver.limitReached(null, TEST_IFACE); + assertNotificationType(TYPE_LIMIT, tagFuture.get()); - verifyAndReset(); + verifyPolicyDataEnable(TYPE_WIFI, false); } // now snooze policy, which should remove quota @@ -732,35 +562,27 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); - - // snoozed interface still has high quota so background data is - // still restricted. - expectRemoveInterfaceQuota(TEST_IFACE); - expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); - expectAdvisePersistThreshold(); - expectMeteredIfacesChanged(TEST_IFACE); - - future = expectClearNotifications(); + when(mConnManager.getAllNetworkState()).thenReturn(state); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); tagFuture = expectEnqueueNotification(); - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); mService.snoozeLimit(sTemplateWifi); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get()); - future.get(); - verifyAndReset(); + // snoozed interface still has high quota so background data is + // still restricted. + verifyRemoveInterfaceQuota(TEST_IFACE); + verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); + verifyPolicyDataEnable(TYPE_WIFI, true); } } - @Suppress public void testMeteredNetworkWithoutLimit() throws Exception { NetworkState[] state = null; NetworkStats stats = null; - Future future; - Future tagFuture; final long TIME_FEB_15 = 1171497600000L; final long TIME_MAR_10 = 1173484800000L; @@ -775,24 +597,19 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { { expectCurrentTime(); - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) - .andReturn(stats.getTotalBytes()).atLeastOnce(); - expectPolicyDataEnable(TYPE_WIFI, true); + when(mConnManager.getAllNetworkState()).thenReturn(state); + when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15, + currentTimeMillis())).thenReturn(stats.getTotalBytes()); - expectRemoveInterfaceQuota(TEST_IFACE); - expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); - - expectClearNotifications(); - expectAdvisePersistThreshold(); - future = expectMeteredIfacesChanged(TEST_IFACE); - - replay(); + mPolicyListener.expect().onMeteredIfacesChanged(any()); setNetworkPolicies(new NetworkPolicy( sTemplateWifi, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, LIMIT_DISABLED, true)); - future.get(); - verifyAndReset(); + mPolicyListener.waitAndVerify().onMeteredIfacesChanged(eq(new String[]{TEST_IFACE})); + + verifyPolicyDataEnable(TYPE_WIFI, true); + verifyRemoveInterfaceQuota(TEST_IFACE); + verifySetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); } } @@ -815,87 +632,36 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } private void expectCurrentTime() throws Exception { - expect(mTime.forceRefresh()).andReturn(false).anyTimes(); - expect(mTime.hasCache()).andReturn(true).anyTimes(); - expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes(); - expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); - expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); - } - - private void expectForceUpdate() throws Exception { - mStatsService.forceUpdate(); - expectLastCall().atLeastOnce(); - } - - private Future expectClearNotifications() throws Exception { - final FutureAnswer future = new FutureAnswer(); - mNotifManager.cancelNotificationWithTag( - isA(String.class), isA(String.class), anyInt(), anyInt()); - expectLastCall().andAnswer(future).anyTimes(); - return future; + when(mTime.forceRefresh()).thenReturn(false); + when(mTime.hasCache()).thenReturn(true); + when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis()); + when(mTime.getCacheAge()).thenReturn(0L); + when(mTime.getCacheCertainty()).thenReturn(0L); } private Future expectEnqueueNotification() throws Exception { - final FutureCapture tag = new FutureCapture(); - mNotifManager.enqueueNotificationWithTag(isA(String.class), isA(String.class), - capture(tag.capture), anyInt(), - isA(Notification.class), isA(int[].class), UserHandle.myUserId()); - return tag; + final FutureAnswer futureAnswer = new FutureAnswer(2); + doAnswer(futureAnswer).when(mNotifManager).enqueueNotificationWithTag( + anyString(), anyString(), anyString() /* capture here (index 2)*/, + anyInt(), isA(Notification.class), isA(int[].class), anyInt()); + return futureAnswer; } - private void expectSetInterfaceQuota(String iface, long quotaBytes) throws Exception { - mNetworkManager.setInterfaceQuota(iface, quotaBytes); - expectLastCall().atLeastOnce(); + private void verifySetInterfaceQuota(String iface, long quotaBytes) throws Exception { + verify(mNetworkManager, atLeastOnce()).setInterfaceQuota(iface, quotaBytes); } - private void expectRemoveInterfaceQuota(String iface) throws Exception { - mNetworkManager.removeInterfaceQuota(iface); - expectLastCall().atLeastOnce(); + private void verifyRemoveInterfaceQuota(String iface) throws Exception { + verify(mNetworkManager, atLeastOnce()).removeInterfaceQuota(iface); } - private void expectSetInterfaceAlert(String iface, long alertBytes) throws Exception { - mNetworkManager.setInterfaceAlert(iface, alertBytes); - expectLastCall().atLeastOnce(); - } - - private void expectRemoveInterfaceAlert(String iface) throws Exception { - mNetworkManager.removeInterfaceAlert(iface); - expectLastCall().atLeastOnce(); - } - - private void expectSetUidMeteredNetworkBlacklist(int uid, boolean rejectOnQuotaInterfaces) - throws Exception { - mNetworkManager.setUidMeteredNetworkBlacklist(uid, rejectOnQuotaInterfaces); - expectLastCall().atLeastOnce(); - } - - private void expectSetUidForeground(int uid, boolean uidForeground) throws Exception { - mStatsService.setUidForeground(uid, uidForeground); - expectLastCall().atLeastOnce(); - } - - private Future expectRulesChanged(int uid, int policy) throws Exception { - final FutureAnswer future = new FutureAnswer(); - mPolicyListener.onUidRulesChanged(eq(uid), eq(policy)); - expectLastCall().andAnswer(future); - return future; - } - - private Future expectMeteredIfacesChanged(String... ifaces) throws Exception { - final FutureAnswer future = new FutureAnswer(); - mPolicyListener.onMeteredIfacesChanged(aryEq(ifaces)); - expectLastCall().andAnswer(future); - return future; - } - - private Future expectPolicyDataEnable(int type, boolean enabled) throws Exception { + private Future verifyPolicyDataEnable(int type, boolean enabled) throws Exception { // TODO: bring back this test return null; } - private void expectAdvisePersistThreshold() throws Exception { - mStatsService.advisePersistThreshold(anyLong()); - expectLastCall().anyTimes(); + private void verifyAdvisePersistThreshold() throws Exception { + verify(mStatsService).advisePersistThreshold(anyLong()); } private static class TestAbstractFuture extends AbstractFuture { @@ -909,50 +675,21 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } } - private static class FutureAnswer extends TestAbstractFuture implements IAnswer { + private static class FutureAnswer extends TestAbstractFuture implements Answer { + private final int index; + + FutureAnswer(int index) { + this.index = index; + } @Override - public Void answer() { - set(null); + public Void answer(InvocationOnMock invocation) throws Throwable { + @SuppressWarnings("unchecked") + T captured = (T) invocation.getArguments()[index]; + set(captured); return null; } } - private static class FutureCapture extends TestAbstractFuture { - public Capture capture = new Capture() { - @Override - public void setValue(T value) { - super.setValue(value); - set(value); - } - }; - } - - private static class IdleFuture extends AbstractFuture implements IdleHandler { - @Override - public Void get() throws InterruptedException, ExecutionException { - try { - return get(5, TimeUnit.SECONDS); - } catch (TimeoutException e) { - throw new RuntimeException(e); - } - } - - @Override - public boolean queueIdle() { - set(null); - return false; - } - } - - /** - * Wait until {@link #mService} internal {@link Handler} is idle. - */ - private IdleFuture expectIdle() { - final IdleFuture future = new IdleFuture(); - mService.addIdleHandler(future); - return future; - } - private static void assertTimeEquals(long expected, long actual) { if (expected != actual) { fail("expected " + formatTime(expected) + " but was actually " + formatTime(actual)); @@ -980,7 +717,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } private static void assertNotificationType(int expected, String actualTag) { - assertEquals( + assertEquals("notification type mismatch for '" + actualTag +"'", Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1)); } @@ -1001,15 +738,78 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mElapsedRealtime += duration; } - private void replay() { - EasyMock.replay(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, - mConnManager, mNotifManager); + /** + * Creates a mock and registers it to {@link LocalServices}. + */ + private T addLocalServiceMock(Class clazz) { + final T mock = mock(clazz); + return addLocalServiceMock(clazz, mock); } - private void verifyAndReset() { - EasyMock.verify(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, - mConnManager, mNotifManager); - EasyMock.reset(mActivityManager, mStatsService, mPolicyListener, mNetworkManager, mTime, - mConnManager, mNotifManager); + /** + * Registers a mock to {@link LocalServices}. + */ + private T addLocalServiceMock(Class clazz, T mock) { + LocalServices.addService(clazz, mock); + mLocalServices.add(clazz); + return mock; + } + + /** + * Unregisters all mocks from {@link LocalServices}. + */ + private void removeLocalServiceMocks() { + for (Class clazz : mLocalServices) { + Log.d(TAG, "removeLocalServiceMock(): " + clazz.getName()); + LocalServices.removeServiceForTest(clazz); + } + mLocalServices.clear(); + } + + /** + * Custom Mockito answer used to verify async {@link INetworkPolicyListener} calls. + * + *

Typical usage: + *


+     *    mPolicyListener.expect().someCallback(any());
+     *    // do something on objects under test
+     *    mPolicyListener.waitAndVerify().someCallback(eq(expectedValue));
+     * 
+ */ + final class NetworkPolicyListenerAnswer implements Answer { + private CountDownLatch latch; + private final INetworkPolicyListener listener; + + NetworkPolicyListenerAnswer(NetworkPolicyManagerService service) { + this.listener = mock(INetworkPolicyListener.class); + // RemoteCallbackList needs a binder to use as key + when(listener.asBinder()).thenReturn(new Binder()); + service.registerListener(listener); + } + + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Log.d(TAG,"counting down on answer: " + invocation); + latch.countDown(); + return null; + } + + INetworkPolicyListener expect() { + assertNull("expect() called before waitAndVerify()", latch); + latch = new CountDownLatch(1); + return doAnswer(this).when(listener); + } + + INetworkPolicyListener waitAndVerify() { + assertNotNull("waitAndVerify() called before expect()", latch); + try { + assertTrue("callback not called in 5 seconds", latch.await(5, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + fail("Thread interrupted before callback called"); + } finally { + latch = null; + } + return verify(listener, atLeastOnce()); + } } }