Change next_proto member type.
[chromium-blink-merge.git] / tools / perf / metrics / speedindex_unittest.py
blob25f3433a20ec5d84b7a6ab86f408c3225cf0ccf3
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.
5 # These tests access private methods in the speedindex module.
6 # pylint: disable=W0212
8 import json
9 import os
10 import unittest
12 from telemetry.core import bitmap
13 from telemetry.timeline import inspector_timeline_data
14 from telemetry.timeline import model
15 from metrics import speedindex
17 # Sample timeline data in the json format provided by devtools.
18 # The sample events will be used in several tests below.
19 _TEST_DIR = os.path.join(os.path.dirname(__file__), 'unittest_data')
20 _SAMPLE_DATA = json.load(open(os.path.join(_TEST_DIR, 'sample_timeline.json')))
21 _SAMPLE_TIMELINE_DATA = inspector_timeline_data.InspectorTimelineData(
22 _SAMPLE_DATA)
23 _SAMPLE_EVENTS = model.TimelineModel(
24 timeline_data=_SAMPLE_TIMELINE_DATA).GetAllEvents()
27 class FakeTimelineModel(object):
29 def __init__(self):
30 self._events = []
32 def SetAllEvents(self, events):
33 self._events = events
35 def GetAllEvents(self, recursive=True):
36 assert recursive == True
37 return self._events
40 class FakeVideo(object):
42 def __init__(self, frames):
43 self._frames = frames
45 def GetVideoFrameIter(self):
46 for frame in self._frames:
47 yield frame
49 class FakeBitmap(object):
51 def __init__(self, r, g, b):
52 self._histogram = bitmap.ColorHistogram(r, g, b, bitmap.WHITE)
54 # pylint: disable=W0613
55 def ColorHistogram(self, ignore_color=None, tolerance=None):
56 return self._histogram
59 class FakeTab(object):
61 def __init__(self, video_capture_result=None):
62 self._timeline_model = FakeTimelineModel()
63 self._javascript_result = None
64 self._video_capture_result = FakeVideo(video_capture_result)
66 @property
67 def timeline_model(self):
68 return self._timeline_model
70 @property
71 def video_capture_supported(self):
72 return self._video_capture_result is not None
74 def SetEvaluateJavaScriptResult(self, result):
75 self._javascript_result = result
77 def EvaluateJavaScript(self, _):
78 return self._javascript_result
80 def StartVideoCapture(self, min_bitrate_mbps=1):
81 assert self.video_capture_supported
82 assert min_bitrate_mbps > 0
84 def StopVideoCapture(self):
85 assert self.video_capture_supported
86 return self._video_capture_result
88 def Highlight(self, _):
89 pass
92 class IncludedPaintEventsTest(unittest.TestCase):
93 def testNumberPaintEvents(self):
94 impl = speedindex.PaintRectSpeedIndexImpl()
95 # In the sample data, there's one event that occurs before the layout event,
96 # and one paint event that's not a leaf paint event.
97 events = impl._IncludedPaintEvents(_SAMPLE_EVENTS)
98 self.assertEqual(len(events), 5)
101 class SpeedIndexImplTest(unittest.TestCase):
102 def testAdjustedAreaDict(self):
103 impl = speedindex.PaintRectSpeedIndexImpl()
104 paint_events = impl._IncludedPaintEvents(_SAMPLE_EVENTS)
105 viewport = 1000, 1000
106 time_area_dict = impl._TimeAreaDict(paint_events, viewport)
107 self.assertEqual(len(time_area_dict), 4)
108 # The event that ends at time 100 is a fullscreen; it's discounted by half.
109 self.assertEqual(time_area_dict[100], 500000)
110 self.assertEqual(time_area_dict[300], 100000)
111 self.assertEqual(time_area_dict[400], 200000)
112 self.assertEqual(time_area_dict[800], 200000)
114 def testVideoCompleteness(self):
115 frames = [
116 (0.0, FakeBitmap([ 0, 0, 0,10], [ 0, 0, 0,10], [ 0, 0, 0,10])),
117 (0.1, FakeBitmap([10, 0, 0, 0], [10, 0, 0, 0], [10, 0, 0, 0])),
118 (0.2, FakeBitmap([ 0, 0, 2, 8], [ 0, 0, 4, 6], [ 0, 0, 1, 9])),
119 (0.3, FakeBitmap([ 0, 3, 2, 5], [ 2, 1, 0, 7], [ 0, 3, 0, 7])),
120 (0.4, FakeBitmap([ 0, 0, 1, 0], [ 0, 0, 1, 0], [ 0, 0, 1, 0])),
121 (0.5, FakeBitmap([ 0, 4, 6, 0], [ 0, 4, 6, 0], [ 0, 4, 6, 0])),
123 max_distance = 42.
125 tab = FakeTab(frames)
126 impl = speedindex.VideoSpeedIndexImpl()
127 impl.Start(tab)
128 impl.Stop(tab)
129 time_completeness = impl.GetTimeCompletenessList(tab)
130 self.assertEqual(len(time_completeness), 6)
131 self.assertEqual(time_completeness[0], (0.0, 0))
132 self.assertTimeCompleteness(
133 time_completeness[1], 0.1, 1 - (16 + 16 + 16) / max_distance)
134 self.assertTimeCompleteness(
135 time_completeness[2], 0.2, 1 - (12 + 10 + 13) / max_distance)
136 self.assertTimeCompleteness(
137 time_completeness[3], 0.3, 1 - (6 + 10 + 8) / max_distance)
138 self.assertTimeCompleteness(
139 time_completeness[4], 0.4, 1 - (4 + 4 + 4) / max_distance)
140 self.assertEqual(time_completeness[5], (0.5, 1))
142 def testBlankPage(self):
143 frames = [
144 (0.0, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
145 (0.1, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
146 (0.2, FakeBitmap([1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1])),
147 (0.3, FakeBitmap([0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1])),
149 tab = FakeTab(frames)
150 impl = speedindex.VideoSpeedIndexImpl()
151 impl.Start(tab)
152 impl.Stop(tab)
153 time_completeness = impl.GetTimeCompletenessList(tab)
154 self.assertEqual(len(time_completeness), 4)
155 self.assertEqual(time_completeness[0], (0.0, 1.0))
156 self.assertEqual(time_completeness[1], (0.1, 1.0))
157 self.assertEqual(time_completeness[2], (0.2, 0.0))
158 self.assertEqual(time_completeness[3], (0.3, 1.0))
160 def assertTimeCompleteness(self, time_completeness, time, completeness):
161 self.assertEqual(time_completeness[0], time)
162 self.assertAlmostEqual(time_completeness[1], completeness)
165 class SpeedIndexTest(unittest.TestCase):
166 def testWithSampleData(self):
167 tab = FakeTab()
168 impl = speedindex.PaintRectSpeedIndexImpl()
169 viewport = 1000, 1000
170 # Add up the parts of the speed index for each time interval.
171 # Each part is the time interval multiplied by the proportion of the
172 # total area value that is not yet painted for that interval.
173 parts = []
174 parts.append(100 * 1.0)
175 parts.append(200 * 0.5)
176 parts.append(100 * 0.4)
177 parts.append(400 * 0.2)
178 expected = sum(parts) # 330.0
179 tab.timeline_model.SetAllEvents(_SAMPLE_EVENTS)
180 tab.SetEvaluateJavaScriptResult(viewport)
181 actual = impl.CalculateSpeedIndex(tab)
182 self.assertEqual(actual, expected)
185 class WPTComparisonTest(unittest.TestCase):
186 """Compare the speed index results with results given by webpagetest.org.
188 Given the same timeline data, both this speedindex metric and webpagetest.org
189 should both return the same results. Fortunately, webpagetest.org also
190 provides timeline data in json format along with the speed index results.
193 def _TestJsonTimelineExpectation(self, filename, viewport, expected):
194 """Check whether the result for some timeline data is as expected.
196 Args:
197 filename: Filename of a json file which contains a
198 expected: The result expected based on the WPT result.
200 tab = FakeTab()
201 impl = speedindex.PaintRectSpeedIndexImpl()
202 file_path = os.path.join(_TEST_DIR, filename)
203 with open(file_path) as json_file:
204 raw_events = json.load(json_file)
205 timeline_data = inspector_timeline_data.InspectorTimelineData(raw_events)
206 tab.timeline_model.SetAllEvents(
207 model.TimelineModel(timeline_data=timeline_data).GetAllEvents())
208 tab.SetEvaluateJavaScriptResult(viewport)
209 actual = impl.CalculateSpeedIndex(tab)
210 # The result might differ by 1 or more milliseconds due to rounding,
211 # so compare to the nearest 10 milliseconds.
212 self.assertAlmostEqual(actual, expected, places=-1)
214 def testCern(self):
215 # Page: http://info.cern.ch/hypertext/WWW/TheProject.html
216 # This page has only one paint event.
217 self._TestJsonTimelineExpectation(
218 'cern_repeat_timeline.json', (1014, 650), 379.0)
220 def testBaidu(self):
221 # Page: http://www.baidu.com/
222 # This page has several paint events, but no nested paint events.
223 self._TestJsonTimelineExpectation(
224 'baidu_repeat_timeline.json', (1014, 650), 1761.43)
226 def test2ch(self):
227 # Page: http://2ch.net/
228 # This page has several paint events, including nested paint events.
229 self._TestJsonTimelineExpectation(
230 '2ch_repeat_timeline.json', (997, 650), 674.58)
233 if __name__ == "__main__":
234 unittest.main()