1# Copyright 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import os
7import shutil
8import tempfile
9import unittest
10
11from telemetry.core import util
12from telemetry import decorators
13from telemetry.internal.browser import browser_finder
14from telemetry.internal.browser import extension_to_load
15from telemetry.testing import options_for_unittests
16
17
18class ExtensionTest(unittest.TestCase):
19  def setUp(self):
20    self._browser = None
21    self._platform = None
22    self._extension = None
23    self._extension_id = None
24
25  def CreateBrowserWithExtension(self, ext_path):
26    extension_path = os.path.join(util.GetUnittestDataDir(), ext_path)
27    options = options_for_unittests.GetCopy()
28    load_extension = extension_to_load.ExtensionToLoad(
29        extension_path, options.browser_type)
30    options.browser_options.extensions_to_load = [load_extension]
31    browser_to_create = browser_finder.FindBrowser(options)
32
33    if not browser_to_create:
34      # May not find a browser that supports extensions.
35      return False
36    self._platform = browser_to_create.platform
37    self._platform.network_controller.InitializeIfNeeded()
38    self._browser = browser_to_create.Create(options)
39    self._extension = self._browser.extensions[load_extension]
40    self._extension_id = load_extension.extension_id
41    self.assertTrue(self._extension)
42    return True
43
44  def tearDown(self):
45    if self._browser:
46      self._browser.Close()
47      self._platform.network_controller.Close()
48
49  def testExtensionBasic(self):
50    """Test ExtensionPage's ExecuteJavaScript and EvaluateJavaScript."""
51    if not self.CreateBrowserWithExtension('simple_extension'):
52      logging.warning('Did not find a browser that supports extensions, '
53                      'skipping test.')
54      return
55    self.assertTrue(
56        self._extension.EvaluateJavaScript('chrome.runtime != null'))
57    self._extension.ExecuteJavaScript('setTestVar("abcdef")')
58    self.assertEquals('abcdef',
59                      self._extension.EvaluateJavaScript('_testVar'))
60
61  def testExtensionGetByExtensionId(self):
62    """Test GetByExtensionId for a simple extension with a background page."""
63    if not self.CreateBrowserWithExtension('simple_extension'):
64      logging.warning('Did not find a browser that supports extensions, '
65                      'skipping test.')
66      return
67    ext = self._browser.extensions.GetByExtensionId(self._extension_id)
68    self.assertEqual(1, len(ext))
69    self.assertEqual(ext[0], self._extension)
70    self.assertTrue(
71        ext[0].EvaluateJavaScript('chrome.runtime != null'))
72
73  @decorators.Disabled('mac')
74  def testWebApp(self):
75    """Tests GetByExtensionId for a web app with multiple pages."""
76    if not self.CreateBrowserWithExtension('simple_app'):
77      logging.warning('Did not find a browser that supports extensions, '
78                      'skipping test.')
79      return
80    extensions = self._browser.extensions.GetByExtensionId(self._extension_id)
81    extension_urls = set([ext.EvaluateJavaScript('location.href;')
82                          for ext in extensions])
83    expected_urls = set(['chrome-extension://' + self._extension_id + '/' + path
84                         for path in ['main.html', 'second.html',
85                                      '_generated_background_page.html']])
86
87    self.assertEqual(expected_urls, extension_urls)
88
89class NonExistentExtensionTest(unittest.TestCase):
90  def testNonExistentExtensionPath(self):
91    """Test that a non-existent extension path will raise an exception."""
92    extension_path = os.path.join(util.GetUnittestDataDir(), 'foo')
93    options = options_for_unittests.GetCopy()
94    self.assertRaises(extension_to_load.ExtensionPathNonExistentException,
95                      lambda: extension_to_load.ExtensionToLoad(
96                          extension_path, options.browser_type))
97
98  def testExtensionNotLoaded(self):
99    """Querying an extension that was not loaded will return None"""
100    extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension')
101    options = options_for_unittests.GetCopy()
102    load_extension = extension_to_load.ExtensionToLoad(
103        extension_path, options.browser_type)
104    browser_to_create = browser_finder.FindBrowser(options)
105    try:
106      browser_to_create.platform.network_controller.InitializeIfNeeded()
107      with browser_to_create.Create(options) as b:
108        if b.supports_extensions:
109          self.assertRaises(KeyError, lambda: b.extensions[load_extension])
110    finally:
111      browser_to_create.platform.network_controller.Close()
112
113class MultipleExtensionTest(unittest.TestCase):
114  def setUp(self):
115    """ Copy the manifest and background.js files of simple_extension to a
116    number of temporary directories to load as extensions"""
117    self._extension_dirs = [tempfile.mkdtemp() for _ in range(3)]
118    src_extension_dir = os.path.join(
119        util.GetUnittestDataDir(), 'simple_extension')
120    manifest_path = os.path.join(src_extension_dir, 'manifest.json')
121    script_path = os.path.join(src_extension_dir, 'background.js')
122    for d in self._extension_dirs:
123      shutil.copy(manifest_path, d)
124      shutil.copy(script_path, d)
125    options = options_for_unittests.GetCopy()
126    self._extensions_to_load = [extension_to_load.ExtensionToLoad(
127                                    d, options.browser_type)
128                                for d in self._extension_dirs]
129    options.browser_options.extensions_to_load = self._extensions_to_load
130    browser_to_create = browser_finder.FindBrowser(options)
131    self._platform = None
132    self._browser = None
133    # May not find a browser that supports extensions.
134    if browser_to_create:
135      self._platform = browser_to_create.platform
136      self._platform.network_controller.InitializeIfNeeded()
137      self._browser = browser_to_create.Create(options)
138
139  def tearDown(self):
140    if self._platform:
141      self._platform.network_controller.Close()
142    if self._browser:
143      self._browser.Close()
144    for d in self._extension_dirs:
145      shutil.rmtree(d)
146
147  def testMultipleExtensions(self):
148    if not self._browser:
149      logging.warning('Did not find a browser that supports extensions, '
150                      'skipping test.')
151      return
152
153    # Test contains.
154    loaded_extensions = [e for e in self._extensions_to_load
155                         if e in self._browser.extensions]
156    self.assertEqual(len(loaded_extensions), len(self._extensions_to_load))
157    for load_extension in self._extensions_to_load:
158      extension = self._browser.extensions[load_extension]
159      assert extension
160      self.assertTrue(
161          extension.EvaluateJavaScript('chrome.runtime != null'))
162      extension.ExecuteJavaScript('setTestVar("abcdef")')
163      self.assertEquals('abcdef', extension.EvaluateJavaScript('_testVar'))
164
165
166class ComponentExtensionTest(unittest.TestCase):
167  def testComponentExtensionBasic(self):
168    extension_path = os.path.join(
169        util.GetUnittestDataDir(), 'component_extension')
170    options = options_for_unittests.GetCopy()
171    load_extension = extension_to_load.ExtensionToLoad(
172        extension_path, options.browser_type, is_component=True)
173
174    options.browser_options.extensions_to_load = [load_extension]
175    browser_to_create = browser_finder.FindBrowser(options)
176    if not browser_to_create:
177      logging.warning('Did not find a browser that supports extensions, '
178                      'skipping test.')
179      return
180
181    try:
182      browser_to_create.platform.network_controller.InitializeIfNeeded()
183      with browser_to_create.Create(options) as b:
184        extension = b.extensions[load_extension]
185        self.assertTrue(
186            extension.EvaluateJavaScript('chrome.runtime != null'))
187        extension.ExecuteJavaScript('setTestVar("abcdef")')
188        self.assertEquals('abcdef', extension.EvaluateJavaScript('_testVar'))
189    finally:
190      browser_to_create.platform.network_controller.Close()
191
192  def testComponentExtensionNoPublicKey(self):
193    # simple_extension does not have a public key.
194    extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension')
195    options = options_for_unittests.GetCopy()
196    self.assertRaises(extension_to_load.MissingPublicKeyException,
197                      lambda: extension_to_load.ExtensionToLoad(
198                          extension_path,
199                          browser_type=options.browser_type,
200                          is_component=True))
201
202
203class WebviewInExtensionTest(ExtensionTest):
204
205  # Flaky on windows, hits an exception: http://crbug.com/508325
206  @decorators.Disabled('win', 'linux')
207  def testWebviewInExtension(self):
208    """Tests GetWebviewContext() for a web app containing <webview> element."""
209    if not self.CreateBrowserWithExtension('webview_app'):
210      logging.warning('Did not find a browser that supports extensions, '
211                      'skipping test.')
212      return
213
214    self._browser.extensions.GetByExtensionId(self._extension_id)
215    webview_contexts = self._extension.GetWebviewContexts()
216    self.assertEquals(1, len(webview_contexts))
217    webview_context = webview_contexts[0]
218    webview_context.WaitForDocumentReadyStateToBeComplete()
219    # Check that the context has the right url from the <webview> element.
220    self.assertTrue(webview_context.GetUrl().startswith('data:'))
221    # Check |test_input_id| element is accessible from the webview context.
222    self.assertTrue(webview_context.EvaluateJavaScript(
223                    'document.getElementById("test_input_id") != null'))
224    # Check that |test_input_id| is not accessible from outside webview context
225    self.assertFalse(self._extension.EvaluateJavaScript(
226                    'document.getElementById("test_input_id") != null'))
227