diff options
author | mvanouwerkerk <mvanouwerkerk@chromium.org> | 2015-12-01 02:45:57 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-01 10:47:28 +0000 |
commit | 37acca793d11829f8006e17da779e706f9667fcc (patch) | |
tree | 91e1a7f38117ba2d1926e1260558ac558a6db84a /chrome/android | |
parent | 20307b827528c927cb508f8057838f92b3913899 (diff) | |
download | chromium_src-37acca793d11829f8006e17da779e706f9667fcc.zip chromium_src-37acca793d11829f8006e17da779e706f9667fcc.tar.gz chromium_src-37acca793d11829f8006e17da779e706f9667fcc.tar.bz2 |
Instrumentation integration test for the Push API on Android.
Checks the happy path of subscribing to push, receiving a push message, and showing a notification. More scenarios to be added later.
BUG=558402
Review URL: https://codereview.chromium.org/1471193006
Cr-Commit-Position: refs/heads/master@{#362371}
Diffstat (limited to 'chrome/android')
7 files changed, 233 insertions, 117 deletions
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 5834ad6..9de720c 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn @@ -321,6 +321,7 @@ android_library("chrome_shared_test_java") { "//chrome/test/android:chrome_java_test_support", "//components/bookmarks/common/android:bookmarks_java", "//components/dom_distiller/android:dom_distiller_core_java", + "//components/gcm_driver/android:gcm_driver_java", "//components/invalidation/impl:java", "//components/invalidation/impl:javatests", "//components/navigation_interception/android:navigation_interception_java", diff --git a/chrome/android/chrome_apk.gyp b/chrome/android/chrome_apk.gyp index f1ca5cd..143397b 100644 --- a/chrome/android/chrome_apk.gyp +++ b/chrome/android/chrome_apk.gyp @@ -290,6 +290,7 @@ '../../chrome/chrome.gyp:chrome_java', '../../chrome/chrome.gyp:chrome_java_test_support', '../../components/components.gyp:invalidation_javatests', + '../../components/components.gyp:gcm_driver_java', '../../components/components.gyp:offline_pages_enums_java', '../../components/components.gyp:precache_javatests', '../../components/components.gyp:web_contents_delegate_android_java', diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS index fc12375..6f2d48d 100644 --- a/chrome/android/javatests/DEPS +++ b/chrome/android/javatests/DEPS @@ -1,6 +1,7 @@ include_rules = [ "+components/bookmarks/common/android/java/src/org/chromium/components/bookmarks", "+components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/core", + "+components/gcm_driver/android/java/src/org/chromium/components/gcm_driver", "+components/navigation_interception", "+components/precache/android/javatests", "+content/public/android/java", diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java new file mode 100644 index 0000000..d812ff2 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationTestBase.java @@ -0,0 +1,138 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.notifications; + +import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; + +import android.app.Notification; + +import org.chromium.base.ThreadUtils; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.preferences.website.ContentSetting; +import org.chromium.chrome.browser.preferences.website.PushNotificationInfo; +import org.chromium.chrome.test.ChromeActivityTestCaseBase; +import org.chromium.chrome.test.util.TestHttpServerClient; +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; + +import java.util.List; +import java.util.concurrent.TimeoutException; + +/** + * Instrumentation tests for the Notification UI Manager implementation on Android. + * + * Web Notifications are only supported on Android JellyBean and beyond. + */ +public class NotificationTestBase extends ChromeActivityTestCaseBase<ChromeActivity> { + /** The maximum time to wait for a criteria to become valid. */ + private static final long MAX_TIME_TO_POLL_MS = scaleTimeout(6000); + + /** The polling interval to wait between checking for a satisfied criteria. */ + private static final long POLLING_INTERVAL_MS = 50; + + private MockNotificationManagerProxy mMockNotificationManager; + + protected NotificationTestBase() { + super(ChromeActivity.class); + } + + /** + * Returns the origin of the HTTP server the test is being ran on. + */ + protected static String getOrigin() { + return TestHttpServerClient.getUrl(""); + } + + /** + * Sets the permission to use Web Notifications for the test HTTP server's origin to |setting|. + */ + protected void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting) + throws InterruptedException, TimeoutException { + final String origin = getOrigin(); + + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + // The notification content setting does not consider the embedder origin. + PushNotificationInfo pushNotificationInfo = + new PushNotificationInfo(origin, "", false); + pushNotificationInfo.setContentSetting(setting); + } + }); + + String permission = runJavaScriptCodeInCurrentTab("Notification.permission"); + if (setting == ContentSetting.ALLOW) { + assertEquals("\"granted\"", permission); + } else if (setting == ContentSetting.BLOCK) { + assertEquals("\"denied\"", permission); + } else { + assertEquals("\"default\"", permission); + } + } + + /** + * Shows a notification with |title| and |options|, waits until it has been displayed and then + * returns the Notification object to the caller. Requires that only a single notification is + * being displayed in the notification manager. + * + * @param title Title of the Web Notification to show. + * @param options Optional map of options to include when showing the notification. + * @return The Android Notification object, as shown in the framework. + */ + protected Notification showAndGetNotification(String title, String options) throws Exception { + runJavaScriptCodeInCurrentTab("showNotification(\"" + title + "\", " + options + ");"); + return waitForNotification().notification; + } + + /** + * Waits until a notification has been displayed and then returns a NotificationEntry object to + * the caller. Requires that only a single notification is displayed. + * + * @return The NotificationEntry object tracked by the MockNotificationManagerProxy. + */ + protected NotificationEntry waitForNotification() throws Exception { + assertTrue(waitForNotificationManagerMutation()); + List<NotificationEntry> notifications = getNotificationEntries(); + assertEquals(1, notifications.size()); + return notifications.get(0); + } + + protected List<NotificationEntry> getNotificationEntries() { + return mMockNotificationManager.getNotifications(); + } + + /** + * Waits for a mutation to occur in the mocked notification manager. This indicates that Chrome + * called into Android to notify or cancel a notification. + * + * @return Whether the wait was successful. + */ + protected boolean waitForNotificationManagerMutation() throws Exception { + return CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + return mMockNotificationManager.getMutationCountAndDecrement() > 0; + } + }, MAX_TIME_TO_POLL_MS, POLLING_INTERVAL_MS); + } + + @Override + public void startMainActivity() throws InterruptedException { + // The NotificationUIManager must be overriden prior to the browser process starting. + mMockNotificationManager = new MockNotificationManagerProxy(); + NotificationUIManager.overrideNotificationManagerForTesting(mMockNotificationManager); + + startMainActivityFromLauncher(); + } + + @Override + protected void tearDown() throws Exception { + NotificationUIManager.overrideNotificationManagerForTesting(null); + + super.tearDown(); + } +} diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java index 4e16212..397d1dc 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java @@ -4,8 +4,6 @@ package org.chromium.chrome.browser.notifications; -import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; - import android.annotation.SuppressLint; import android.app.Notification; import android.content.Context; @@ -16,24 +14,16 @@ import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; -import org.chromium.base.ThreadUtils; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.base.test.util.Feature; -import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.preferences.website.ContentSetting; -import org.chromium.chrome.browser.preferences.website.PushNotificationInfo; import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.chrome.browser.widget.RoundedIconGenerator; -import org.chromium.chrome.test.ChromeActivityTestCaseBase; import org.chromium.chrome.test.util.TestHttpServerClient; -import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy; import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry; -import org.chromium.content.browser.test.util.Criteria; -import org.chromium.content.browser.test.util.CriteriaHelper; import java.util.Arrays; import java.util.List; -import java.util.concurrent.TimeoutException; /** * Instrumentation tests for the Notification UI Manager implementation on Android. @@ -44,106 +34,10 @@ import java.util.concurrent.TimeoutException; @SuppressLint("NewApi") // TODO(peter): fix deprecation warnings crbug.com/528076 @SuppressWarnings("deprecation") -public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<ChromeActivity> { +public class NotificationUIManagerTest extends NotificationTestBase { private static final String NOTIFICATION_TEST_PAGE = TestHttpServerClient.getUrl("chrome/test/data/notifications/android_test.html"); - /** The maximum time to wait for a criteria to become valid. */ - private static final long MAX_TIME_TO_POLL_MS = scaleTimeout(6000); - - /** The polling interval to wait between checking for a satisfied criteria. */ - private static final long POLLING_INTERVAL_MS = 50; - - private MockNotificationManagerProxy mMockNotificationManager; - - public NotificationUIManagerTest() { - super(ChromeActivity.class); - } - - /** - * Returns the origin of the HTTP server the test is being ran on. - */ - private static String getOrigin() { - return TestHttpServerClient.getUrl(""); - } - - /** - * Sets the permission to use Web Notifications for the test HTTP server's origin to |setting|. - */ - private void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting) - throws InterruptedException, TimeoutException { - final String origin = getOrigin(); - - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - // The notification content setting does not consider the embedder origin. - PushNotificationInfo pushNotificationInfo = new PushNotificationInfo( - origin, "", false); - pushNotificationInfo.setContentSetting(setting); - } - }); - - String permission = runJavaScriptCodeInCurrentTab("Notification.permission"); - if (setting == ContentSetting.ALLOW) { - assertEquals("\"granted\"", permission); - } else if (setting == ContentSetting.BLOCK) { - assertEquals("\"denied\"", permission); - } else { - assertEquals("\"default\"", permission); - } - } - - /** - * Shows a notification with |title| and |options|, waits until it has been displayed and then - * returns the Notification object to the caller. Requires that only a single notification is - * being displayed in the notification manager. - * - * @param title Title of the Web Notification to show. - * @param options Optional map of options to include when showing the notification. - * @return The Android Notification object, as shown in the framework. - */ - private Notification showAndGetNotification(String title, String options) throws Exception { - runJavaScriptCodeInCurrentTab("showNotification(\"" + title + "\", " + options + ");"); - assertTrue(waitForNotificationManagerMutation()); - - List<NotificationEntry> notifications = mMockNotificationManager.getNotifications(); - assertEquals(1, notifications.size()); - - return notifications.get(0).notification; - } - - /** - * Waits for a mutation to occur in the mocked notification manager. This indicates that Chrome - * called into Android to notify or cancel a notification. - * - * @return Whether the wait was successful. - */ - private boolean waitForNotificationManagerMutation() throws Exception { - return CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return mMockNotificationManager.getMutationCountAndDecrement() > 0; - } - }, MAX_TIME_TO_POLL_MS, POLLING_INTERVAL_MS); - } - - @Override - public void startMainActivity() throws InterruptedException { - // The NotificationUIManager must be overriden prior to the browser process starting. - mMockNotificationManager = new MockNotificationManagerProxy(); - NotificationUIManager.overrideNotificationManagerForTesting(mMockNotificationManager); - - startMainActivityWithURL(NOTIFICATION_TEST_PAGE); - } - - @Override - protected void tearDown() throws Exception { - NotificationUIManager.overrideNotificationManagerForTesting(null); - - super.tearDown(); - } - /** * Verifies that the intended default properties of a notification will indeed be set on the * Notification object that will be send to Android. @@ -151,6 +45,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testDefaultNotificationProperties() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); Notification notification = showAndGetNotification("MyNotification", "{ body: 'Hello' }"); @@ -188,6 +83,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testNotificationSilentProperty() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); Notification notification = showAndGetNotification("MyNotification", "{ silent: true }"); @@ -203,6 +99,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testShowNotificationWithIcon() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); Notification notification = showAndGetNotification("MyNotification", "{icon: 'icon.png'}"); @@ -223,6 +120,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testShowNotificationWithoutIcon() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); Notification notification = showAndGetNotification("NoIconNotification", "{}"); @@ -254,6 +152,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testEnsureNormalizedIconBehavior() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); // Create a notification to ensure that the NotificationUIManager is initialized. @@ -302,6 +201,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @LargeTest @Feature({"Browser", "Notifications"}) public void testNotificationContentIntentClosesNotification() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); Notification notification = showAndGetNotification("MyNotification", "{}"); @@ -313,9 +213,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome // The Service Worker will close the notification upon receiving the notificationclick // event. This will eventually bubble up to a call to cancel() in the NotificationManager. assertTrue(waitForNotificationManagerMutation()); - - List<NotificationEntry> notifications = mMockNotificationManager.getNotifications(); - assertTrue(notifications.isEmpty()); + assertTrue(getNotificationEntries().isEmpty()); } /** @@ -326,11 +224,12 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @MediumTest @Feature({"Browser", "Notifications"}) public void testNotificationTagReplacement() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); runJavaScriptCodeInCurrentTab("showNotification('MyNotification', {tag: 'myTag'});"); assertTrue(waitForNotificationManagerMutation()); - List<NotificationEntry> notifications = mMockNotificationManager.getNotifications(); + List<NotificationEntry> notifications = getNotificationEntries(); String tag = notifications.get(0).tag; int id = notifications.get(0).id; @@ -338,7 +237,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome assertTrue(waitForNotificationManagerMutation()); // Verify that the notification was successfully replaced. - notifications = mMockNotificationManager.getNotifications(); + notifications = getNotificationEntries(); assertEquals(1, notifications.size()); assertEquals("SecondNotification", notifications.get(0).notification.extras.getString(Notification.EXTRA_TITLE)); @@ -358,12 +257,13 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome @LargeTest @Feature({"Browser", "Notifications"}) public void testShowAndCloseMultipleNotifications() throws Exception { + loadUrl(NOTIFICATION_TEST_PAGE); setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); // Open the first notification and verify it is displayed. runJavaScriptCodeInCurrentTab("showNotification('One');"); assertTrue(waitForNotificationManagerMutation()); - List<NotificationEntry> notifications = mMockNotificationManager.getNotifications(); + List<NotificationEntry> notifications = getNotificationEntries(); assertEquals(1, notifications.size()); Notification notificationOne = notifications.get(0).notification; assertEquals("One", notificationOne.extras.getString(Notification.EXTRA_TITLE)); @@ -371,7 +271,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome // Open the second notification and verify it is displayed. runJavaScriptCodeInCurrentTab("showNotification('Two');"); assertTrue(waitForNotificationManagerMutation()); - notifications = mMockNotificationManager.getNotifications(); + notifications = getNotificationEntries(); assertEquals(2, notifications.size()); Notification notificationTwo = notifications.get(1).notification; assertEquals("Two", notificationTwo.extras.getString(Notification.EXTRA_TITLE)); @@ -395,7 +295,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome // upon receiving the event. notificationOne.contentIntent.send(); assertTrue(waitForNotificationManagerMutation()); - notifications = mMockNotificationManager.getNotifications(); + notifications = getNotificationEntries(); assertEquals(1, notifications.size()); assertEquals("Two", notifications.get(0).notification.extras.getString(Notification.EXTRA_TITLE)); @@ -403,8 +303,7 @@ public class NotificationUIManagerTest extends ChromeActivityTestCaseBase<Chrome // Close the last notification and verify that none remain. notifications.get(0).notification.contentIntent.send(); assertTrue(waitForNotificationManagerMutation()); - notifications = mMockNotificationManager.getNotifications(); - assertTrue(notifications.isEmpty()); + assertTrue(getNotificationEntries().isEmpty()); } /** diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/OWNERS new file mode 100644 index 0000000..59870a7 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/OWNERS @@ -0,0 +1 @@ +file://content/browser/push_messaging/OWNERS
\ No newline at end of file diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/PushMessagingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/PushMessagingTest.java new file mode 100644 index 0000000..e7270ff --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/push_messaging/PushMessagingTest.java @@ -0,0 +1,75 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.push_messaging; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.content.Context; +import android.os.Bundle; +import android.test.suitebuilder.annotation.MediumTest; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.notifications.NotificationTestBase; +import org.chromium.chrome.browser.preferences.website.ContentSetting; +import org.chromium.chrome.test.util.TestHttpServerClient; +import org.chromium.chrome.test.util.browser.TabTitleObserver; +import org.chromium.chrome.test.util.browser.notifications.MockNotificationManagerProxy.NotificationEntry; +import org.chromium.components.gcm_driver.FakeGoogleCloudMessagingSubscriber; +import org.chromium.components.gcm_driver.GCMDriver; + +/** + * Instrumentation tests for the Push API and the integration with the Notifications API on Android. + */ +// TODO(mvanouwerkerk): remove @SuppressLint once crbug.com/501900 is fixed. +@SuppressLint("NewApi") +public class PushMessagingTest extends NotificationTestBase { + private static final String PUSH_TEST_PAGE = TestHttpServerClient.getUrl( + "chrome/test/data/push_messaging/push_messaging_test_android.html"); + private static final String SENDER_ID_BUNDLE_KEY = "from"; + private static final int TITLE_UPDATE_TIMEOUT_SECONDS = 5; + + /** + * Verifies that a notification can be shown from a push event handler in the service worker. + */ + @MediumTest + @Feature({"Browser", "PushMessaging"}) + public void testPushAndShowNotification() throws Exception { + FakeGoogleCloudMessagingSubscriber subscriber = new FakeGoogleCloudMessagingSubscriber(); + GCMDriver.overrideSubscriberForTesting(subscriber); + + loadUrl(PUSH_TEST_PAGE); + setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW); + runScriptAndWaitForTitle("subscribePush()", "subscribe ok"); + + sendPushMessage(subscriber.getLastSubscribeSubtype(), subscriber.getLastSubscribeSource()); + NotificationEntry notificationEntry = waitForNotification(); + assertEquals("push notification", + notificationEntry.notification.extras.getString(Notification.EXTRA_TITLE)); + } + + /** + * Runs {@code script} in the current tab and waits for the tab title to change to + * {@code expectedResult}. + */ + private void runScriptAndWaitForTitle(String script, String expectedResult) throws Exception { + runJavaScriptCodeInCurrentTab(script); + TabTitleObserver titleObserver = + new TabTitleObserver(getActivity().getActivityTab(), expectedResult); + titleObserver.waitForTitleUpdate(TITLE_UPDATE_TIMEOUT_SECONDS); + } + + private void sendPushMessage(final String appId, final String senderId) { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + Context context = getInstrumentation().getTargetContext().getApplicationContext(); + Bundle extras = new Bundle(); + extras.putString(SENDER_ID_BUNDLE_KEY, senderId); + GCMDriver.onMessageReceived(context, appId, extras); + } + }); + } +} |