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
.internal
.browser
import browser_options
9 from telemetry
.internal
.results
import page_test_results
10 from telemetry
.internal
import story_runner
11 from telemetry
.testing
import simple_mock
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 def supports_cpu_metrics(self
):
102 def supports_memory_metrics(self
):
106 def supports_power_metrics(self
):
110 class FakePlatform(object):
113 def CanMonitorPower(self
):
117 class PageCyclerUnitTest(unittest
.TestCase
):
119 def SetUpCycler(self
, page_repeat
=1, pageset_repeat
=10, cold_load_percent
=50,
120 report_speed_index
=False, setup_memory_module
=False):
121 cycler
= page_cycler
.PageCycler(
122 page_repeat
= page_repeat
,
123 pageset_repeat
= pageset_repeat
,
124 cold_load_percent
= cold_load_percent
,
125 report_speed_index
= report_speed_index
)
126 options
= browser_options
.BrowserFinderOptions()
127 options
.browser_options
.platform
= FakePlatform()
128 parser
= options
.CreateParser()
129 story_runner
.AddCommandLineArgs(parser
)
130 args
= ['--page-repeat=%i' % page_repeat
,
131 '--pageset-repeat=%i' % pageset_repeat
]
132 parser
.parse_args(args
)
133 story_runner
.ProcessCommandLineArgs(parser
, options
)
134 cycler
.CustomizeBrowserOptions(options
.browser_options
)
136 if setup_memory_module
:
137 # Mock out memory metrics; the real ones require a real browser.
138 mock_memory_metric
= MockMemoryMetric()
140 mock_memory_module
= simple_mock
.MockObject()
141 mock_memory_module
.ExpectCall(
142 'MemoryMetric').WithArgs(simple_mock
.DONT_CARE
).WillReturn(
145 real_memory_module
= page_cycler
.memory
147 page_cycler
.memory
= mock_memory_module
148 browser
= FakeBrowser()
149 cycler
.WillStartBrowser(options
.browser_options
.platform
)
150 cycler
.DidStartBrowser(browser
)
152 page_cycler
.memory
= real_memory_module
156 def testOptionsColdLoadNoArgs(self
):
157 cycler
= self
.SetUpCycler()
159 self
.assertEquals(cycler
._cold
_run
_start
_index
, 5)
161 def testOptionsColdLoadPagesetRepeat(self
):
162 cycler
= self
.SetUpCycler(pageset_repeat
=20, page_repeat
=2)
164 self
.assertEquals(cycler
._cold
_run
_start
_index
, 20)
166 def testOptionsColdLoadRequested(self
):
167 cycler
= self
.SetUpCycler(pageset_repeat
=21, page_repeat
=2,
168 cold_load_percent
=40)
170 self
.assertEquals(cycler
._cold
_run
_start
_index
, 26)
172 def testCacheHandled(self
):
173 cycler
= self
.SetUpCycler(pageset_repeat
=5,
174 cold_load_percent
=50,
175 setup_memory_module
=True)
177 url_name
= 'http://fakepage.com'
178 page
= FakePage(url_name
)
182 results
= page_test_results
.PageTestResults()
183 results
.WillRunPage(page
)
184 cycler
.WillNavigateToPage(page
, tab
)
185 self
.assertEqual(max(0, i
- 2), tab
.clear_cache_calls
,
186 'Iteration %d tab.clear_cache_calls %d' %
187 (i
, tab
.clear_cache_calls
))
188 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
189 results
.DidRunPage(page
)
191 values
= results
.all_page_specific_values
192 self
.assertGreater(len(values
), 2)
194 self
.assertEqual(values
[0].page
, page
)
195 chart_name
= 'cold_times' if i
== 0 or i
> 2 else 'warm_times'
196 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
197 self
.assertEqual(values
[0].units
, 'ms')
199 cycler
.DidNavigateToPage(page
, tab
)
201 def testColdWarm(self
):
202 cycler
= self
.SetUpCycler(pageset_repeat
=3, setup_memory_module
=True)
203 pages
= [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
207 results
= page_test_results
.PageTestResults()
208 results
.WillRunPage(page
)
209 cycler
.WillNavigateToPage(page
, tab
)
210 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
211 results
.DidRunPage(page
)
213 values
= results
.all_page_specific_values
214 self
.assertGreater(len(values
), 2)
216 self
.assertEqual(values
[0].page
, page
)
218 chart_name
= 'cold_times' if i
== 0 or i
> 1 else 'warm_times'
219 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
220 self
.assertEqual(values
[0].units
, 'ms')
222 cycler
.DidNavigateToPage(page
, tab
)
224 def testResults(self
):
225 cycler
= self
.SetUpCycler(setup_memory_module
=True)
227 pages
= [FakePage('http://fakepage1.com'), FakePage('http://fakepage2.com')]
232 results
= page_test_results
.PageTestResults()
233 results
.WillRunPage(page
)
234 cycler
.WillNavigateToPage(page
, tab
)
235 cycler
.ValidateAndMeasurePage(page
, tab
, results
)
236 results
.DidRunPage(page
)
238 values
= results
.all_page_specific_values
240 # On Mac, there is an additional measurement: the number of keychain
243 if sys
.platform
== 'darwin':
245 self
.assertEqual(value_count
, len(values
))
247 self
.assertEqual(values
[0].page
, page
)
248 chart_name
= 'cold_times' if i
== 0 else 'warm_times'
249 self
.assertEqual(values
[0].name
, '%s.page_load_time' % chart_name
)
250 self
.assertEqual(values
[0].units
, 'ms')
252 expected_values
= ['gpu', 'browser']
253 for value
, expected
in zip(values
[1:len(expected_values
) + 1],
255 self
.assertEqual(value
.page
, page
)
256 self
.assertEqual(value
.name
,
257 'cpu_utilization.cpu_utilization_%s' % expected
)
258 self
.assertEqual(value
.units
, '%')
260 cycler
.DidNavigateToPage(page
, tab
)
262 def testLegacyPagesAvoidCrossRenderNavigation(self
):
263 # For legacy page cyclers with file URLs, verify that WillNavigateToPage
264 # does an initial navigate to avoid paying for a cross-renderer navigation.
265 cycler
= self
.SetUpCycler(setup_memory_module
=True)
266 pages
= [FakePage('file://fakepage1.com'), FakePage('file://fakepage2.com')]
269 self
.assertEqual([], tab
.navigated_urls
)
270 for page
in pages
* 2:
271 cycler
.WillNavigateToPage(page
, tab
)
273 ['http://fakeserver:99999/nonexistent.html'], tab
.navigated_urls
)