1# Copyright 2016 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.
4
5from page_sets.system_health import platforms
6from page_sets.system_health import story_tags
7
8from telemetry.page import page
9from telemetry.page import shared_page_state
10from telemetry.util import wpr_modes
11
12
13# Extra wait time after the page has loaded required by the loading metric. We
14# use it in all benchmarks to avoid divergence between benchmarks.
15# TODO(petrcermak): Switch the memory benchmarks to use it as well.
16_WAIT_TIME_AFTER_LOAD = 10
17
18
19class _SystemHealthSharedState(shared_page_state.SharedPageState):
20  """Shared state which enables disabling stories on individual platforms.
21     This should be used only to disable the stories permanently. For
22     disabling stories temporarily use story expectations in ./expectations.py.
23  """
24
25  def CanRunOnBrowser(self, browser_info, story):
26    if (browser_info.browser_type.startswith('android-webview') and
27        story.WEBVIEW_NOT_SUPPORTED):
28      return False
29
30    if story.TAGS and story_tags.WEBGL in story.TAGS:
31      return browser_info.HasWebGLSupport()
32    return True
33
34
35class _MetaSystemHealthStory(type):
36  """Metaclass for SystemHealthStory."""
37
38  @property
39  def ABSTRACT_STORY(cls):
40    """Class field marking whether the class is abstract.
41
42    If true, the story will NOT be instantiated and added to a System Health
43    story set. This field is NOT inherited by subclasses (that's why it's
44    defined on the metaclass).
45    """
46    return cls.__dict__.get('ABSTRACT_STORY', False)
47
48
49class SystemHealthStory(page.Page):
50  """Abstract base class for System Health user stories."""
51  __metaclass__ = _MetaSystemHealthStory
52
53  # The full name of a single page story has the form CASE:GROUP:PAGE:[VERSION]
54  # (e.g. 'load:search:google' or 'load:search:google:2018').
55  NAME = NotImplemented
56  URL = NotImplemented
57  ABSTRACT_STORY = True
58  # Skip the login flow in replay mode
59  # If you want to replay the login flow in your story, set SKIP_LOGIN to False
60  SKIP_LOGIN = True
61  SUPPORTED_PLATFORMS = platforms.ALL_PLATFORMS
62  TAGS = []
63  PLATFORM_SPECIFIC = False
64  WEBVIEW_NOT_SUPPORTED = False
65
66  def __init__(self, story_set, take_memory_measurement,
67      extra_browser_args=None):
68    case, group, _ = self.NAME.split(':', 2)
69    tags = []
70    found_year_tag = False
71    for t in self.TAGS:  # pylint: disable=not-an-iterable
72      assert t in story_tags.ALL_TAGS
73      tags.append(t.name)
74      if t in story_tags.YEAR_TAGS:
75        # Assert that this is the first year tag.
76        assert not found_year_tag, (
77            "%s has more than one year tag found." % self.__class__.__name__)
78        found_year_tag = True
79    # Assert that there is one year tag.
80    assert found_year_tag, (
81        "%s needs exactly one year tag." % self.__class__.__name__)
82    super(SystemHealthStory, self).__init__(
83        shared_page_state_class=_SystemHealthSharedState,
84        page_set=story_set, name=self.NAME, url=self.URL, tags=tags,
85        grouping_keys={'case': case, 'group': group},
86        platform_specific=self.PLATFORM_SPECIFIC,
87        extra_browser_args=extra_browser_args)
88    self._take_memory_measurement = take_memory_measurement
89
90  @classmethod
91  def GetStoryDescription(cls):
92    if cls.__doc__:
93      return cls.__doc__
94    return cls.GenerateStoryDescription()
95
96  @classmethod
97  def GenerateStoryDescription(cls):
98    """ Subclasses of SystemHealthStory can override this to auto generate
99    their story description.
100    However, it's recommended to use the Python docstring to describe the user
101    stories instead and this should only be used for very repetitive cases.
102    """
103    return None
104
105  def _Measure(self, action_runner):
106    if self._take_memory_measurement:
107      action_runner.MeasureMemory(deterministic_mode=True)
108    else:
109      action_runner.Wait(_WAIT_TIME_AFTER_LOAD)
110
111  def _Login(self, action_runner):
112    pass
113
114  def _DidLoadDocument(self, action_runner):
115    pass
116
117  def RunNavigateSteps(self, action_runner):
118    if not (self.SKIP_LOGIN and self.wpr_mode == wpr_modes.WPR_REPLAY):
119      self._Login(action_runner)
120    super(SystemHealthStory, self).RunNavigateSteps(action_runner)
121
122  def RunPageInteractions(self, action_runner):
123    action_runner.tab.WaitForDocumentReadyStateToBeComplete()
124    self._DidLoadDocument(action_runner)
125    self._Measure(action_runner)
126
127