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._minidump_path = ''
63    self._system_log = '(Not implemented)'
64    if app:
65      try:
66        system_log = app.platform.GetSystemLog()
67        if system_log:
68          self._system_log = system_log
69        self._is_valid_dump, trace_output = app.GetStackTrace()
70        self._stack_trace = trace_output.splitlines()
71        self._minidump_path = app.GetMostRecentMinidumpPath()
72      except Exception as err:
73        logging.error('Problem when trying to gather stack trace: %s' % err)
74      try:
75        self._app_stdout = app.GetStandardOutput().splitlines()
76      except Exception as err:
77        logging.error('Problem when trying to gather standard output: %s' % err)
78
79  @property
80  def stack_trace(self):
81    return self._stack_trace
82
83  @property
84  def minidump_path(self):
85    return self._minidump_path
86
87  @property
88  def is_valid_dump(self):
89    return self._is_valid_dump
90
91  def __str__(self):
92    divider = '*' * 80
93    debug_messages = []
94    debug_messages.append(super(AppCrashException, self).__str__())
95    debug_messages.append('Found Minidump: %s' % self._is_valid_dump)
96    debug_messages.append('Stack Trace:')
97    debug_messages.append(divider)
98    debug_messages.extend(('\t%s' % l) for l in self._stack_trace)
99    debug_messages.append(divider)
100    debug_messages.append('Standard output:')
101    debug_messages.append(divider)
102    debug_messages.extend(('\t%s' % l) for l in self._app_stdout)
103    debug_messages.append(divider)
104    debug_messages.append('System log:')
105    debug_messages.append(self._system_log)
106    return '\n'.join(debug_messages)
107
108class DevtoolsTargetCrashException(AppCrashException):
109  """Represents a crash of the current devtools target but not the overall app.
110
111  This can be a tab or a WebView. In this state, the tab/WebView is
112  gone, but the underlying browser is still alive.
113  """
114
115  def __init__(self, app, msg='Devtools target crashed'):
116    super(DevtoolsTargetCrashException, self).__init__(app, msg)
117
118
119class BrowserGoneException(AppCrashException):
120  """Represents a crash of the entire browser.
121
122  In this state, all bets are pretty much off."""
123
124  def __init__(self, app, msg='Browser crashed'):
125    super(BrowserGoneException, self).__init__(app, msg)
126
127
128class BrowserConnectionGoneException(BrowserGoneException):
129  """Represents a browser that still exists but cannot be reached."""
130
131  def __init__(self, app, msg='Browser exists but the connection is gone'):
132    super(BrowserConnectionGoneException, self).__init__(app, msg)
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 ProfilingException(Error):
167  pass
168
169
170class PathMissingError(Error):
171  """ Represents an exception thrown when an expected path doesn't exist. """
172
173
174class UnknownPackageError(Error):
175  """ Represents an exception when encountering an unsupported Android APK. """
176
177
178class PackageDetectionError(Error):
179  """ Represents an error when parsing an Android APK's package. """
180
181
182class AndroidDeviceParsingError(Error):
183  """Represents an error when parsing output from an android device"""
184