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.
8 from telemetry
.core
import browser_options
9 from telemetry
.results
import page_test_results
10 from telemetry
.unittest_util
import simple_mock
11 from telemetry
.user_story
import user_story_runner
13 from measurements
import page_cycler
14 from metrics
import keychain_metric
17 # Allow testing protected members in the unit test.
18 # pylint: disable=W0212
20 class MockMemoryMetric(object):
21 """Used instead of simple_mock.MockObject so that the precise order and
22 number of calls need not be specified."""
26 def Start(self
, page
, tab
):
29 def Stop(self
, page
, tab
):
32 def AddResults(self
, tab
, results
):
35 def AddSummaryResults(self
, tab
, results
):
39 class FakePage(object):
40 """Used to mock loading a page."""
41 def __init__(self
, url
):
43 self
.is_file
= url
.startswith('file://')
46 class FakeTab(object):
47 """Used to mock a browser tab."""
49 self
.clear_cache_calls
= 0
50 self
.navigated_urls
= []
51 def ClearCache(self
, force
=False):
53 self
.clear_cache_calls
+= 1
54 def EvaluateJavaScript(self
, script
):
55 # If the page cycler invokes javascript to measure the number of keychain
56 # accesses, return a valid JSON dictionary.
57 keychain_histogram_name
= keychain_metric
.KeychainMetric
.HISTOGRAM_NAME
59 # Fake data for keychain metric.
60 if keychain_histogram_name
in script
:
61 return '{{ "{0}" : 0 }}'.format(keychain_histogram_name
)
64 def Navigate(self
, url
):
65 self
.navigated_urls
.append(url
)
66 def WaitForJavaScriptExpression(self
, _
, __
):
72 class FakeBrowser(object):
77 FakeBrowser
._iteration
+= 1
79 'Browser': {'CpuProcessTime': FakeBrowser
._iteration
,
80 'TotalTime': FakeBrowser
._iteration
* 2},
81 'Renderer': {'CpuProcessTime': FakeBrowser
._iteration
,
82 'TotalTime': FakeBrowser
._iteration
* 3},
83 'Gpu': {'CpuProcessTime': FakeBrowser
._iteration
,
84 'TotalTime': FakeBrowser
._iteration
* 4}
91 def http_server(self
):
92 class FakeHttpServer(object):
93 def UrlOf(self
, url_path
):
94 return 'http://fakeserver:99999/%s' % url_path
95 return FakeHttpServer()
98 class FakePlatform(object):
101 def CanMonitorPower(self
):
105 class PageCyclerUnitTest(unittest
.TestCase
):
107 def SetUpCycler(self
, page_repeat
=1, pageset_repeat
=10, cold_load_percent
=50,
108 report_speed_index
=False, setup_memory_module
=False):
109 cycler
= page_cycler
.PageCycler(
110 page_repeat
= page_repeat
,
111 pageset_repeat
= pageset_repeat
,
112 cold_load_percent
= cold_load_percent
,
113 report_speed_index
= report_speed_index
)
114 options
= browser_options
.BrowserFinderOptions()
115 options
.browser_options
.platform
= FakePlatform()
116 parser
= options
.CreateParser()
117 user_story_runner
.AddCommandLineArgs(parser
)
118 args
= ['--page-repeat=%i' % page_repeat
,
119 '--pageset-repeat=%i' % pageset_repeat
]
120 parser
.parse_args(args
)
121 user_story_runner
.ProcessCommandLineArgs(parser
, options
)
122 cycler
.CustomizeBrowserOptions(options
.browser_options
)
124 if setup_memory_module
:
125 # Mock out memory metrics; the real ones require a real browser.
126 mock_memory_metric
= MockMemoryMetric()
128 mock_memory_module
= simple_mock
.MockObject()
129 mock_memory_module
.ExpectCall(
130 'MemoryMetric').WithArgs(simple_mock
.DONT_CARE
).WillReturn(
133 real_memory_module
= page_cycler
.memory
135 page_cycler
.memory
= mock_memory_module
136 browser
= FakeBrowser()
137 cycler
.WillStartBrowser(options
.browser_options
.platform
)
138 cycler
.DidStartBrowser(browser
)
140 page_cycler
.memory
= real_memory_module
144 def testOptionsColdLoadNoArgs(self
):
145 cycler
= self
.SetUpCycler()
147 self
.assertEquals(cycler
._cold
_run
_start
_index
, 5)
149 def testOptionsColdLoadPagesetRepeat(self
):
150 cycler
= self
.SetUpCycler(pageset_repeat
=20, page_repeat
=2)
152 self
.assertEquals(cycler
._cold
_run
_start
_index
, 20)
154 def testOptionsColdLoadRequested(self
):
155 cycler
= self
.SetUpCycler(pageset_repeat
=21, page_repeat
=2,
156 cold_load_percent
=40)
158 self
.assertEquals(cycler
._cold
_run
_start
_index
, 26)
160 def testCacheHandled(self
):
161 cycler
= self
.SetUpCycler(pageset_repeat
=5,
162 cold_load_percent
=50,
163 setup_memory_module
=True)
165 url_name
= 'http://fakepage.com'
166 page
= FakePage(url_name
)
170 results
= page_test_results
.PageTestResults()
171 results
.WillRunPage(page
)
172 cycler
.WillNavigateToPage(page
, tab
)
173 self
.assertEqual(max(0, i
- 2), tab
.clear_cache_calls
,
174 'Iteration %d tab.clear_cache_calls %d' %
175 (i
, tab
.clear_cache_calls
))
176 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
177 results
.DidRunPage(page
)
179 values
= results
.all_page_specific_values
180 self
.assertGreater(len(values
), 2)
182 self
.assertEqual(values
[0].page
, page
)
183 chart_name
= 'cold_times' if i
== 0 or i
> 2 else 'warm_times'
184 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
185 self
.assertEqual(values
[0].units
, 'ms')
187 cycler
.DidNavigateToPage(page
, tab
)
189 def testColdWarm(self
):
190 cycler
= self
.SetUpCycler(pageset_repeat
=3, setup_memory_module
=True)
191 pages
= [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
195 results
= page_test_results
.PageTestResults()
196 results
.WillRunPage(page
)
197 cycler
.WillNavigateToPage(page
, tab
)
198 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
199 results
.DidRunPage(page
)
201 values
= results
.all_page_specific_values
202 self
.assertGreater(len(values
), 2)
204 self
.assertEqual(values
[0].page
, page
)
206 chart_name
= 'cold_times' if i
== 0 or i
> 1 else 'warm_times'
207 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
208 self
.assertEqual(values
[0].units
, 'ms')
210 cycler
.DidNavigateToPage(page
, tab
)
212 def testResults(self
):
213 cycler
= self
.SetUpCycler(setup_memory_module
=True)
215 pages
= [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
220 results
= page_test_results
.PageTestResults()
221 results
.WillRunPage(page
)
222 cycler
.WillNavigateToPage(page
, tab
)
223 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
224 results
.DidRunPage(page
)
226 values
= results
.all_page_specific_values
228 # On Mac, there is an additional measurement: the number of keychain
231 if sys
.platform
== 'darwin':
233 self
.assertEqual(value_count
, len(values
))
235 self
.assertEqual(values
[0].page
, page
)
236 chart_name
= 'cold_times' if i
== 0 else 'warm_times'
237 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
238 self
.assertEqual(values
[0].units
, 'ms')
240 expected_values
= ['gpu', 'renderer', 'browser']
241 for value
, expected
in zip(values
[1:len(expected_values
) + 1],
243 self
.assertEqual(value
.page
, page
)
244 self
.assertEqual(value
.name
,
245 'cpu_utilization.cpu_utilization_%s' % expected
)
246 self
.assertEqual(value
.units
, '%')
248 cycler
.DidNavigateToPage(page
, tab
)
250 def testLegacyPagesAvoidCrossRenderNavigation(self
):
251 # For legacy page cyclers with file URLs, verify that WillNavigateToPage
252 # does an initial navigate to avoid paying for a cross-renderer navigation.
253 cycler
= self
.SetUpCycler(setup_memory_module
=True)
254 pages
= [FakePage('file://fakepage1.com'), FakePage('file://fakepage2.com')]
257 self
.assertEqual([], tab
.navigated_urls
)
258 for page
in pages
* 2:
259 cycler
.WillNavigateToPage(page
, tab
)
261 ['http://fakeserver:99999/nonexistent.html'], tab
.navigated_urls
)