1#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7import os
8
9import pyauto_functional  # Must be imported before pyauto
10import pyauto
11import test_utils
12
13class SpecialTabsTest(pyauto.PyUITest):
14  """TestCase for Special Tabs like about:version, chrome://history, etc."""
15
16  @staticmethod
17  def GetSpecialAcceleratorTabs():
18    """Get a dict of accelerators and corresponding tab titles."""
19    ret = {
20        pyauto.IDC_SHOW_HISTORY: 'History',
21        pyauto.IDC_MANAGE_EXTENSIONS: 'Extensions',
22        pyauto.IDC_SHOW_DOWNLOADS: 'Downloads',
23    }
24    return ret
25
26  special_url_redirects = {
27   'about:': 'chrome://version',
28   'about:about': 'chrome://about',
29   'about:appcache-internals': 'chrome://appcache-internals',
30   'about:credits': 'chrome://credits',
31   'about:dns': 'chrome://dns',
32   'about:histograms': 'chrome://histograms',
33   'about:plugins': 'chrome://plugins',
34   'about:sync': 'chrome://sync-internals',
35   'about:sync-internals': 'chrome://sync-internals',
36   'about:version': 'chrome://version',
37  }
38
39  special_url_tabs = {
40    'chrome://about': { 'title': 'Chrome URLs' },
41    'chrome://appcache-internals': { 'title': 'AppCache Internals' },
42    'chrome://blob-internals': { 'title': 'Blob Storage Internals' },
43    'chrome://feedback': {},
44    'chrome://chrome-urls': { 'title': 'Chrome URLs' },
45    'chrome://crashes': { 'title': 'Crashes' },
46    'chrome://credits': { 'title': 'Credits' },
47    'chrome://downloads': { 'title': 'Downloads' },
48    'chrome://dns': { 'title': 'About DNS' },
49    'chrome://extensions': { 'title': 'Extensions' },
50    'chrome://flags': {},
51    'chrome://flash': {},
52    'chrome://gpu-internals': {},
53    'chrome://histograms': { 'title': 'About Histograms' },
54    'chrome://history': { 'title': 'History' },
55    'chrome://inspect': { 'title': 'Inspect with Chrome Developer Tools' },
56    'chrome://media-internals': { 'title': 'Media Internals' },
57    'chrome://memory-redirect': { 'title': 'About Memory' },
58    'chrome://net-internals': {},
59    'chrome://net-internals/help.html': {},
60    'chrome://newtab': { 'title': 'New Tab', 'CSP': False },
61    'chrome://plugins': { 'title': 'Plug-ins' },
62    'chrome://settings': { 'title': 'Settings' },
63    'chrome://settings/autofill': { 'title': 'Settings - Autofill settings' },
64    'chrome://settings/clearBrowserData':
65      { 'title': 'Settings - Clear browsing data' },
66    'chrome://settings/content': { 'title': 'Settings - Content settings' },
67    'chrome://settings/languages':
68      { 'title': 'Settings - Languages' },
69    'chrome://settings/passwords': { 'title': 'Settings - Passwords' },
70    'chrome://stats': {},
71    'chrome://sync': { 'title': 'Sync Internals' },
72    'chrome://sync-internals': { 'title': 'Sync Internals' },
73    'chrome://terms': {},
74    'chrome://version': { 'title': 'About Version' },
75    'chrome://view-http-cache': {},
76    'chrome://webrtc-internals': { 'title': 'WebRTC Internals' },
77  }
78  broken_special_url_tabs = {
79    # crashed under debug when invoked from location bar (bug 88223).
80    'chrome://devtools': { 'CSP': False },
81
82    # returns "not available" despite having an URL constant.
83    'chrome://dialog': { 'CSP': False },
84
85    # separate window on mac, PC untested, not implemented elsewhere.
86    'chrome://ipc': { 'CSP': False },
87
88    # race against redirects via meta-refresh.
89    'chrome://memory': { 'CSP': False },
90  }
91
92  chromeos_special_url_tabs = {
93    'chrome://choose-mobile-network': { 'title': 'undefined', 'CSP': True },
94    'chrome://flags': { 'CSP': True },
95    'chrome://imageburner': { 'title':'Create a Recovery Media', 'CSP': True },
96    'chrome://keyboardoverlay': { 'title': 'Keyboard Overlay', 'CSP': True },
97    'chrome://network': { 'title': 'About Network' },
98    'chrome://os-credits': { 'title': 'Credits', 'CSP': False },
99    'chrome://proxy-settings': { 'CSP': False },
100    'chrome://register': { 'CSP': False },
101    'chrome://settings/languages':
102      { 'title': 'Settings - Languages and input' },
103    'chrome://sim-unlock': { 'title': 'Enter SIM card PIN', 'CSP': False },
104    'chrome://system': { 'title': 'About System', 'CSP': False },
105
106    # OVERRIDE - title and page different on CrOS
107    'chrome://settings/accounts': { 'title': 'Settings - Users' },
108  }
109  broken_chromeos_special_url_tabs = {
110    # returns "not available" page on chromeos=1 linux but has an URL constant.
111    'chrome://activationmessage': { 'CSP': False },
112    'chrome://cloudprintresources': { 'CSP': False },
113    'chrome://cloudprintsetup': { 'CSP': False },
114    'chrome://collected-cookies': { 'CSP': False },
115    'chrome://constrained-test': { 'CSP': False },
116    'chrome://enterprise-enrollment': { 'CSP': False },
117    'chrome://http-auth': { 'CSP': False },
118    'chrome://login-container': { 'CSP': False },
119    'chrome://media-player': { 'CSP': False },
120    'chrome://screenshots': { 'CSP': False },
121    'chrome://slideshow': { 'CSP': False },
122    'chrome://syncresources': { 'CSP': False },
123    'chrome://theme': { 'CSP': False },
124    'chrome://view-http-cache': { 'CSP': False },
125
126    # crashes on chromeos=1 on linux, possibly missing real CrOS features.
127    'chrome://cryptohome': { 'CSP': False},
128    'chrome://mobilesetup': { 'CSP': False },
129    'chrome://print': { 'CSP': False },
130  }
131
132  linux_special_url_tabs = {
133    'chrome://linux-proxy-config': { 'title': 'Proxy Configuration Help' },
134    'chrome://tcmalloc': { 'title': 'tcmalloc stats' },
135    'chrome://sandbox': { 'title': 'Sandbox Status' },
136  }
137  broken_linux_special_url_tabs = {}
138
139  mac_special_url_tabs = {
140    'chrome://settings/languages': { 'title': 'Settings - Languages' },
141  }
142  broken_mac_special_url_tabs = {}
143
144  win_special_url_tabs = {
145    'chrome://conflicts': {},
146  }
147  broken_win_special_url_tabs = {
148    # Sync on windows badly broken at the moment.
149    'chrome://sync': {},
150  }
151
152  google_special_url_tabs = {
153    # OVERRIDE - different title for Google Chrome vs. Chromium.
154    'chrome://terms': {
155      'title': 'Google Chrome Terms of Service',
156    },
157  }
158  broken_google_special_url_tabs = {}
159
160  google_chromeos_special_url_tabs = {
161    # OVERRIDE - different title for Google Chrome OS vs. Chromium OS.
162    'chrome://terms': {
163      'title': 'Google Chrome OS Terms',
164    },
165  }
166  broken_google_chromeos_special_url_tabs = {}
167
168  google_win_special_url_tabs = {}
169  broken_google_win_special_url_tabs = {}
170
171  google_mac_special_url_tabs = {}
172  broken_google_mac_special_url_tabs = {}
173
174  google_linux_special_url_tabs = {}
175  broken_google_linux_special_url_tabs = {}
176
177  def _VerifyAppCacheInternals(self):
178    """Confirm about:appcache-internals contains expected content for Caches.
179       Also confirms that the about page populates Application Caches."""
180    # Navigate to html page to activate DNS prefetching.
181    self.NavigateToURL('http://futtta.be/html5/offline.php')
182    # Wait for page to load and display sucess or fail message.
183    self.WaitUntil(
184        lambda: self.GetDOMValue('document.getElementById("status").innerHTML'),
185                                 expect_retval='cached')
186    self.TabGoBack()
187    test_utils.StringContentCheck(
188        self, self.GetTabContents(),
189        ['Manifest',
190         'http://futtta.be/html5/manifest.php'],
191        [])
192
193  def _VerifyAboutDNS(self):
194    """Confirm about:dns contains expected content related to DNS info.
195       Also confirms that prefetching DNS records propogate."""
196    # Navigate to a page to activate DNS prefetching.
197    self.NavigateToURL('http://www.google.com')
198    self.TabGoBack()
199    test_utils.StringContentCheck(self, self.GetTabContents(),
200                                  ['Host name', 'How long ago', 'Motivation'],
201                                  [])
202
203  def _GetPlatformSpecialURLTabs(self):
204    tabs = self.special_url_tabs.copy()
205    broken_tabs = self.broken_special_url_tabs.copy()
206    if self.IsChromeOS():
207      tabs.update(self.chromeos_special_url_tabs)
208      broken_tabs.update(self.broken_chromeos_special_url_tabs)
209    elif self.IsLinux():
210      tabs.update(self.linux_special_url_tabs)
211      broken_tabs.update(self.broken_linux_special_url_tabs)
212    elif self.IsMac():
213      tabs.update(self.mac_special_url_tabs)
214      broken_tabs.update(self.broken_mac_special_url_tabs)
215    elif self.IsWin():
216      tabs.update(self.win_special_url_tabs)
217      broken_tabs.update(self.broken_win_special_url_tabs)
218    for key, value in broken_tabs.iteritems():
219      if key in tabs:
220       del tabs[key]
221    broken_tabs = {}
222    if self.GetBrowserInfo()['properties']['branding'] == 'Google Chrome':
223      tabs.update(self.google_special_url_tabs)
224      broken_tabs.update(self.broken_google_special_url_tabs)
225      if self.IsChromeOS():
226        tabs.update(self.google_chromeos_special_url_tabs)
227        broken_tabs.update(self.broken_google_chromeos_special_url_tabs)
228      elif self.IsLinux():
229        tabs.update(self.google_linux_special_url_tabs)
230        broken_tabs.update(self.broken_google_linux_special_url_tabs)
231      elif self.IsMac():
232        tabs.update(self.google_mac_special_url_tabs)
233        broken_tabs.update(self.broken_google_mac_special_url_tabs)
234      elif self.IsWin():
235        tabs.update(self.google_win_special_url_tabs)
236        broken_tabs.update(self.broken_google_win_special_url_tabs)
237      for key, value in broken_tabs.iteritems():
238        if key in tabs:
239         del tabs[key]
240    return tabs
241
242  def testSpecialURLRedirects(self):
243    """Test that older about: URLs are implemented by newer chrome:// URLs.
244       The location bar may not get updated in all cases, so checking the
245       tab URL is misleading, instead check for the same contents as the
246       chrome:// page."""
247    tabs = self._GetPlatformSpecialURLTabs()
248    for url, redirect in self.special_url_redirects.iteritems():
249      if redirect in tabs:
250        logging.debug('Testing redirect from %s to %s.' % (url, redirect))
251        self.NavigateToURL(url)
252        self.assertEqual(self.special_url_tabs[redirect]['title'],
253                         self.GetActiveTabTitle())
254
255  def testSpecialURLTabs(self):
256    """Test special tabs created by URLs like chrome://downloads,
257       chrome://settings/extensionSettings, chrome://history etc.
258       Also ensures they specify content-security-policy and not inline
259       scripts for those pages that are expected to do so.  Patches which
260       break this test by including new inline javascript are security
261       vulnerabilities and should be reverted."""
262    tabs = self._GetPlatformSpecialURLTabs()
263    for url, properties in tabs.iteritems():
264      logging.debug('Testing URL %s.' % url)
265      self.NavigateToURL(url)
266      expected_title = 'title' in properties and properties['title'] or url
267      actual_title = self.GetActiveTabTitle()
268      self.assertTrue(self.WaitUntil(
269          lambda: self.GetActiveTabTitle(), expect_retval=expected_title),
270          msg='Title did not match for %s. Expected: %s. Got %s' % (
271              url, expected_title, self.GetActiveTabTitle()))
272      include_list = []
273      exclude_list = []
274      no_csp = 'CSP' in properties and not properties['CSP']
275      if no_csp:
276        exclude_list.extend(['Content-Security-Policy'])
277      else:
278        exclude_list.extend(['<script>', 'onclick=', 'onload=',
279                             'onchange=', 'onsubmit=', 'javascript:'])
280      if 'includes' in properties:
281        include_list.extend(properties['includes'])
282      if 'excludes' in properties:
283        exclude_list.extend(properties['exlcudes'])
284      test_utils.StringContentCheck(self, self.GetTabContents(),
285                                    include_list, exclude_list)
286      result = self.ExecuteJavascript("""
287          var r = 'blocked';
288          var f = 'executed';
289          var s = document.createElement('script');
290          s.textContent = 'r = f';
291          document.body.appendChild(s);
292          window.domAutomationController.send(r);
293        """)
294      logging.debug('has csp %s, result %s.' % (not no_csp, result))
295      if no_csp:
296        self.assertEqual(result, 'executed',
297                         msg='Got %s for %s' % (result, url))
298      else:
299        self.assertEqual(result, 'blocked',
300                         msg='Got %s for %s' % (result, url))
301
302      # Restart browser so that every URL gets a fresh instance.
303      self.RestartBrowser(clear_profile=True)
304
305  def testAboutAppCacheTab(self):
306    """Test App Cache tab to confirm about page populates caches."""
307    self.NavigateToURL('about:appcache-internals')
308    self._VerifyAppCacheInternals()
309    self.assertEqual('AppCache Internals', self.GetActiveTabTitle())
310
311  def testAboutDNSTab(self):
312    """Test DNS tab to confirm DNS about page propogates records."""
313    self.NavigateToURL('about:dns')
314    self._VerifyAboutDNS()
315    self.assertEqual('About DNS', self.GetActiveTabTitle())
316
317  def testSpecialAcceratorTabs(self):
318    """Test special tabs created by accelerators."""
319    for accel, title in self.GetSpecialAcceleratorTabs().iteritems():
320      self.RunCommand(accel)
321      self.assertTrue(self.WaitUntil(
322            self.GetActiveTabTitle, expect_retval=title),
323          msg='Expected "%s", got "%s"' % (title, self.GetActiveTabTitle()))
324
325
326if __name__ == '__main__':
327  pyauto_functional.Main()
328