page_runner_unittest.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1# Copyright (c) 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.
4import logging
5import os
6import tempfile
7import unittest
8
9from telemetry.core import exceptions
10from telemetry.core import user_agent
11from telemetry.core import util
12from telemetry.page import page as page_module
13from telemetry.page import page_measurement
14from telemetry.page import page_set
15from telemetry.page import page_test
16from telemetry.page import page_runner
17from telemetry.page import test_expectations
18from telemetry.unittest import options_for_unittests
19
20SIMPLE_CREDENTIALS_STRING = """
21{
22  "test": {
23    "username": "example",
24    "password": "asdf"
25  }
26}
27"""
28class StubCredentialsBackend(object):
29  def __init__(self, login_return_value):
30    self.did_get_login = False
31    self.did_get_login_no_longer_needed = False
32    self.login_return_value = login_return_value
33
34  @property
35  def credentials_type(self): # pylint: disable=R0201
36    return 'test'
37
38  def LoginNeeded(self, tab, config): # pylint: disable=W0613
39    self.did_get_login = True
40    return self.login_return_value
41
42  def LoginNoLongerNeeded(self, tab): # pylint: disable=W0613
43    self.did_get_login_no_longer_needed = True
44
45class PageRunnerTests(unittest.TestCase):
46  # TODO(nduca): Move the basic "test failed, test succeeded" tests from
47  # page_measurement_unittest to here.
48
49  def testHandlingOfCrashedTab(self):
50    ps = page_set.PageSet()
51    expectations = test_expectations.TestExpectations()
52    page1 = page_module.Page('chrome://crash', ps)
53    ps.pages.append(page1)
54
55    class Test(page_test.PageTest):
56      def RunTest(self, *args):
57        pass
58
59    options = options_for_unittests.GetCopy()
60    options.output_format = 'none'
61    results = page_runner.Run(Test('RunTest'), ps, expectations, options)
62    self.assertEquals(0, len(results.successes))
63    self.assertEquals(0, len(results.failures))
64    self.assertEquals(1, len(results.errors))
65
66  def testHandlingOfTestThatRaisesWithNonFatalUnknownExceptions(self):
67    ps = page_set.PageSet()
68    expectations = test_expectations.TestExpectations()
69    ps.pages.append(page_module.Page(
70        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
71    ps.pages.append(page_module.Page(
72        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
73
74    class ExpectedException(Exception):
75      pass
76
77    class Test(page_test.PageTest):
78      def __init__(self, *args):
79        super(Test, self).__init__(*args)
80        self.run_count = 0
81      def RunTest(self, *_):
82        old_run_count = self.run_count
83        self.run_count += 1
84        if old_run_count == 0:
85          raise ExpectedException()
86
87    options = options_for_unittests.GetCopy()
88    options.output_format = 'none'
89    test = Test('RunTest')
90    results = page_runner.Run(test, ps, expectations, options)
91    self.assertEquals(2, test.run_count)
92    self.assertEquals(1, len(results.successes))
93    self.assertEquals(1, len(results.failures))
94
95  def testHandlingOfCrashedTabWithExpectedFailure(self):
96    ps = page_set.PageSet()
97    expectations = test_expectations.TestExpectations()
98    expectations.Fail('chrome://crash')
99    page1 = page_module.Page('chrome://crash', ps)
100    ps.pages.append(page1)
101
102    class Test(page_test.PageTest):
103      def RunTest(self, *_):
104        pass
105
106    options = options_for_unittests.GetCopy()
107    options.output_format = 'none'
108    results = page_runner.Run(
109        Test('RunTest'), ps, expectations, options)
110    self.assertEquals(1, len(results.successes))
111    self.assertEquals(0, len(results.failures))
112    self.assertEquals(0, len(results.errors))
113
114  def testRetryOnBrowserCrash(self):
115    ps = page_set.PageSet()
116    expectations = test_expectations.TestExpectations()
117    ps.pages.append(page_module.Page(
118        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
119
120    class CrashyMeasurement(page_measurement.PageMeasurement):
121      has_crashed = False
122      def MeasurePage(self, *_):
123        if not self.has_crashed:
124          self.has_crashed = True
125          raise exceptions.BrowserGoneException()
126
127    options = options_for_unittests.GetCopy()
128    options.output_format = 'csv'
129
130    results = page_runner.Run(CrashyMeasurement(), ps, expectations, options)
131
132    self.assertEquals(1, len(results.successes))
133    self.assertEquals(0, len(results.failures))
134    self.assertEquals(0, len(results.errors))
135
136  def testDiscardFirstResult(self):
137    ps = page_set.PageSet()
138    expectations = test_expectations.TestExpectations()
139    ps.pages.append(page_module.Page(
140        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
141    ps.pages.append(page_module.Page(
142        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
143
144    class Measurement(page_measurement.PageMeasurement):
145      @property
146      def discard_first_result(self):
147        return True
148      def MeasurePage(self, *args):
149        pass
150
151    options = options_for_unittests.GetCopy()
152    options.output_format = 'none'
153    options.reset_results = None
154    options.upload_results = None
155    options.results_label = None
156
157    options.repeat_options.page_repeat_iters = 1
158    options.repeat_options.pageset_repeat_iters = 1
159    results = page_runner.Run(Measurement(), ps, expectations, options)
160    self.assertEquals(0, len(results.successes))
161    self.assertEquals(0, len(results.failures))
162
163    options.repeat_options.page_repeat_iters = 1
164    options.repeat_options.pageset_repeat_iters = 2
165    results = page_runner.Run(Measurement(), ps, expectations, options)
166    self.assertEquals(2, len(results.successes))
167    self.assertEquals(0, len(results.failures))
168
169    options.repeat_options.page_repeat_iters = 2
170    options.repeat_options.pageset_repeat_iters = 1
171    results = page_runner.Run(Measurement(), ps, expectations, options)
172    self.assertEquals(2, len(results.successes))
173    self.assertEquals(0, len(results.failures))
174
175    options.output_format = 'html'
176    options.repeat_options.page_repeat_iters = 1
177    options.repeat_options.pageset_repeat_iters = 1
178    results = page_runner.Run(Measurement(), ps, expectations, options)
179    self.assertEquals(0, len(results.successes))
180    self.assertEquals(0, len(results.failures))
181
182  def testPagesetRepeat(self):
183    ps = page_set.PageSet()
184    expectations = test_expectations.TestExpectations()
185    ps.pages.append(page_module.Page(
186        'file://blank.html', ps, base_dir=util.GetUnittestDataDir()))
187    ps.pages.append(page_module.Page(
188        'file://green_rect.html', ps, base_dir=util.GetUnittestDataDir()))
189
190    class Measurement(page_measurement.PageMeasurement):
191      i = 0
192      def MeasurePage(self, _, __, results):
193        self.i += 1
194        results.Add('metric', 'unit', self.i)
195
196    output_file = tempfile.NamedTemporaryFile(delete=False).name
197    try:
198      options = options_for_unittests.GetCopy()
199      options.output_format = 'buildbot'
200      options.output_file = output_file
201      options.reset_results = None
202      options.upload_results = None
203      options.results_label = None
204
205      options.repeat_options.page_repeat_iters = 1
206      options.repeat_options.pageset_repeat_iters = 2
207      results = page_runner.Run(Measurement(), ps, expectations, options)
208      results.PrintSummary()
209      self.assertEquals(4, len(results.successes))
210      self.assertEquals(0, len(results.failures))
211      stdout = open(output_file).read()
212      self.assertIn('RESULT metric_by_url: blank.html= [1,3] unit', stdout)
213      self.assertIn('RESULT metric_by_url: green_rect.html= [2,4] unit', stdout)
214      self.assertIn('*RESULT metric: metric= [1,2,3,4] unit', stdout)
215    finally:
216      results._output_stream.close()  # pylint: disable=W0212
217      os.remove(output_file)
218
219  def testCredentialsWhenLoginFails(self):
220    credentials_backend = StubCredentialsBackend(login_return_value=False)
221    did_run = self.runCredentialsTest(credentials_backend)
222    assert credentials_backend.did_get_login == True
223    assert credentials_backend.did_get_login_no_longer_needed == False
224    assert did_run == False
225
226  def testCredentialsWhenLoginSucceeds(self):
227    credentials_backend = StubCredentialsBackend(login_return_value=True)
228    did_run = self.runCredentialsTest(credentials_backend)
229    assert credentials_backend.did_get_login == True
230    assert credentials_backend.did_get_login_no_longer_needed == True
231    assert did_run
232
233  def runCredentialsTest(self, # pylint: disable=R0201
234                         credentials_backend):
235    ps = page_set.PageSet()
236    expectations = test_expectations.TestExpectations()
237    page = page_module.Page(
238        'file://blank.html', ps, base_dir=util.GetUnittestDataDir())
239    page.credentials = "test"
240    ps.pages.append(page)
241
242    did_run = [False]
243
244    try:
245      with tempfile.NamedTemporaryFile(delete=False) as f:
246        f.write(SIMPLE_CREDENTIALS_STRING)
247        ps.credentials_path = f.name
248
249      class TestThatInstallsCredentialsBackend(page_test.PageTest):
250        def __init__(self, credentials_backend):
251          super(TestThatInstallsCredentialsBackend, self).__init__('RunTest')
252          self._credentials_backend = credentials_backend
253
254        def DidStartBrowser(self, browser):
255          browser.credentials.AddBackend(self._credentials_backend)
256
257        def RunTest(self, page, tab, results): # pylint: disable=W0613,R0201
258          did_run[0] = True
259
260      test = TestThatInstallsCredentialsBackend(credentials_backend)
261      options = options_for_unittests.GetCopy()
262      options.output_format = 'none'
263      page_runner.Run(test, ps, expectations, options)
264    finally:
265      os.remove(f.name)
266
267    return did_run[0]
268
269  def testUserAgent(self):
270    ps = page_set.PageSet()
271    expectations = test_expectations.TestExpectations()
272    page = page_module.Page(
273        'file://blank.html', ps, base_dir=util.GetUnittestDataDir())
274    ps.pages.append(page)
275    ps.user_agent_type = 'tablet'
276
277    class TestUserAgent(page_test.PageTest):
278      def RunTest(self, page, tab, results): # pylint: disable=W0613,R0201
279        actual_user_agent = tab.EvaluateJavaScript('window.navigator.userAgent')
280        expected_user_agent = user_agent.UA_TYPE_MAPPING['tablet']
281        assert actual_user_agent.strip() == expected_user_agent
282
283        # This is so we can check later that the test actually made it into this
284        # function. Previously it was timing out before even getting here, which
285        # should fail, but since it skipped all the asserts, it slipped by.
286        self.hasRun = True # pylint: disable=W0201
287
288    test = TestUserAgent('RunTest')
289    options = options_for_unittests.GetCopy()
290    options.output_format = 'none'
291    page_runner.Run(test, ps, expectations, options)
292
293    self.assertTrue(hasattr(test, 'hasRun') and test.hasRun)
294
295  # Ensure that page_runner forces exactly 1 tab before running a page.
296  def testOneTab(self):
297    ps = page_set.PageSet()
298    expectations = test_expectations.TestExpectations()
299    page = page_module.Page(
300        'file://blank.html', ps, base_dir=util.GetUnittestDataDir())
301    ps.pages.append(page)
302
303    class TestOneTab(page_test.PageTest):
304      def __init__(self,
305                   test_method_name,
306                   action_name_to_run='',
307                   needs_browser_restart_after_each_run=False):
308        super(TestOneTab, self).__init__(test_method_name, action_name_to_run,
309                                         needs_browser_restart_after_each_run)
310        self._browser = None
311
312      def DidStartBrowser(self, browser):
313        self._browser = browser
314        if self._browser.supports_tab_control:
315          self._browser.tabs.New()
316
317      def RunTest(self, page, tab, results): # pylint: disable=W0613,R0201
318        if not self._browser.supports_tab_control:
319          logging.warning('Browser does not support tab control, skipping test')
320          return
321        assert len(self._browser.tabs) == 1
322
323    test = TestOneTab('RunTest')
324    options = options_for_unittests.GetCopy()
325    options.output_format = 'none'
326    page_runner.Run(test, ps, expectations, options)
327
328  # Ensure that page_runner allows the test to customize the browser before it
329  # launches.
330  def testBrowserBeforeLaunch(self):
331    ps = page_set.PageSet()
332    expectations = test_expectations.TestExpectations()
333    page = page_module.Page(
334        'file://blank.html', ps, base_dir=util.GetUnittestDataDir())
335    ps.pages.append(page)
336
337    class TestBeforeLaunch(page_test.PageTest):
338      def __init__(self,
339                   test_method_name,
340                   action_name_to_run=''):
341        super(TestBeforeLaunch, self).__init__(
342            test_method_name, action_name_to_run, False)
343        self._did_call_will_start = False
344        self._did_call_did_start = False
345
346      def WillStartBrowser(self, browser):
347        self._did_call_will_start = True
348        # TODO(simonjam): Test that the profile is available.
349
350      def DidStartBrowser(self, browser):
351        assert self._did_call_will_start
352        self._did_call_did_start = True
353
354      def RunTest(self, page, tab, results): # pylint: disable=W0613,R0201
355        assert self._did_call_did_start
356
357    test = TestBeforeLaunch('RunTest')
358    options = options_for_unittests.GetCopy()
359    options.output_format = 'none'
360    page_runner.Run(test, ps, expectations, options)
361