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 logging
5import sys
6
7
8class Error(Exception):
9  """Base class for Telemetry exceptions."""
10
11  def __init__(self, msg=''):
12    super(Error, self).__init__(msg)
13    self._debugging_messages = []
14
15  def AddDebuggingMessage(self, msg):
16    """Adds a message to the description of the exception.
17
18    Many Telemetry exceptions arise from failures in another application. These
19    failures are difficult to pinpoint. This method allows Telemetry classes to
20    append useful debugging information to the exception. This method also logs
21    information about the location from where it was called.
22    """
23    frame = sys._getframe(1)
24    line_number = frame.f_lineno
25    file_name = frame.f_code.co_filename
26    function_name = frame.f_code.co_name
27    call_site = '%s:%s %s' % (file_name, line_number, function_name)
28    annotated_message = '(%s) %s' % (call_site, msg)
29
30    self._debugging_messages.append(annotated_message)
31
32  def __str__(self):
33    divider = '\n' + '*' * 80 + '\n'
34    output = super(Error, self).__str__()
35    for message in self._debugging_messages:
36      output += divider
37      output += message
38    return output
39
40
41class PlatformError(Error):
42  """ Represents an exception thrown when constructing platform. """
43
44
45class TimeoutException(Error):
46  """The operation failed to complete because of a timeout.
47
48  It is possible that waiting for a longer period of time would result in a
49  successful operation.
50  """
51  pass
52
53
54class AppCrashException(Error):
55
56  def __init__(self, app=None, msg=''):
57    super(AppCrashException, self).__init__(msg)
58    self._msg = msg
59    self._is_valid_dump = False
60    self._stack_trace = []
61    self._app_stdout = []
62    self._system_log = '(Not implemented)'
63
64    if app:
65      debug_data = app.CollectDebugData(logging.ERROR)
66      self._system_log = debug_data.system_log or self._system_log
67      self._app_stdout = debug_data.stdout.splitlines()
68      self._is_valid_dump = bool(debug_data.symbolized_minidumps)
69      self._stack_trace = '\n'.join(
70          debug_data.symbolized_minidumps).splitlines()
71
72  @property
73  def stack_trace(self):
74    return self._stack_trace
75
76  @property
77  def is_valid_dump(self):
78    return self._is_valid_dump
79
80  def __str__(self):
81    divider = '*' * 80
82    debug_messages = []
83    debug_messages.append(super(AppCrashException, self).__str__())
84    debug_messages.append('Found Minidump: %s' % self._is_valid_dump)
85    debug_messages.append('Stack Trace:')
86    debug_messages.append(divider)
87    if self.is_valid_dump:
88      # CollectDebugData will handle this already.
89      debug_messages.append('Stack trace(s) already output above.')
90    else:
91      debug_messages.append('Unable to get stack trace.')
92    debug_messages.append(divider)
93    debug_messages.append('Standard output:')
94    debug_messages.append(divider)
95    debug_messages.extend(('\t%s' % l) for l in self._app_stdout)
96    debug_messages.append(divider)
97    debug_messages.append('System log:')
98    debug_messages.append(self._system_log)
99    return '\n'.join(debug_messages)
100
101class DevtoolsTargetCrashException(AppCrashException):
102  """Represents a crash of the current devtools target but not the overall app.
103
104  This can be a tab or a WebView. In this state, the tab/WebView is
105  gone, but the underlying browser is still alive.
106  """
107
108  def __init__(self, app, msg='Devtools target crashed'):
109    super(DevtoolsTargetCrashException, self).__init__(app, msg)
110
111class DevtoolsTargetClosedException(Error):
112  """Represents an error when Devtools target navigated or closed.
113  """
114
115class BrowserGoneException(AppCrashException):
116  """Represents a crash of the entire browser.
117
118  In this state, all bets are pretty much off."""
119
120  def __init__(self, app, msg='Browser crashed'):
121    super(BrowserGoneException, self).__init__(app, msg)
122
123
124class BrowserConnectionGoneException(BrowserGoneException):
125  """Represents a browser that still exists but cannot be reached."""
126
127  def __init__(self, app, msg='Browser exists but the connection is gone'):
128    super(BrowserConnectionGoneException, self).__init__(app, msg)
129
130
131class TabMissingError(Error):
132  """Represents an error when an expected browser tab is not found."""
133
134
135class ProcessGoneException(Error):
136  """Represents a process that no longer exists for an unknown reason."""
137
138
139class IntentionalException(Error):
140  """Represent an exception raised by a unittest which is not printed."""
141
142
143class InitializationError(Error):
144
145  def __init__(self, string):
146    super(InitializationError, self).__init__(string)
147
148
149class LoginException(Error):
150  pass
151
152
153class EvaluateException(Error):
154  def __init__(self, text='', class_name='', description=None):
155    super(EvaluateException, self).__init__(text)
156    self._class_name = class_name
157    self._description = description
158
159  def __str__(self):
160    output = super(EvaluateException, self).__str__()
161    if self._class_name and self._description:
162      output += '%s:\n%s' % (self._class_name, self._description)
163    return output
164
165
166class StoryActionError(Error):
167  """Represents an error when trying to perform an action on a story."""
168
169
170class TracingException(Error):
171  """Represents an error that ocurred while collecting or flushing traces."""
172
173
174class AtraceTracingError(TracingException):
175  """Represents an error that ocurred while collecting traces with Atrace."""
176
177
178class PathMissingError(Error):
179  """Represents an exception thrown when an expected path doesn't exist."""
180
181
182class UnknownPackageError(Error):
183  """Represents an exception when encountering an unsupported Android APK."""
184
185
186class PackageDetectionError(Error):
187  """Represents an error when parsing an Android APK's package."""
188
189
190class AndroidDeviceParsingError(Error):
191  """Represents an error when parsing output from an android device."""
192