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.
4import sys
5
6from measurements import smoothness
7from metrics import power
8from telemetry.core import exceptions
9from telemetry.core import wpr_modes
10from telemetry.page import page
11from telemetry.page import page_test
12from telemetry.unittest import options_for_unittests
13from telemetry.unittest import page_test_test_case
14from telemetry.unittest import test
15
16class FakeTracingController(object):
17  def __init__(self):
18    self.category_filter = None
19  def Start(self, _options, category_filter, _timeout):
20    self.category_filter = category_filter
21
22
23class FakePlatform(object):
24  def __init__(self):
25    self.tracing_controller = FakeTracingController()
26  def IsRawDisplayFrameRateSupported(self):
27    return False
28  def CanMonitorPower(self):
29    return False
30
31
32class FakeBrowser(object):
33  def __init__(self):
34    self.platform = FakePlatform()
35
36
37class AnimatedPage(page.Page):
38  def __init__(self, page_set):
39    super(AnimatedPage, self).__init__(
40      url='file://animated_page.html',
41      page_set=page_set, base_dir=page_set.base_dir)
42
43  def RunSmoothness(self, action_runner):
44    action_runner.Wait(.2)
45
46
47class FakeTab(object):
48  def __init__(self):
49    self.browser = FakeBrowser()
50
51  def ExecuteJavaScript(self, js):
52    pass
53
54class SmoothnessUnitTest(page_test_test_case.PageTestTestCase):
55  """Smoke test for smoothness measurement
56
57     Runs smoothness measurement on a simple page and verifies
58     that all metrics were added to the results. The test is purely functional,
59     i.e. it only checks if the metrics are present and non-zero.
60  """
61  def testSyntheticDelayConfiguration(self):
62    test_page = page.Page('http://dummy', None)
63    test_page.synthetic_delays = {
64        'cc.BeginMainFrame': { 'target_duration': 0.012 },
65        'cc.DrawAndSwap': { 'target_duration': 0.012, 'mode': 'alternating' },
66        'gpu.PresentingFrame': { 'target_duration': 0.012 }
67    }
68
69    tab = FakeTab()
70    measurement = smoothness.Smoothness()
71    measurement.WillStartBrowser(tab.browser.platform)
72    measurement.WillNavigateToPage(test_page, tab)
73    measurement.WillRunActions(test_page, tab)
74
75    expected_category_filter = set([
76        'DELAY(cc.BeginMainFrame;0.012000;static)',
77        'DELAY(cc.DrawAndSwap;0.012000;alternating)',
78        'DELAY(gpu.PresentingFrame;0.012000;static)',
79        'benchmark'
80    ])
81    tracing_controller = tab.browser.platform.tracing_controller
82    actual_category_filter = (
83      tracing_controller.category_filter.included_categories)
84
85    # FIXME: Put blink.console into the expected above and remove these two
86    # remove entries when the blink.console change has rolled into chromium.
87    actual_category_filter.remove('webkit.console')
88    actual_category_filter.remove('blink.console')
89
90    if expected_category_filter != actual_category_filter:
91      sys.stderr.write("Expected category filter: %s\n" %
92                       repr(expected_category_filter))
93      sys.stderr.write("Actual category filter filter: %s\n" %
94                       repr(actual_category_filter))
95    self.assertEquals(expected_category_filter, actual_category_filter)
96
97  def setUp(self):
98    self._options = options_for_unittests.GetCopy()
99    self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF
100
101  def testSmoothness(self):
102    ps = self.CreatePageSetFromFileInUnittestDataDir('scrollable_page.html')
103    measurement = smoothness.Smoothness()
104    results = self.RunMeasurement(measurement, ps, options=self._options)
105    self.assertEquals(0, len(results.failures))
106
107    frame_times = results.FindAllPageSpecificValuesNamed('frame_times')
108    self.assertEquals(len(frame_times), 1)
109    self.assertGreater(frame_times[0].GetRepresentativeNumber(), 0)
110
111    mean_frame_time = results.FindAllPageSpecificValuesNamed('mean_frame_time')
112    self.assertEquals(len(mean_frame_time), 1)
113    self.assertGreater(mean_frame_time[0].GetRepresentativeNumber(), 0)
114
115    jank = results.FindAllPageSpecificValuesNamed('jank')
116    self.assertEquals(len(jank), 1)
117    self.assertGreater(jank[0].GetRepresentativeNumber(), 0)
118
119    mostly_smooth = results.FindAllPageSpecificValuesNamed('mostly_smooth')
120    self.assertEquals(len(mostly_smooth), 1)
121    self.assertGreaterEqual(mostly_smooth[0].GetRepresentativeNumber(), 0)
122
123    mean_input_event_latency = results.FindAllPageSpecificValuesNamed(
124        'mean_input_event_latency')
125    if mean_input_event_latency:
126      self.assertEquals(len(mean_input_event_latency), 1)
127      self.assertGreater(
128          mean_input_event_latency[0].GetRepresentativeNumber(), 0)
129
130  @test.Disabled('mac', 'chromeos')  # http://crbug.com/403903
131  def testSmoothnessForPageWithNoGesture(self):
132    ps = self.CreateEmptyPageSet()
133    ps.AddPage(AnimatedPage(ps))
134
135    measurement = smoothness.Smoothness()
136    results = self.RunMeasurement(measurement, ps, options=self._options)
137    self.assertEquals(0, len(results.failures))
138
139    mostly_smooth = results.FindAllPageSpecificValuesNamed('mostly_smooth')
140    self.assertEquals(len(mostly_smooth), 1)
141    self.assertGreaterEqual(mostly_smooth[0].GetRepresentativeNumber(), 0)
142
143  def testCleanUpTrace(self):
144    self.TestTracingCleanedUp(smoothness.Smoothness, self._options)
145
146  def testCleanUpPowerMetric(self):
147    class FailPage(page.Page):
148      def __init__(self, page_set):
149        super(FailPage, self).__init__(
150            url='file://blank.html',
151            page_set=page_set, base_dir=page_set.base_dir)
152      def RunSmoothness(self, _):
153        raise exceptions.IntentionalException
154
155    class FakePowerMetric(power.PowerMetric):
156      start_called = False
157      stop_called = True
158      def Start(self, _1, _2):
159        self.start_called = True
160      def Stop(self, _1, _2):
161        self.stop_called = True
162
163    ps = self.CreateEmptyPageSet()
164    ps.AddPage(FailPage(ps))
165
166    class BuggyMeasurement(smoothness.Smoothness):
167      fake_power = None
168      # Inject fake power metric.
169      def WillStartBrowser(self, platform):
170        self.fake_power = self._power_metric = FakePowerMetric(platform)
171
172    measurement = BuggyMeasurement()
173    try:
174      self.RunMeasurement(measurement, ps)
175    except page_test.TestNotSupportedOnPlatformFailure:
176      pass
177
178    self.assertTrue(measurement.fake_power.start_called)
179    self.assertTrue(measurement.fake_power.stop_called)
180