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    if app:
64      try:
65        self._is_valid_dump, trace_output = app.GetStackTrace()
66        self._stack_trace = trace_output.splitlines()
67        self._minidump_path = app.GetMostRecentMinidumpPath()
68      except Exception as err:
69        logging.error('Problem when trying to gather stack trace: %s' % err)
70      try:
71        self._app_stdout = app.GetStandardOutput().splitlines()
72      except Exception as err:
73        logging.error('Problem when trying to gather standard output: %s' % err)
74
75  @property
76  def stack_trace(self):
77    return self._stack_trace
78
79  @property
80  def minidump_path(self):
81    return self._minidump_path
82
83  @property
84  def is_valid_dump(self):
85    return self._is_valid_dump
86
87  def __str__(self):
88    divider = '*' * 80
89    debug_messages = []
90    debug_messages.append(super(AppCrashException, self).__str__())
91    debug_messages.append('Found Minidump: %s' % self._is_valid_dump)
92    debug_messages.append('Stack Trace:')
93    debug_messages.append(divider)
94    debug_messages.extend(('\t%s' % l) for l in self._stack_trace)
95    debug_messages.append(divider)
96    debug_messages.append('Standard output:')
97    debug_messages.append(divider)
98    debug_messages.extend(('\t%s' % l) for l in self._app_stdout)
99    debug_messages.append(divider)
100    return '\n'.join(debug_messages)
101
102class DevtoolsTargetCrashException(AppCrashException):
103  """Represents a crash of the current devtools target but not the overall app.
104
105  This can be a tab or a WebView. In this state, the tab/WebView is
106  gone, but the underlying browser is still alive.
107  """
108
109  def __init__(self, app, msg='Devtools target crashed'):
110    super(DevtoolsTargetCrashException, self).__init__(app, msg)
111
112
113class BrowserGoneException(AppCrashException):
114  """Represents a crash of the entire browser.
115
116  In this state, all bets are pretty much off."""
117
118  def __init__(self, app, msg='Browser crashed'):
119    super(BrowserGoneException, self).__init__(app, msg)
120
121
122class BrowserConnectionGoneException(BrowserGoneException):
123  """Represents a browser that still exists but cannot be reached."""
124
125  def __init__(self, app, msg='Browser exists but the connection is gone'):
126    super(BrowserConnectionGoneException, self).__init__(app, msg)
127
128
129class ProcessGoneException(Error):
130  """Represents a process that no longer exists for an unknown reason."""
131
132
133class IntentionalException(Error):
134  """Represent an exception raised by a unittest which is not printed."""
135
136
137class InitializationError(Error):
138
139  def __init__(self, string):
140    super(InitializationError, self).__init__(string)
141
142
143class LoginException(Error):
144  pass
145
146
147class EvaluateException(Error):
148  pass
149
150
151class ProfilingException(Error):
152  pass
153
154
155class PathMissingError(Error):
156  """ Represents an exception thrown when an expected path doesn't exist. """
157
158
159class UnknownPackageError(Error):
160  """ Represents an exception when encountering an unsupported Android APK. """
161
162
163class PackageDetectionError(Error):
164  """ Represents an error when parsing an Android APK's package. """
165
166
167class AndroidDeviceParsingError(Error):
168  """Represents an error when parsing output from an android device"""
169