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