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