import os
import unittest
-from telemetry import test
+from telemetry import benchmark
from telemetry.core import wpr_modes
+from telemetry.page import page as page_module
+from telemetry.page import page_set
+from telemetry.results import page_test_results
from telemetry.timeline import model as model_module
from telemetry.timeline import async_slice
-from telemetry.page import page_measurement_unittest_base
-from telemetry.page import page_set
-from telemetry.page import page as page_module
-# pylint: disable=W0401,W0614
-from telemetry.page.actions.all_page_actions import *
-from telemetry.results import page_measurement_results
from telemetry.unittest import options_for_unittests
+from telemetry.unittest import page_test_test_case
+from telemetry.value import scalar
from telemetry.web_perf import timeline_based_measurement as tbm_module
+from telemetry.web_perf import timeline_interaction_record as tir_module
from telemetry.web_perf.metrics import timeline_based_metric
-class TimelineBasedMetricsTests(unittest.TestCase):
+class FakeFastMetric(timeline_based_metric.TimelineBasedMetric):
- def setUp(self):
- model = model_module.TimelineModel()
- renderer_thread = model.GetOrCreateProcess(1).GetOrCreateThread(2)
- renderer_thread.name = 'CrRendererMain'
-
- # [ X ]
- # [ Y ]
- renderer_thread.BeginSlice('cat1', 'x.y', 10, 0)
- renderer_thread.EndSlice(20, 20)
-
- renderer_thread.async_slices.append(async_slice.AsyncSlice(
- 'cat', 'Interaction.LogicalName1/is_smooth',
- timestamp=0, duration=20,
- start_thread=renderer_thread, end_thread=renderer_thread,
- thread_start=5, thread_duration=15))
- renderer_thread.async_slices.append(async_slice.AsyncSlice(
- 'cat', 'Interaction.LogicalName2/is_responsive',
- timestamp=25, duration=5,
- start_thread=renderer_thread, end_thread=renderer_thread,
- thread_start=25, thread_duration=5))
- model.FinalizeImport()
-
- self.model = model
- self.renderer_thread = renderer_thread
+ def AddResults(self, model, renderer_thread, interaction_records, results):
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'FakeFastMetric', 'ms', 1))
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'FastMetricRecords', 'count',
+ len(interaction_records)))
- def testFindTimelineInteractionRecords(self):
- metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
- self.model, self.renderer_thread, lambda _: [])
- interactions = metric.FindTimelineInteractionRecords()
- self.assertEquals(2, len(interactions))
- self.assertTrue(interactions[0].is_smooth)
- self.assertEquals(0, interactions[0].start)
- self.assertEquals(20, interactions[0].end)
- self.assertTrue(interactions[1].is_responsive)
- self.assertEquals(25, interactions[1].start)
- self.assertEquals(30, interactions[1].end)
+class FakeSmoothMetric(timeline_based_metric.TimelineBasedMetric):
- def testAddResults(self):
- results = page_measurement_results.PageMeasurementResults()
+ def AddResults(self, model, renderer_thread, interaction_records, results):
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'FakeSmoothMetric', 'ms', 1))
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'SmoothMetricRecords', 'count',
+ len(interaction_records)))
- class FakeSmoothMetric(timeline_based_metric.TimelineBasedMetric):
- def AddResults(self, model, renderer_thread,
- interaction_records, results):
- results.Add('FakeSmoothMetric', 'ms', 1)
+class FakeLoadingMetric(timeline_based_metric.TimelineBasedMetric):
- class FakeLoadingMetric(timeline_based_metric.TimelineBasedMetric):
+ def AddResults(self, model, renderer_thread, interaction_records, results):
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'FakeLoadingMetric', 'ms', 2))
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, 'LoadingMetricRecords', 'count',
+ len(interaction_records)))
- def AddResults(self, model, renderer_thread,
- interaction_records, results):
- for r in interaction_records:
- assert r.logical_name == 'LogicalName2'
- results.Add('FakeLoadingMetric', 'ms', 2)
- def CreateMetricsForTimelineInteractionRecord(interaction):
- res = []
- if interaction.is_smooth:
- res.append(FakeSmoothMetric())
- if interaction.is_responsive:
- res.append(FakeLoadingMetric())
- return res
+def GetMetricFromMetricType(metric_type):
+ if metric_type == tir_module.IS_FAST:
+ return FakeFastMetric()
+ if metric_type == tir_module.IS_SMOOTH:
+ return FakeSmoothMetric()
+ if metric_type == tir_module.IS_RESPONSIVE:
+ return FakeLoadingMetric()
+ raise Exception('Unrecognized metric type: %s' % metric_type)
- metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
- self.model, self.renderer_thread,
- CreateMetricsForTimelineInteractionRecord)
- ps = page_set.PageSet(file_path=os.path.dirname(__file__))
- ps.AddPageWithDefaultRunNavigate('http://www.bar.com/')
- results.WillMeasurePage(ps.pages[0])
- metric.AddResults(results)
- results.DidMeasurePage()
+class TimelineBasedMetricTestData(object):
- v = results.FindAllPageSpecificValuesNamed('LogicalName1-FakeSmoothMetric')
- self.assertEquals(len(v), 1)
- v = results.FindAllPageSpecificValuesNamed('LogicalName2-FakeLoadingMetric')
- self.assertEquals(len(v), 1)
+ def __init__(self):
+ self._model = model_module.TimelineModel()
+ renderer_process = self._model.GetOrCreateProcess(1)
+ self._renderer_thread = renderer_process.GetOrCreateThread(2)
+ self._renderer_thread.name = 'CrRendererMain'
+ self._results = page_test_results.PageTestResults()
+ self._metric = None
+ self._ps = None
+
+ @property
+ def results(self):
+ return self._results
+
+ @property
+ def metric(self):
+ return self._metric
+
+ def AddInteraction(self, marker='', ts=0, duration=5):
+ self._renderer_thread.async_slices.append(async_slice.AsyncSlice(
+ 'category', marker, timestamp=ts, duration=duration,
+ start_thread=self._renderer_thread, end_thread=self._renderer_thread,
+ thread_start=ts, thread_duration=duration))
+
+ def FinalizeImport(self):
+ self._model.FinalizeImport()
+ self._metric = tbm_module._TimelineBasedMetrics( # pylint: disable=W0212
+ self._model, self._renderer_thread, GetMetricFromMetricType)
+ self._ps = page_set.PageSet(file_path=os.path.dirname(__file__))
+ self._ps.AddPageWithDefaultRunNavigate('http://www.bar.com/')
+ self._results.WillRunPage(self._ps.pages[0])
+
+ def AddResults(self):
+ self._metric.AddResults(self._results)
+ self._results.DidRunPage(self._ps.pages[0])
+
+
+class TimelineBasedMetricsTests(unittest.TestCase):
+
+ def testFindTimelineInteractionRecords(self):
+ d = TimelineBasedMetricTestData()
+ d.AddInteraction(ts=0, duration=20,
+ marker='Interaction.LogicalName1/is_smooth')
+ d.AddInteraction(ts=25, duration=5,
+ marker='Interaction.LogicalName2/is_responsive')
+ d.AddInteraction(ts=50, duration=15,
+ marker='Interaction.LogicalName3/is_fast')
+ d.FinalizeImport()
+ interactions = d.metric.FindTimelineInteractionRecords()
+ self.assertEquals(3, len(interactions))
+ self.assertTrue(interactions[0].is_smooth)
+ self.assertEquals(0, interactions[0].start)
+ self.assertEquals(20, interactions[0].end)
+
+ self.assertTrue(interactions[1].is_responsive)
+ self.assertEquals(25, interactions[1].start)
+ self.assertEquals(30, interactions[1].end)
+
+ self.assertTrue(interactions[2].is_fast)
+ self.assertEquals(50, interactions[2].start)
+ self.assertEquals(65, interactions[2].end)
+
+ def testAddResults(self):
+ d = TimelineBasedMetricTestData()
+ d.AddInteraction(ts=0, duration=20,
+ marker='Interaction.LogicalName1/is_smooth')
+ d.AddInteraction(ts=25, duration=5,
+ marker='Interaction.LogicalName2/is_responsive')
+ d.AddInteraction(ts=50, duration=15,
+ marker='Interaction.LogicalName3/is_fast')
+ d.FinalizeImport()
+ d.AddResults()
+ self.assertEquals(1, len(d.results.FindAllPageSpecificValuesNamed(
+ 'LogicalName1-FakeSmoothMetric')))
+ self.assertEquals(1, len(d.results.FindAllPageSpecificValuesNamed(
+ 'LogicalName2-FakeLoadingMetric')))
+ self.assertEquals(1, len(d.results.FindAllPageSpecificValuesNamed(
+ 'LogicalName3-FakeFastMetric')))
+
+ def testNoInteractions(self):
+ d = TimelineBasedMetricTestData()
+ d.FinalizeImport()
+ self.assertRaises(tbm_module.InvalidInteractions, d.AddResults)
+
+ def testDuplicateUnrepeatableInteractions(self):
+ d = TimelineBasedMetricTestData()
+ d.AddInteraction(ts=10, duration=5,
+ marker='Interaction.LogicalName/is_smooth')
+ d.AddInteraction(ts=20, duration=5,
+ marker='Interaction.LogicalName/is_smooth')
+ d.FinalizeImport()
+ self.assertRaises(tbm_module.InvalidInteractions, d.AddResults)
+
+ def testDuplicateRepeatableInteractions(self):
+ d = TimelineBasedMetricTestData()
+ d.AddInteraction(ts=10, duration=5,
+ marker='Interaction.LogicalName/is_smooth,repeatable')
+ d.AddInteraction(ts=20, duration=5,
+ marker='Interaction.LogicalName/is_smooth,repeatable')
+ d.FinalizeImport()
+ d.AddResults()
+ self.assertEquals(1, len(d.results.pages_that_succeeded))
+
+ def testDuplicateRepeatableInteractionsWithDifferentMetrics(self):
+ d = TimelineBasedMetricTestData()
+
+ responsive_marker = 'Interaction.LogicalName/is_responsive,repeatable'
+ d.AddInteraction(ts=10, duration=5, marker=responsive_marker)
+ smooth_marker = 'Interaction.LogicalName/is_smooth,repeatable'
+ d.AddInteraction(ts=20, duration=5, marker=smooth_marker)
+ d.FinalizeImport()
+ self.assertRaises(tbm_module.InvalidInteractions, d.AddResults)
class TestTimelinebasedMeasurementPage(page_module.Page):
- def __init__(self, ps, base_dir):
+ def __init__(self, ps, base_dir, trigger_animation=False,
+ trigger_jank=False):
super(TestTimelinebasedMeasurementPage, self).__init__(
'file://interaction_enabled_page.html', ps, base_dir)
+ self._trigger_animation = trigger_animation
+ self._trigger_jank = trigger_jank
def RunSmoothness(self, action_runner):
- action_runner.Wait(2)
- action_runner.TapElement('#drawer')
- action_runner.Wait(1)
+ if self._trigger_animation:
+ action_runner.TapElement('#animating-button')
+ action_runner.WaitForJavaScriptCondition('window.animationDone')
+ if self._trigger_jank:
+ action_runner.TapElement('#jank-button')
+ action_runner.WaitForJavaScriptCondition('window.jankScriptDone')
-class TimelineBasedMeasurementTest(
- page_measurement_unittest_base.PageMeasurementUnitTestBase):
+class TimelineBasedMeasurementTest(page_test_test_case.PageTestTestCase):
def setUp(self):
self._options = options_for_unittests.GetCopy()
self._options.browser_options.wpr_mode = wpr_modes.WPR_OFF
- # Disabled due to flakiness: crbug.com/368386
- @test.Disabled
def testSmoothnessTimelineBasedMeasurementForSmoke(self):
- ps = self.CreatePageSetFromFileInUnittestDataDir(
- 'interaction_enabled_page.html')
- setattr(ps.pages[0], 'RunSmoothness', {
- 'action': 'wait', 'javascript': 'window.animationDone'})
+ ps = self.CreateEmptyPageSet()
+ ps.AddPage(TestTimelinebasedMeasurementPage(
+ ps, ps.base_dir, trigger_animation=True))
+
measurement = tbm_module.TimelineBasedMeasurement()
results = self.RunMeasurement(measurement, ps,
options=self._options)
+
self.assertEquals(0, len(results.failures))
v = results.FindAllPageSpecificValuesNamed('CenterAnimation-jank')
self.assertEquals(len(v), 1)
self.assertEquals(len(v), 1)
# Disabled since mainthread_jank metric is not supported on windows platform.
- @test.Disabled('win')
+ @benchmark.Disabled('win')
def testMainthreadJankTimelineBasedMeasurement(self):
ps = self.CreateEmptyPageSet()
- ps.AddPage(TestTimelinebasedMeasurementPage(ps, ps.base_dir))
+ ps.AddPage(TestTimelinebasedMeasurementPage(
+ ps, ps.base_dir, trigger_jank=True))
measurement = tbm_module.TimelineBasedMeasurement()
results = self.RunMeasurement(measurement, ps,