From 36612d27b67ff2e79ffff8eb12d95d2058abde02 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 Jul 2012 17:42:25 -0700 Subject: Move notification tests to LittleMock. Directly mock NotificationManager instead of using SystemFacade. Change-Id: If932d26e23816e8674469c275a828701cce5fc2d --- .../providers/downloads/DownloadNotification.java | 15 +++--- .../providers/downloads/DownloadReceiver.java | 5 +- .../providers/downloads/DownloadService.java | 10 ++-- .../providers/downloads/RealSystemFacade.java | 43 +++++++---------- .../android/providers/downloads/SystemFacade.java | 32 ++++++------- tests/Android.mk | 2 +- .../AbstractDownloadProviderFunctionalTest.java | 28 +++++------ .../providers/downloads/FakeSystemFacade.java | 29 ----------- .../downloads/PublicApiFunctionalTest.java | 56 +++++++++++++++++----- 9 files changed, 108 insertions(+), 112 deletions(-) diff --git a/src/com/android/providers/downloads/DownloadNotification.java b/src/com/android/providers/downloads/DownloadNotification.java index bbd39f60..f5778e79 100644 --- a/src/com/android/providers/downloads/DownloadNotification.java +++ b/src/com/android/providers/downloads/DownloadNotification.java @@ -17,6 +17,7 @@ package com.android.providers.downloads; import android.app.Notification; +import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentUris; import android.content.Context; @@ -38,9 +39,9 @@ import java.util.HashMap; */ class DownloadNotification { - Context mContext; - HashMap mNotifications; - private SystemFacade mSystemFacade; + private Context mContext; + private NotificationManager mNotifManager; + private HashMap mNotifications; /** Time when each {@link DownloadInfo#mId} was first shown. */ private SparseLongArray mFirstShown = new SparseLongArray(); @@ -102,7 +103,8 @@ class DownloadNotification { */ DownloadNotification(Context ctx, SystemFacade systemFacade) { mContext = ctx; - mSystemFacade = systemFacade; + mNotifManager = (NotificationManager) mContext.getSystemService( + Context.NOTIFICATION_SERVICE); mNotifications = new HashMap(); } @@ -207,8 +209,7 @@ class DownloadNotification { builder.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); - mSystemFacade.postNotification(item.mId, builder.getNotification()); - + mNotifManager.notify(item.mId, builder.build()); } } @@ -262,7 +263,7 @@ class DownloadNotification { intent.setData(contentUri); builder.setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0)); - mSystemFacade.postNotification(id, builder.getNotification()); + mNotifManager.notify((int) id, builder.build()); } private boolean isActiveAndVisible(DownloadInfo download) { diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index 26ad992e..81ff4040 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -17,6 +17,7 @@ package com.android.providers.downloads; import android.app.DownloadManager; +import android.app.NotificationManager; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentUris; @@ -120,7 +121,9 @@ public class DownloadReceiver extends BroadcastReceiver { * @param cursor Cursor for reading the download's fields */ private void hideNotification(Context context, Uri uri, Cursor cursor) { - mSystemFacade.cancelNotification(ContentUris.parseId(uri)); + final NotificationManager notifManager = (NotificationManager) context.getSystemService( + Context.NOTIFICATION_SERVICE); + notifManager.cancel((int) ContentUris.parseId(uri)); int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS); int status = cursor.getInt(statusColumn); diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java index 55efefcf..7030deae 100644 --- a/src/com/android/providers/downloads/DownloadService.java +++ b/src/com/android/providers/downloads/DownloadService.java @@ -19,6 +19,7 @@ package com.android.providers.downloads; import static com.android.providers.downloads.Constants.TAG; import android.app.AlarmManager; +import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ComponentName; @@ -65,6 +66,7 @@ public class DownloadService extends Service { /** Class to handle Notification Manager updates */ private DownloadNotification mNotifier; + private NotificationManager mNotifManager; /** * The Service's view of the list of downloads, mapping download IDs to the corresponding info @@ -221,7 +223,9 @@ public class DownloadService extends Service { mMediaScannerConnection = new MediaScannerConnection(); mNotifier = new DownloadNotification(this, mSystemFacade); - mSystemFacade.cancelAllNotifications(); + mNotifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + mNotifManager.cancelAll(); + mStorageManager = StorageManager.getInstance(getApplicationContext()); updateFromProvider(); } @@ -464,7 +468,7 @@ public class DownloadService extends Service { !Downloads.Impl.isStatusCompleted(oldStatus) && Downloads.Impl.isStatusCompleted(info.mStatus); if (lostVisibility || justCompleted) { - mSystemFacade.cancelNotification(info.mId); + mNotifManager.cancel((int) info.mId); } info.startIfReady(now, mStorageManager); @@ -487,7 +491,7 @@ public class DownloadService extends Service { } new File(info.mFileName).delete(); } - mSystemFacade.cancelNotification(info.mId); + mNotifManager.cancel((int) info.mId); mDownloads.remove(info.mId); } diff --git a/src/com/android/providers/downloads/RealSystemFacade.java b/src/com/android/providers/downloads/RealSystemFacade.java index 6580f909..228c7165 100644 --- a/src/com/android/providers/downloads/RealSystemFacade.java +++ b/src/com/android/providers/downloads/RealSystemFacade.java @@ -1,26 +1,35 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.android.providers.downloads; import android.app.DownloadManager; -import android.app.Notification; -import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.provider.Settings; -import android.provider.Settings.SettingNotFoundException; import android.telephony.TelephonyManager; import android.util.Log; class RealSystemFacade implements SystemFacade { private Context mContext; - private NotificationManager mNotificationManager; public RealSystemFacade(Context context) { mContext = context; - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); } public long currentTimeMillis() { @@ -84,26 +93,6 @@ class RealSystemFacade implements SystemFacade { return mContext.getPackageManager().getApplicationInfo(packageName, 0).uid == uid; } - @Override - public void postNotification(long id, Notification notification) { - /** - * TODO: The system notification manager takes ints, not longs, as IDs, but the download - * manager uses IDs take straight from the database, which are longs. This will have to be - * dealt with at some point. - */ - mNotificationManager.notify((int) id, notification); - } - - @Override - public void cancelNotification(long id) { - mNotificationManager.cancel((int) id); - } - - @Override - public void cancelAllNotifications() { - mNotificationManager.cancelAll(); - } - @Override public void startThread(Thread thread) { thread.start(); diff --git a/src/com/android/providers/downloads/SystemFacade.java b/src/com/android/providers/downloads/SystemFacade.java index d1439354..fda97e08 100644 --- a/src/com/android/providers/downloads/SystemFacade.java +++ b/src/com/android/providers/downloads/SystemFacade.java @@ -1,12 +1,25 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.android.providers.downloads; -import android.app.Notification; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.NetworkInfo; - interface SystemFacade { /** * @see System#currentTimeMillis() @@ -49,21 +62,6 @@ interface SystemFacade { */ public boolean userOwnsPackage(int uid, String pckg) throws NameNotFoundException; - /** - * Post a system notification to the NotificationManager. - */ - public void postNotification(long id, Notification notification); - - /** - * Cancel a system notification. - */ - public void cancelNotification(long id); - - /** - * Cancel all system notifications. - */ - public void cancelAllNotifications(); - /** * Start a thread. */ diff --git a/tests/Android.mk b/tests/Android.mk index aaf32ba4..ff3e1d47 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -8,7 +8,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_INSTRUMENTATION_FOR := DownloadProvider LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := mockwebserver +LOCAL_STATIC_JAVA_LIBRARIES := mockwebserver littlemock dexmaker LOCAL_PACKAGE_NAME := DownloadProviderTests LOCAL_CERTIFICATE := media diff --git a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java index 1912e84c..a65693fa 100644 --- a/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java +++ b/tests/src/com/android/providers/downloads/AbstractDownloadProviderFunctionalTest.java @@ -16,6 +16,9 @@ package com.android.providers.downloads; +import static com.google.testing.littlemock.LittleMock.mock; + +import android.app.NotificationManager; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -42,9 +45,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.UnknownHostException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; public abstract class AbstractDownloadProviderFunctionalTest extends ServiceTestCase { @@ -94,19 +94,14 @@ public abstract class AbstractDownloadProviderFunctionalTest extends static class TestContext extends RenamingDelegatingContext { private static final String FILENAME_PREFIX = "test."; - private Context mRealContext; - private Set mAllowedSystemServices; private ContentResolver mResolver; + private final NotificationManager mNotifManager; boolean mHasServiceBeenStarted = false; public TestContext(Context realContext) { super(realContext, FILENAME_PREFIX); - mRealContext = realContext; - mAllowedSystemServices = new HashSet(Arrays.asList(new String[] { - Context.NOTIFICATION_SERVICE, - Context.POWER_SERVICE, - })); + mNotifManager = mock(NotificationManager.class); } public void setResolver(ContentResolver resolver) { @@ -118,7 +113,6 @@ public abstract class AbstractDownloadProviderFunctionalTest extends */ @Override public ContentResolver getContentResolver() { - assert mResolver != null; return mResolver; } @@ -127,9 +121,10 @@ public abstract class AbstractDownloadProviderFunctionalTest extends */ @Override public Object getSystemService(String name) { - if (mAllowedSystemServices.contains(name)) { - return mRealContext.getSystemService(name); + if (Context.NOTIFICATION_SERVICE.equals(name)) { + return mNotifManager; } + return super.getSystemService(name); } @@ -155,10 +150,13 @@ public abstract class AbstractDownloadProviderFunctionalTest extends protected void setUp() throws Exception { super.setUp(); - Context realContext = getContext(); + // Since we're testing a system app, AppDataDirGuesser doesn't find our + // cache dir, so set it explicitly. + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); + + final Context realContext = getContext(); mTestContext = new TestContext(realContext); setupProviderAndResolver(); - mTestContext.setResolver(mResolver); setContext(mTestContext); setupService(); diff --git a/tests/src/com/android/providers/downloads/FakeSystemFacade.java b/tests/src/com/android/providers/downloads/FakeSystemFacade.java index c184de83..6898efdb 100644 --- a/tests/src/com/android/providers/downloads/FakeSystemFacade.java +++ b/tests/src/com/android/providers/downloads/FakeSystemFacade.java @@ -1,17 +1,13 @@ package com.android.providers.downloads; -import android.app.Notification; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.test.AssertionFailedError; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Queue; public class FakeSystemFacade implements SystemFacade { @@ -22,8 +18,6 @@ public class FakeSystemFacade implements SystemFacade { Long mMaxBytesOverMobile = null; Long mRecommendedMaxBytesOverMobile = null; List mBroadcastsSent = new ArrayList(); - Map mActiveNotifications = new HashMap(); - List mCanceledNotifications = new ArrayList(); Queue mStartedThreads = new LinkedList(); private boolean returnActualTime = false; @@ -73,29 +67,6 @@ public class FakeSystemFacade implements SystemFacade { return true; } - @Override - public void postNotification(long id, Notification notification) { - if (notification == null) { - throw new AssertionFailedError("Posting null notification"); - } - mActiveNotifications.put(id, notification); - } - - @Override - public void cancelNotification(long id) { - Notification notification = mActiveNotifications.remove(id); - if (notification != null) { - mCanceledNotifications.add(notification); - } - } - - @Override - public void cancelAllNotifications() { - for (long id : mActiveNotifications.keySet()) { - cancelNotification(id); - } - } - public boolean startThreadsWithoutWaiting = false; public void setStartThreadsWithoutWaiting(boolean flag) { this.startThreadsWithoutWaiting = flag; diff --git a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java index 2f5282ae..34a69df9 100644 --- a/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java +++ b/tests/src/com/android/providers/downloads/PublicApiFunctionalTest.java @@ -16,7 +16,17 @@ package com.android.providers.downloads; +import static com.google.testing.littlemock.LittleMock.anyInt; +import static com.google.testing.littlemock.LittleMock.atLeastOnce; +import static com.google.testing.littlemock.LittleMock.isA; +import static com.google.testing.littlemock.LittleMock.never; +import static com.google.testing.littlemock.LittleMock.times; +import static com.google.testing.littlemock.LittleMock.verify; + import android.app.DownloadManager; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.ConnectivityManager; @@ -24,7 +34,6 @@ import android.net.Uri; import android.os.Environment; import android.provider.Downloads; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; import com.google.mockwebserver.MockResponse; import com.google.mockwebserver.RecordedRequest; @@ -37,12 +46,14 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.util.List; + @LargeTest public class PublicApiFunctionalTest extends AbstractPublicApiTest { private static final String REDIRECTED_PATH = "/other_path"; private static final String ETAG = "my_etag"; protected File mTestDirectory; + private NotificationManager mNotifManager; public PublicApiFunctionalTest() { super(new FakeSystemFacade()); @@ -52,6 +63,9 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest { protected void setUp() throws Exception { super.setUp(); + mNotifManager = (NotificationManager) getContext() + .getSystemService(Context.NOTIFICATION_SERVICE); + mTestDirectory = new File(Environment.getExternalStorageDirectory() + File.separator + "download_manager_functional_test"); if (mTestDirectory.exists()) { @@ -501,24 +515,42 @@ public class PublicApiFunctionalTest extends AbstractPublicApiTest { assertTrue(mResolver.mNotifyWasCalled); } - public void testNotifications() throws Exception { - enqueueResponse(buildEmptyResponse(HTTP_OK)); + public void testNotificationNever() throws Exception { enqueueResponse(buildEmptyResponse(HTTP_OK)); - Download download = enqueueRequest(getRequest().setShowRunningNotification(false)); + final Download download = enqueueRequest( + getRequest().setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN)); download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); - assertEquals(0, mSystemFacade.mActiveNotifications.size()); - assertEquals(0, mSystemFacade.mCanceledNotifications.size()); + runService(); + + verify(mNotifManager, never()).notify(anyInt(), isA(Notification.class)); + // TODO: verify that it never cancels + } + + public void testNotificationVisible() throws Exception { + enqueueResponse(buildEmptyResponse(HTTP_OK)); - download = enqueueRequest(getRequest()); // notifications by default + // only shows in-progress notifications + final Download download = enqueueRequest(getRequest()); download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); - assertEquals(1, mSystemFacade.mActiveNotifications.size()); + runService(); + + // TODO: verify different notif types with tags + verify(mNotifManager, atLeastOnce()).notify(anyInt(), isA(Notification.class)); + verify(mNotifManager, times(1)).cancel(anyInt()); + } - // The notification doesn't actually get canceled until the UpdateThread runs again, which - // gets triggered by the DownloadThread updating the status in the provider. + public void testNotificationVisibleComplete() throws Exception { + enqueueResponse(buildEmptyResponse(HTTP_OK)); + + final Download download = enqueueRequest(getRequest().setNotificationVisibility( + DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)); + download.runUntilStatus(DownloadManager.STATUS_SUCCESSFUL); runService(); - assertEquals(0, mSystemFacade.mActiveNotifications.size()); - assertEquals(1, mSystemFacade.mCanceledNotifications.size()); + + // TODO: verify different notif types with tags + verify(mNotifManager, atLeastOnce()).notify(anyInt(), isA(Notification.class)); + verify(mNotifManager, times(1)).cancel(anyInt()); } public void testRetryAfter() throws Exception { -- cgit v1.2.3