Home | History | Annotate | Download | only in measurements
      1 # Copyright 2013 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 
      5 import unittest
      6 
      7 from telemetry.core import browser_options
      8 from telemetry.page import page_runner
      9 from telemetry.results import page_test_results
     10 from telemetry.unittest import simple_mock
     11 
     12 from measurements import page_cycler
     13 
     14 
     15 # Allow testing protected members in the unit test.
     16 # pylint: disable=W0212
     17 
     18 class MockMemoryMetric(object):
     19   """Used instead of simple_mock.MockObject so that the precise order and
     20   number of calls need not be specified."""
     21   def __init__(self):
     22     pass
     23 
     24   def Start(self, page, tab):
     25     pass
     26 
     27   def Stop(self, page, tab):
     28     pass
     29 
     30   def AddResults(self, tab, results):
     31     pass
     32 
     33   def AddSummaryResults(self, tab, results):
     34     pass
     35 
     36 
     37 class FakePage(object):
     38   """Used to mock loading a page."""
     39   def __init__(self, url):
     40     self.url = url
     41     self.is_file = url.startswith('file://')
     42 
     43 
     44 class FakeTab(object):
     45   """Used to mock a browser tab."""
     46   def __init__(self):
     47     self.clear_cache_calls = 0
     48     self.navigated_urls = []
     49   def ClearCache(self, force=False):
     50     assert force
     51     self.clear_cache_calls += 1
     52   def EvaluateJavaScript(self, _):
     53     return 1
     54   def Navigate(self, url):
     55     self.navigated_urls.append(url)
     56   def WaitForJavaScriptExpression(self, _, __):
     57     pass
     58   @property
     59   def browser(self):
     60     return FakeBrowser()
     61 
     62 class FakeBrowser(object):
     63   _iteration = 0
     64 
     65   @property
     66   def cpu_stats(self):
     67     FakeBrowser._iteration += 1
     68     return {
     69         'Browser': {'CpuProcessTime': FakeBrowser._iteration,
     70                     'TotalTime': FakeBrowser._iteration * 2},
     71         'Renderer': {'CpuProcessTime': FakeBrowser._iteration,
     72                     'TotalTime': FakeBrowser._iteration * 3},
     73         'Gpu': {'CpuProcessTime': FakeBrowser._iteration,
     74                  'TotalTime': FakeBrowser._iteration * 4}
     75     }
     76   @property
     77   def platform(self):
     78     return FakePlatform()
     79 
     80   @property
     81   def http_server(self):
     82     class FakeHttpServer(object):
     83       def UrlOf(self, url_path):
     84         return 'http://fakeserver:99999/%s' % url_path
     85     return FakeHttpServer()
     86 
     87 
     88 class FakePlatform(object):
     89   def GetOSName(self):
     90     return 'fake'
     91   def CanMonitorPower(self):
     92     return False
     93 
     94 
     95 class PageCyclerUnitTest(unittest.TestCase):
     96 
     97   def SetUpCycler(self, args, setup_memory_module=False):
     98     cycler = page_cycler.PageCycler()
     99     options = browser_options.BrowserFinderOptions()
    100     options.browser_options.platform = FakePlatform()
    101     parser = options.CreateParser()
    102     page_runner.AddCommandLineArgs(parser)
    103     cycler.AddCommandLineArgs(parser)
    104     cycler.SetArgumentDefaults(parser)
    105     parser.parse_args(args)
    106     page_runner.ProcessCommandLineArgs(parser, options)
    107     cycler.ProcessCommandLineArgs(parser, options)
    108     cycler.CustomizeBrowserOptions(options.browser_options)
    109 
    110     if setup_memory_module:
    111       # Mock out memory metrics; the real ones require a real browser.
    112       mock_memory_metric = MockMemoryMetric()
    113 
    114       mock_memory_module = simple_mock.MockObject()
    115       mock_memory_module.ExpectCall(
    116         'MemoryMetric').WithArgs(simple_mock.DONT_CARE).WillReturn(
    117         mock_memory_metric)
    118 
    119       real_memory_module = page_cycler.memory
    120       try:
    121         page_cycler.memory = mock_memory_module
    122         browser = FakeBrowser()
    123         cycler.WillStartBrowser(options.browser_options.platform)
    124         cycler.DidStartBrowser(browser)
    125       finally:
    126         page_cycler.memory = real_memory_module
    127 
    128     return cycler
    129 
    130   def testOptionsColdLoadNoArgs(self):
    131     cycler = self.SetUpCycler([])
    132 
    133     self.assertEquals(cycler._cold_run_start_index, 5)
    134 
    135   def testOptionsColdLoadPagesetRepeat(self):
    136     cycler = self.SetUpCycler(['--pageset-repeat=20', '--page-repeat=2'])
    137 
    138     self.assertEquals(cycler._cold_run_start_index, 20)
    139 
    140   def testOptionsColdLoadRequested(self):
    141     cycler = self.SetUpCycler(['--pageset-repeat=21', '--page-repeat=2',
    142                                '--cold-load-percent=40'])
    143 
    144     self.assertEquals(cycler._cold_run_start_index, 26)
    145 
    146   def testCacheHandled(self):
    147     cycler = self.SetUpCycler(['--pageset-repeat=5',
    148                                '--cold-load-percent=50'],
    149                               True)
    150 
    151     url_name = 'http://fakepage.com'
    152     page = FakePage(url_name)
    153     tab = FakeTab()
    154 
    155     for i in range(5):
    156       results = page_test_results.PageTestResults()
    157       results.WillRunPage(page)
    158       cycler.WillNavigateToPage(page, tab)
    159       self.assertEqual(max(0, i - 2), tab.clear_cache_calls,
    160                        'Iteration %d tab.clear_cache_calls %d' %
    161                        (i, tab.clear_cache_calls))
    162       cycler.ValidateAndMeasurePage(page, tab, results)
    163       results.DidRunPage(page)
    164 
    165       values = results.all_page_specific_values
    166       self.assertGreater(len(values), 2)
    167 
    168       self.assertEqual(values[0].page, page)
    169       chart_name = 'cold_times' if i == 0 or i > 2 else 'warm_times'
    170       self.assertEqual(values[0].name, '%s.page_load_time' % chart_name)
    171       self.assertEqual(values[0].units, 'ms')
    172 
    173       cycler.DidNavigateToPage(page, tab)
    174 
    175   def testColdWarm(self):
    176     cycler = self.SetUpCycler(['--pageset-repeat=3'], True)
    177     pages = [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
    178     tab = FakeTab()
    179     for i in range(3):
    180       for page in pages:
    181         results = page_test_results.PageTestResults()
    182         results.WillRunPage(page)
    183         cycler.WillNavigateToPage(page, tab)
    184         cycler.ValidateAndMeasurePage(page, tab, results)
    185         results.DidRunPage(page)
    186 
    187         values = results.all_page_specific_values
    188         self.assertGreater(len(values), 2)
    189 
    190         self.assertEqual(values[0].page, page)
    191 
    192         chart_name = 'cold_times' if i == 0 or i > 1 else 'warm_times'
    193         self.assertEqual(values[0].name, '%s.page_load_time' % chart_name)
    194         self.assertEqual(values[0].units, 'ms')
    195 
    196         cycler.DidNavigateToPage(page, tab)
    197 
    198   def testResults(self):
    199     cycler = self.SetUpCycler([], True)
    200 
    201     pages = [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
    202     tab = FakeTab()
    203 
    204     for i in range(2):
    205       for page in pages:
    206         results = page_test_results.PageTestResults()
    207         results.WillRunPage(page)
    208         cycler.WillNavigateToPage(page, tab)
    209         cycler.ValidateAndMeasurePage(page, tab, results)
    210         results.DidRunPage(page)
    211 
    212         values = results.all_page_specific_values
    213         self.assertEqual(4, len(values))
    214 
    215         self.assertEqual(values[0].page, page)
    216         chart_name = 'cold_times' if i == 0 else 'warm_times'
    217         self.assertEqual(values[0].name, '%s.page_load_time' % chart_name)
    218         self.assertEqual(values[0].units, 'ms')
    219 
    220         for value, expected in zip(values[1:], ['gpu', 'renderer', 'browser']):
    221           self.assertEqual(value.page, page)
    222           self.assertEqual(value.name,
    223                            'cpu_utilization.cpu_utilization_%s' % expected)
    224           self.assertEqual(value.units, '%')
    225 
    226         cycler.DidNavigateToPage(page, tab)
    227 
    228   def testLegacyPagesAvoidCrossRenderNavigation(self):
    229     # For legacy page cyclers with file URLs, verify that WillNavigateToPage
    230     # does an initial navigate to avoid paying for a cross-renderer navigation.
    231     cycler = self.SetUpCycler([], True)
    232     pages = [FakePage('file://fakepage1.com'), FakePage('file://fakepage2.com')]
    233     tab = FakeTab()
    234 
    235     self.assertEqual([], tab.navigated_urls)
    236     for page in pages * 2:
    237       cycler.WillNavigateToPage(page, tab)
    238       self.assertEqual(
    239           ['http://fakeserver:99999/nonexistent.html'], tab.navigated_urls)
    240