blob: 11a426c1f11ae27717bf5c13aa831f6f21be3bc1 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2011 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.
import os
import urllib
import pyauto_functional
import pyauto
class NotificationsTest(pyauto.PyUITest):
"""Test of HTML5 desktop notifications."""
def __init__(self, methodName='runTest'):
super(NotificationsTest, self).__init__(methodName)
self.EMPTY_PAGE_URL = self.GetHttpURLForDataPath('empty.html')
# Content settings for default notification permission.
self.ALLOW_ALL_SETTING = 1
self.DENY_ALL_SETTING = 2
self.ASK_SETTING = 3
# HTML page used for notification testing.
self.TEST_PAGE_URL = self.GetFileURLForDataPath(
os.path.join('notifications', 'notification_tester.html'))
def Debug(self):
"""Test method for experimentation.
This method will not run automatically.
"""
while True:
raw_input('Interact with the browser and hit <enter> to dump notification'
'state...')
print '*' * 20
self.pprint(self.GetActiveNotifications())
self.pprint(self._GetDefaultPermissionSetting())
def _SetDefaultPermissionSetting(self, setting):
"""Sets the default setting for whether sites are allowed to create
notifications.
"""
self.SetPrefs(pyauto.kDefaultContentSettings, {u'notifications': setting})
def _GetDefaultPermissionSetting(self):
"""Gets the default setting for whether sites are allowed to create
notifications.
"""
return self.GetPrefsInfo().Prefs(
pyauto.kDefaultContentSettings)[u'notifications']
def _GetDeniedOrigins(self):
"""Gets the list of origins that are explicitly denied to create
notifications.
"""
return (self.GetPrefsInfo().Prefs(pyauto.kDesktopNotificationDeniedOrigins)
or [])
def _GetAllowedOrigins(self):
"""Gets the list of origins that are explicitly allowed to create
notifications.
"""
return (self.GetPrefsInfo().Prefs(pyauto.kDesktopNotificationAllowedOrigins)
or [])
def _SetAllowedOrigins(self, origins):
"""Sets the list of allowed origins to the given list.
None of the items in the list should be explicitly denied.
"""
return self.SetPrefs(pyauto.kDesktopNotificationAllowedOrigins, origins)
def _SetDeniedOrigins(self, origins):
"""Sets the list of denied origins to the given list.
None of the items in the list should be explicitly allowed.
"""
return self.SetPrefs(pyauto.kDesktopNotificationDeniedOrigins, origins)
def _DenyOrigin(self, new_origin):
"""Denies the given origin to create notifications.
If it was explicitly allowed, that preference is dropped.
"""
self._DropOriginPreference(new_origin)
denied = self._GetDeniedOrigins()
if new_origin not in denied:
self._SetDeniedOrigins(denied + [new_origin])
def _AllowOrigin(self, new_origin):
"""Allows the given origin to create notifications. If it was explicitly
denied, that preference is dropped.
"""
self._DropOriginPreference(new_origin)
allowed = self._GetAllowedOrigins()
if new_origin not in allowed:
self._SetAllowedOrigins(allowed + [new_origin])
def _DropOriginPreference(self, new_origin):
"""Drops the preference as to whether this origin should be allowed to
create notifications. If it was explicitly allowed or explicitly denied,
that preference is removed.
"""
allowed = self._GetAllowedOrigins()
if allowed and new_origin in allowed:
allowed.remove(new_origin)
self._SetAllowedOrigins(allowed)
denied = self._GetDeniedOrigins()
if denied and new_origin in denied:
denied.remove(new_origin)
self._SetDeniedOrigins(denied)
def _AllowAllOrigins(self):
"""Allows any origin to create notifications."""
self._SetDefaultPermissionSetting(self.ALLOW_ALL_SETTING)
self._SetDeniedOrigins([])
def _VerifyInfobar(self, origin, tab_index=0, windex=0):
"""Helper to verify the notification infobar contents are correct.
Defaults to first tab in first window.
Args:
origin: origin of the notification, e.g., www.gmail.com
tab_index: index of the tab within the given window
windex: index of the window
"""
tab_info = self.GetBrowserInfo()['windows'][windex]['tabs'][tab_index]
self.assertEquals(1, len(tab_info['infobars']))
infobar = tab_info['infobars'][0]
text = 'Allow %s to show desktop notifications?' % origin
self.assertEqual(text, infobar['text'])
self.assertEqual(2, len(infobar['buttons']))
self.assertEqual('Allow', infobar['buttons'][0])
self.assertEqual('Deny', infobar['buttons'][1])
def _CreateSimpleNotification(self, img_url, title, text,
replace_id='', tab_index=0, windex=0):
"""Creates a simple notification.
Returns the id of the notification, which can be used to cancel it later.
This executes a script in the page which shows a notification.
This will only work if the page is navigated to |TEST_PAGE_URL|.
The page must also have permission to show notifications.
Args:
img_url: url of a image to use; can be a data url
title: title of the notification
text: text in the notification
replace_id: id string to be used for this notification. If another
notification is shown with the same replace_id, the former
will be replaced.
tab_index: index of the tab within the given window
windex: index of the window
"""
return self.CallJavascriptFunc('createNotification',
[img_url, title, text, replace_id],
tab_index,
windex);
def _CreateHTMLNotification(self, content_url, replace_id='',
wait_for_display=True, tab_index=0, windex=0):
"""Creates an HTML notification.
Returns the id of the notification, which can be used to cancel it later.
This executes a script in the page which shows a notification.
This will only work if the page is navigated to |TEST_PAGE_URL|.
The page must also have permission to show notifications.
Args:
content_url: url of the page to show in the notification
replace_id: id string to be used for this notification. If another
notification is shown with the same replace_id, the former
will be replaced.
wait_for_display: whether we should wait for the notification to display
tab_index: index of the tab within the given window
windex: index of the window
"""
return self.CallJavascriptFunc('createHTMLNotification',
[content_url, replace_id, wait_for_display],
tab_index,
windex)
def _RequestPermission(self, tab_index=0, windex=0):
"""Requests permission to create notifications.
This will only work if the current page is navigated to |TEST_PAGE_URL|.
Args:
tab_index: index of the tab within the given window
windex: index of the window
"""
self.CallJavascriptFunc('requestPermission', [], tab_index, windex)
def _CancelNotification(self, notification_id, tab_index=0, windex=0):
"""Cancels a notification with the given id.
This canceling is done in the page that showed that notification and so
follows a different path than closing a notification via the UI.
This function should NOT be called until |WaitForNotificationCount| has been
used to verify the notification is showing. This function cannot be used to
cancel a notification that is in the display queue.
This will only work if the page is navigated to |TEST_PAGE_URL|.
Args:
notification_id: id of the notification to cancel
tab_index: index of the tab within the given window that created the
notification
windex: index of the window
"""
msg = self.CallJavascriptFunc(
'cancelNotification', [notification_id], tab_index, windex)
# '1' signifies success.
self.assertEquals('1', msg)
def testCreateSimpleNotification(self):
"""Creates a simple notification."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateSimpleNotification('no_such_file.png', 'My Title', 'My Body')
self.assertEquals(1, len(self.GetActiveNotifications()))
notification = self.GetActiveNotifications()[0]
html_data = urllib.unquote(notification['content_url'])
self.assertTrue('no_such_file.png' in html_data)
self.assertTrue('My Title' in html_data)
self.assertTrue('My Body' in html_data)
def testCreateHTMLNotification(self):
"""Creates an HTML notification using a fake url."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
notification = self.GetActiveNotifications()[0]
self.assertEquals(self.EMPTY_PAGE_URL, notification['content_url'])
self.assertEquals('', notification['display_source'])
self.assertEquals('file:///', notification['origin_url'])
def testCloseNotification(self):
"""Creates a notification and closes it."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.CloseNotification(0)
self.assertFalse(self.GetActiveNotifications())
def testCancelNotification(self):
"""Creates a notification and cancels it in the origin page."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
note_id = self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertNotEquals(-1, note_id)
self.WaitForNotificationCount(1)
self._CancelNotification(note_id)
self.assertFalse(self.GetActiveNotifications())
def testPermissionInfobarAppears(self):
"""Requests notification privileges and verifies the infobar appears."""
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.assertFalse(self.GetActiveNotifications())
self._VerifyInfobar('') # file:/// origins are blank
def testAllowOnPermissionInfobar(self):
"""Tries to create a notification and clicks allow on the infobar."""
self.NavigateToURL(self.TEST_PAGE_URL)
# This notification should not be shown because we do not have permission.
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertFalse(self.GetActiveNotifications())
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.PerformActionOnInfobar('accept', 0)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.WaitForNotificationCount(1)
def testOriginPreferencesBasic(self):
"""Tests that we can allow and deny origins."""
altavista = 'http://www.altavista.com'
gmail = 'http://www.gmail.com'
yahoo = 'http://www.yahoo.com'
self._SetDeniedOrigins([altavista, gmail])
self.assertEquals(altavista, self._GetDeniedOrigins()[0])
self.assertEquals(gmail, self._GetDeniedOrigins()[1])
self._DenyOrigin(yahoo)
self.assertEquals(yahoo, self._GetDeniedOrigins()[2])
self.assertEquals(3, len(self._GetDeniedOrigins()))
self._DropOriginPreference(gmail)
self.assertEquals(2, len(self._GetDeniedOrigins()))
self.assertFalse(gmail in self._GetDeniedOrigins())
self._AllowOrigin(yahoo)
self.assertEquals(1, len(self._GetDeniedOrigins()))
self.assertFalse(yahoo in self._GetDeniedOrigins())
self.assertTrue(yahoo in self._GetAllowedOrigins())
self._SetAllowedOrigins([altavista, gmail])
self._SetDeniedOrigins([])
self.assertEquals(altavista, self._GetAllowedOrigins()[0])
self.assertEquals(gmail, self._GetAllowedOrigins()[1])
self._AllowOrigin(yahoo)
self.assertEquals(yahoo, self._GetAllowedOrigins()[2])
self.assertEquals(3, len(self._GetAllowedOrigins()))
self._DropOriginPreference(gmail)
self.assertEquals(2, len(self._GetAllowedOrigins()))
self.assertFalse(gmail in self._GetAllowedOrigins())
self._DenyOrigin(yahoo)
self.assertEquals(1, len(self._GetAllowedOrigins()))
self.assertTrue(yahoo in self._GetDeniedOrigins())
self.assertFalse(yahoo in self._GetAllowedOrigins())
def testDenyOnPermissionInfobar (self):
"""Test that no notification is created when Deny is chosen
from permission infobar."""
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.PerformActionOnInfobar('cancel', 0)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertFalse(self.GetActiveNotifications())
self.assertEquals(['file:///'], self._GetDeniedOrigins())
def testClosePermissionInfobar(self):
"""Test that no notification is created when permission
infobar is dismissed."""
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.PerformActionOnInfobar('dismiss', 0)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertFalse(self.GetActiveNotifications())
self.assertFalse(self._GetDeniedOrigins())
def testNotificationWithPropertyMissing(self):
"""Test that a notification can be created if one property is missing."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateSimpleNotification('no_such_file.png', 'My Title', '')
self.assertEquals(1, len(self.GetActiveNotifications()))
html_data = urllib.unquote(self.GetActiveNotifications()[0]['content_url'])
self.assertTrue('no_such_file.png' in html_data)
self.assertTrue('My Title' in html_data)
def testAllowNotificationsFromAllSites(self):
"""Verify that all domains can be allowed to show notifications."""
self._SetDefaultPermissionSetting(self.ALLOW_ALL_SETTING)
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
self.assertFalse(self.GetBrowserInfo()['windows'][0]['tabs'][0]['infobars'])
def testDenyNotificationsFromAllSites(self):
"""Verify that no domain can show notifications."""
self._SetDefaultPermissionSetting(self.DENY_ALL_SETTING)
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertFalse(self.GetActiveNotifications())
def testDenyDomainAndAllowAll(self):
"""Verify that denying a domain and allowing all shouldn't show
notifications from the denied domain."""
self._DenyOrigin('file:///')
self._SetDefaultPermissionSetting(self.ALLOW_ALL_SETTING)
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertFalse(self.GetActiveNotifications())
def testAllowDomainAndDenyAll(self):
"""Verify that allowing a domain and denying all others should show
notifications from the allowed domain."""
self._AllowOrigin('file:///')
self._SetDefaultPermissionSetting(self.DENY_ALL_SETTING)
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
self.assertFalse(self.GetBrowserInfo()['windows'][0]['tabs'][0]['infobars'])
def testDenyAndThenAllowDomain(self):
"""Verify that denying and again allowing should show notifications."""
self._DenyOrigin('file:///')
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(len(self.GetActiveNotifications()), 0)
self._AllowOrigin('file:///')
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
self.assertFalse(self.GetBrowserInfo()['windows'][0]['tabs'][0]['infobars'])
def testCreateDenyCloseNotifications(self):
"""Verify able to create, deny, and close the notification."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
origin = 'file:///'
self._DenyOrigin(origin)
self.assertTrue(origin in self._GetDeniedOrigins())
self.CloseNotification(0)
self.assertEquals(0, len(self.GetActiveNotifications()))
def testOriginPrefsNotSavedInIncognito(self):
"""Verify that allow/deny origin preferences are not saved in incognito."""
self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
self.NavigateToURL(self.TEST_PAGE_URL, 1, 0)
self._RequestPermission(windex=1)
self.assertTrue(self.WaitForInfobarCount(1, windex=1))
self.PerformActionOnInfobar('cancel', 0, windex=1)
self.CloseBrowserWindow(1)
self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
self.NavigateToURL(self.TEST_PAGE_URL, 1, 0)
self._RequestPermission(windex=1)
self.assertTrue(self.WaitForInfobarCount(1, windex=1))
self.PerformActionOnInfobar('accept', 0, windex=1)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL, windex=1)
self.assertEquals(1, len(self.GetActiveNotifications()))
self.CloseBrowserWindow(1)
self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
self.NavigateToURL(self.TEST_PAGE_URL, 1, 0)
self._RequestPermission(windex=1)
self.assertTrue(self.WaitForInfobarCount(1, windex=1))
self.assertFalse(self._GetDeniedOrigins())
self.assertFalse(self._GetAllowedOrigins())
def testExitBrowserWithInfobar(self):
"""Exit the browser window, when the infobar appears."""
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
def testCrashTabWithPermissionInfobar(self):
"""Test crashing the tab with permission infobar doesn't crash Chrome."""
self.AppendTab(pyauto.GURL(self.EMPTY_PAGE_URL))
self.assertTrue(self.ActivateTab(0))
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.KillRendererProcess(
self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid'])
def testKillNotificationProcess(self):
"""Test killing a notification doesn't crash Chrome."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.KillRendererProcess(self.GetActiveNotifications()[0]['pid'])
self.WaitForNotificationCount(0)
def testIncognitoNotification(self):
"""Test notifications in incognito window."""
self.RunCommand(pyauto.IDC_NEW_INCOGNITO_WINDOW)
self.NavigateToURL(self.TEST_PAGE_URL, 1, 0)
self.assertTrue(self.ActivateTab(0, 1))
self._RequestPermission(windex=1)
self.assertTrue(self.WaitForInfobarCount(1, windex=1))
self.PerformActionOnInfobar('accept', infobar_index=0, windex=1)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL, windex=1)
self.assertEquals(1, len(self.GetActiveNotifications()))
def testSpecialURLNotification(self):
"""Test a page cannot create a notification to a chrome: url."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification('chrome://settings',
wait_for_display=False);
self.assertFalse(self.GetActiveNotifications())
def testCloseTabWithPermissionInfobar(self):
"""Test that user can close tab when infobar present."""
self.AppendTab(pyauto.GURL('about:blank'))
self.ActivateTab(0)
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.CloseTab()
def testNavigateAwayWithPermissionInfobar(self):
"""Test navigating away when an infobar is present, then trying to create a
notification from the same page."""
self.AppendTab(pyauto.GURL('about:blank'))
self.assertTrue(self.ActivateTab(0))
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.NavigateToURL(self.TEST_PAGE_URL)
self._RequestPermission()
self.assertTrue(self.WaitForInfobarCount(1))
self.PerformActionOnInfobar('accept', 0)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
def testCrashRendererNotificationRemain(self):
"""Test crashing renderer does not close or crash notification."""
self._AllowAllOrigins()
self.AppendTab(pyauto.GURL('about:blank'))
self.ActivateTab(0)
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateHTMLNotification(self.EMPTY_PAGE_URL)
self.assertEquals(1, len(self.GetActiveNotifications()))
self.KillRendererProcess(
self.GetBrowserInfo()['windows'][0]['tabs'][0]['renderer_pid'])
self.assertEquals(1, len(self.GetActiveNotifications()))
def testNotificationOrderAfterClosingOne(self):
"""Tests that closing a notification leaves the rest
of the notifications in the correct order.
"""
if self.IsWin7():
return # crbug.com/66072
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateSimpleNotification('', 'Title1', '')
self._CreateSimpleNotification('', 'Title2', '')
self._CreateSimpleNotification('', 'Title3', '')
old_notifications = self.GetAllNotifications()
self.assertEquals(3, len(old_notifications))
self.CloseNotification(1)
new_notifications = self.GetAllNotifications()
self.assertEquals(2, len(new_notifications))
self.assertEquals(old_notifications[0]['id'], new_notifications[0]['id'])
self.assertEquals(old_notifications[2]['id'], new_notifications[1]['id'])
def testNotificationReplacement(self):
"""Test that we can replace a notification using the replaceId."""
self._AllowAllOrigins()
self.NavigateToURL(self.TEST_PAGE_URL)
self._CreateSimpleNotification('', 'Title2', '', 'chat')
self.WaitForNotificationCount(1)
# Since this notification has the same replaceId, 'chat', it should replace
# the first notification.
self._CreateHTMLNotification(self.EMPTY_PAGE_URL, 'chat')
notifications = self.GetActiveNotifications()
self.assertEquals(1, len(notifications))
self.assertEquals(self.EMPTY_PAGE_URL, notifications[0]['content_url'])
if __name__ == '__main__':
pyauto_functional.Main()