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
12 from telemetry
.core
.timeline
import model
13 from metrics
import speedindex
15 # Sample timeline data in the json format provided by devtools.
16 # The sample events will be used in several tests below.
17 _TEST_DIR
= os
.path
.join(os
.path
.dirname(__file__
), 'unittest_data')
18 _SAMPLE_DATA
= json
.load(open(os
.path
.join(_TEST_DIR
, 'sample_timeline.json')))
19 _SAMPLE_EVENTS
= model
.TimelineModel(event_data
=_SAMPLE_DATA
).GetAllEvents()
22 class FakeTimelineModel(object):
27 def SetAllEvents(self
, events
):
30 def GetAllEvents(self
):
34 class FakeBitmap(object):
36 def __init__(self
, histogram
):
37 self
._histogram
= histogram
39 # pylint: disable=W0613
40 def ColorHistogram(self
, ignore_color
=None, tolerance
=None):
41 return self
._histogram
44 class FakeTab(object):
46 def __init__(self
, video_capture_result
=None):
47 self
._timeline
_model
= FakeTimelineModel()
48 self
._javascript
_result
= None
49 self
._video
_capture
_result
= video_capture_result
52 def timeline_model(self
):
53 return self
._timeline
_model
56 def video_capture_supported(self
):
57 return self
._video
_capture
_result
is not None
59 def SetEvaluateJavaScriptResult(self
, result
):
60 self
._javascript
_result
= result
62 def EvaluateJavaScript(self
, _
):
63 return self
._javascript
_result
65 def StartVideoCapture(self
, min_bitrate_mbps
=1):
66 assert self
.video_capture_supported
67 assert min_bitrate_mbps
> 0
69 def StopVideoCapture(self
):
70 assert self
.video_capture_supported
71 return self
._video
_capture
_result
73 def Highlight(self
, _
):
77 class IncludedPaintEventsTest(unittest
.TestCase
):
78 def testNumberPaintEvents(self
):
79 impl
= speedindex
.PaintRectSpeedIndexImpl()
80 # In the sample data, there's one event that occurs before the layout event,
81 # and one paint event that's not a leaf paint event.
82 events
= impl
._IncludedPaintEvents
(_SAMPLE_EVENTS
)
83 self
.assertEquals(len(events
), 5)
86 class SpeedIndexImplTest(unittest
.TestCase
):
87 def testAdjustedAreaDict(self
):
88 impl
= speedindex
.PaintRectSpeedIndexImpl()
89 paint_events
= impl
._IncludedPaintEvents
(_SAMPLE_EVENTS
)
91 time_area_dict
= impl
._TimeAreaDict
(paint_events
, viewport
)
92 self
.assertEquals(len(time_area_dict
), 4)
93 # The event that ends at time 100 is a fullscreen; it's discounted by half.
94 self
.assertEquals(time_area_dict
[100], 500000)
95 self
.assertEquals(time_area_dict
[300], 100000)
96 self
.assertEquals(time_area_dict
[400], 200000)
97 self
.assertEquals(time_area_dict
[800], 200000)
99 def testVideoCompleteness(self
):
101 (0.0, FakeBitmap([100, 0, 0])),
102 (0.1, FakeBitmap([50, 25, 25])),
103 (0.2, FakeBitmap([60, 0, 40])),
104 (0.3, FakeBitmap([0, 10, 90]))
106 tab
= FakeTab(frames
)
107 impl
= speedindex
.VideoSpeedIndexImpl()
110 time_completeness
= impl
.GetTimeCompletenessList(tab
)
111 self
.assertEquals(len(time_completeness
), 4)
112 self
.assertEquals(time_completeness
[0], (0.0, 0.0))
113 self
.assertEquals(time_completeness
[1], (0.1, 0.425))
114 self
.assertEquals(time_completeness
[2], (0.2, 0.4))
115 self
.assertEquals(time_completeness
[3], (0.3, 1.0))
118 class SpeedIndexTest(unittest
.TestCase
):
119 def testWithSampleData(self
):
121 impl
= speedindex
.PaintRectSpeedIndexImpl()
122 viewport
= 1000, 1000
123 # Add up the parts of the speed index for each time interval.
124 # Each part is the time interval multiplied by the proportion of the
125 # total area value that is not yet painted for that interval.
127 parts
.append(100 * 1.0)
128 parts
.append(200 * 0.5)
129 parts
.append(100 * 0.4)
130 parts
.append(400 * 0.2)
131 expected
= sum(parts
) # 330.0
132 tab
.timeline_model
.SetAllEvents(_SAMPLE_EVENTS
)
133 tab
.SetEvaluateJavaScriptResult(viewport
)
134 actual
= impl
.CalculateSpeedIndex(tab
)
135 self
.assertEqual(actual
, expected
)
138 class WPTComparisonTest(unittest
.TestCase
):
139 """Compare the speed index results with results given by webpagetest.org.
141 Given the same timeline data, both this speedindex metric and webpagetest.org
142 should both return the same results. Fortunately, webpagetest.org also
143 provides timeline data in json format along with the speed index results.
146 def _TestJsonTimelineExpectation(self
, filename
, viewport
, expected
):
147 """Check whether the result for some timeline data is as expected.
150 filename: Filename of a json file which contains a
151 expected: The result expected based on the WPT result.
154 impl
= speedindex
.PaintRectSpeedIndexImpl()
155 file_path
= os
.path
.join(_TEST_DIR
, filename
)
156 with
open(file_path
) as json_file
:
157 raw_events
= json
.load(json_file
)
158 tab
.timeline_model
.SetAllEvents(
159 model
.TimelineModel(event_data
=raw_events
).GetAllEvents())
160 tab
.SetEvaluateJavaScriptResult(viewport
)
161 actual
= impl
.CalculateSpeedIndex(tab
)
162 # The result might differ by 1 or more milliseconds due to rounding,
163 # so compare to the nearest 10 milliseconds.
164 self
.assertAlmostEqual(actual
, expected
, places
=-1)
167 # Page: http://info.cern.ch/hypertext/WWW/TheProject.html
168 # This page has only one paint event.
169 self
._TestJsonTimelineExpectation
(
170 'cern_repeat_timeline.json', (1014, 650), 379.0)
173 # Page: http://www.baidu.com/
174 # This page has several paint events, but no nested paint events.
175 self
._TestJsonTimelineExpectation
(
176 'baidu_repeat_timeline.json', (1014, 650), 1761.43)
179 # Page: http://2ch.net/
180 # This page has several paint events, including nested paint events.
181 self
._TestJsonTimelineExpectation
(
182 '2ch_repeat_timeline.json', (997, 650), 674.58)
185 if __name__
== "__main__":