page_action.py revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1# Copyright (c) 2012 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
5
6import telemetry.core.timeline.bounds as timeline_bounds
7from telemetry.page.actions import wait_until
8
9class PageActionNotSupported(Exception):
10  pass
11
12class PageActionFailed(Exception):
13  pass
14
15class PageActionInvalidTimelineMarker(Exception):
16  pass
17
18class PageAction(object):
19  """Represents an action that a user might try to perform to a page."""
20  _next_timeline_marker_id = 0
21
22  def __init__(self, attributes=None):
23    if attributes:
24      for k, v in attributes.iteritems():
25        setattr(self, k, v)
26    self._timeline_marker_base_name = None
27    self._timeline_marker_id = None
28    if hasattr(self, 'wait_until'):
29      self.wait_until = wait_until.WaitUntil(self, self.wait_until)
30    else:
31      self.wait_until = None
32
33  def CustomizeBrowserOptionsForPageSet(self, options):
34    """Override to add action-specific options to the BrowserOptions
35    object. These options will be set for the whole page set.
36
37    If the browser is not being restarted for every page in the page set then
38    all browser options required for the action must be set here. This, however,
39    requires that they do not conflict with options require by other actions
40    used up by the page set.
41    """
42    pass
43
44  def WillRunAction(self, page, tab):
45    """Override to do action-specific setup before
46    Test.WillRunAction is called."""
47    pass
48
49  def WillWaitAfterRun(self):
50    return self.wait_until is not None
51
52  def RunActionAndMaybeWait(self, page, tab):
53    if self.wait_until:
54      self.wait_until.RunActionAndWait(page, tab)
55    else:
56      self.RunAction(page, tab)
57
58  def RunAction(self, page, tab):
59    raise NotImplementedError()
60
61  def CleanUp(self, page, tab):
62    pass
63
64  def CanBeBound(self):
65    """If this class implements BindMeasurementJavaScript, override CanBeBound
66    to return True so that a test knows it can bind measurements."""
67    return False
68
69  def BindMeasurementJavaScript(
70      self, tab, start_js, stop_js):  # pylint: disable=W0613
71    """Let this action determine when measurements should start and stop.
72
73    A measurement can call this method to provide the action
74    with JavaScript code that starts and stops measurements. The action
75    determines when to execute the provided JavaScript code, for more accurate
76    timings.
77
78    Args:
79      tab: The tab to do everything on.
80      start_js: JavaScript code that starts measurements.
81      stop_js: JavaScript code that stops measurements.
82    """
83    raise Exception('This action cannot be bound.')
84
85  @staticmethod
86  def ResetNextTimelineMarkerId():
87    PageAction._next_timeline_marker_id = 0
88
89  def _SetTimelineMarkerBaseName(self, name):
90    self._timeline_marker_base_name = name
91    self._timeline_marker_id = PageAction._next_timeline_marker_id
92    PageAction._next_timeline_marker_id += 1
93
94  def _GetUniqueTimelineMarkerName(self):
95    if self._timeline_marker_base_name:
96      return \
97        '%s_%d' % (self._timeline_marker_base_name, self._timeline_marker_id)
98    else:
99      return None
100
101  def GetActiveRangeOnTimeline(self, timeline):
102    active_range = timeline_bounds.Bounds()
103
104    if self._GetUniqueTimelineMarkerName():
105      active_range.AddEvent(
106          timeline.GetEventOfName(self._GetUniqueTimelineMarkerName(),
107                                  True, True))
108    if self.wait_until:
109      active_range.AddBounds(
110          self.wait_until.GetActiveRangeOnTimeline(timeline))
111
112    return active_range
113