| Index: tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_backend.py
|
| diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_backend.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_backend.py
|
| deleted file mode 100644
|
| index 194db0be2a7c8af90345c2fb517d4a7b8920649f..0000000000000000000000000000000000000000
|
| --- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/inspector_backend.py
|
| +++ /dev/null
|
| @@ -1,349 +0,0 @@
|
| -# Copyright 2013 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -import functools
|
| -import logging
|
| -import os
|
| -import socket
|
| -import sys
|
| -
|
| -from telemetry.core import exceptions
|
| -from telemetry import decorators
|
| -from telemetry.internal.backends.chrome_inspector import devtools_http
|
| -from telemetry.internal.backends.chrome_inspector import inspector_console
|
| -from telemetry.internal.backends.chrome_inspector import inspector_memory
|
| -from telemetry.internal.backends.chrome_inspector import inspector_page
|
| -from telemetry.internal.backends.chrome_inspector import inspector_runtime
|
| -from telemetry.internal.backends.chrome_inspector import inspector_websocket
|
| -from telemetry.internal.backends.chrome_inspector import websocket
|
| -
|
| -
|
| -def _HandleInspectorWebSocketExceptions(func):
|
| - """Decorator for converting inspector_websocket exceptions.
|
| -
|
| - When an inspector_websocket exception is thrown in the original function,
|
| - this decorator converts it into a telemetry exception and adds debugging
|
| - information.
|
| - """
|
| - @functools.wraps(func)
|
| - def inner(inspector_backend, *args, **kwargs):
|
| - try:
|
| - return func(inspector_backend, *args, **kwargs)
|
| - except (socket.error, websocket.WebSocketException,
|
| - inspector_websocket.WebSocketDisconnected) as e:
|
| - inspector_backend._ConvertExceptionFromInspectorWebsocket(e)
|
| -
|
| - return inner
|
| -
|
| -
|
| -class InspectorBackend(object):
|
| - """Class for communicating with a devtools client.
|
| -
|
| - The owner of an instance of this class is responsible for calling
|
| - Disconnect() before disposing of the instance.
|
| - """
|
| - def __init__(self, app, devtools_client, context, timeout=60):
|
| - self._websocket = inspector_websocket.InspectorWebsocket()
|
| - self._websocket.RegisterDomain(
|
| - 'Inspector', self._HandleInspectorDomainNotification)
|
| -
|
| - self._app = app
|
| - self._devtools_client = devtools_client
|
| - # Be careful when using the context object, since the data may be
|
| - # outdated since this is never updated once InspectorBackend is
|
| - # created. Consider an updating strategy for this. (For an example
|
| - # of the subtlety, see the logic for self.url property.)
|
| - self._context = context
|
| -
|
| - logging.debug('InspectorBackend._Connect() to %s', self.debugger_url)
|
| - try:
|
| - self._websocket.Connect(self.debugger_url)
|
| - except (websocket.WebSocketException, exceptions.TimeoutException) as e:
|
| - self._ConvertExceptionFromInspectorWebsocket(e)
|
| -
|
| - self._console = inspector_console.InspectorConsole(self._websocket)
|
| - self._memory = inspector_memory.InspectorMemory(self._websocket)
|
| - self._page = inspector_page.InspectorPage(
|
| - self._websocket, timeout=timeout)
|
| - self._runtime = inspector_runtime.InspectorRuntime(self._websocket)
|
| -
|
| - def Disconnect(self):
|
| - """Disconnects the inspector websocket.
|
| -
|
| - This method intentionally leaves the self._websocket object around, so that
|
| - future calls it to it will fail with a relevant error.
|
| - """
|
| - if self._websocket:
|
| - self._websocket.Disconnect()
|
| -
|
| - def __del__(self):
|
| - self.Disconnect()
|
| -
|
| - @property
|
| - def app(self):
|
| - return self._app
|
| -
|
| - @property
|
| - def url(self):
|
| - """Returns the URL of the tab, as reported by devtools.
|
| -
|
| - Raises:
|
| - devtools_http.DevToolsClientConnectionError
|
| - """
|
| - return self._devtools_client.GetUrl(self.id)
|
| -
|
| - @property
|
| - def id(self):
|
| - return self._context['id']
|
| -
|
| - @property
|
| - def debugger_url(self):
|
| - return self._context['webSocketDebuggerUrl']
|
| -
|
| - def GetWebviewInspectorBackends(self):
|
| - """Returns a list of InspectorBackend instances associated with webviews.
|
| -
|
| - Raises:
|
| - devtools_http.DevToolsClientConnectionError
|
| - """
|
| - inspector_backends = []
|
| - devtools_context_map = self._devtools_client.GetUpdatedInspectableContexts()
|
| - for context in devtools_context_map.contexts:
|
| - if context['type'] == 'webview':
|
| - inspector_backends.append(
|
| - devtools_context_map.GetInspectorBackend(context['id']))
|
| - return inspector_backends
|
| -
|
| - def IsInspectable(self):
|
| - """Whether the tab is inspectable, as reported by devtools."""
|
| - try:
|
| - return self._devtools_client.IsInspectable(self.id)
|
| - except devtools_http.DevToolsClientConnectionError:
|
| - return False
|
| -
|
| - # Public methods implemented in JavaScript.
|
| -
|
| - @property
|
| - @decorators.Cache
|
| - def screenshot_supported(self):
|
| - if (self.app.platform.GetOSName() == 'linux' and (
|
| - os.getenv('DISPLAY') not in [':0', ':0.0'])):
|
| - # Displays other than 0 mean we are likely running in something like
|
| - # xvfb where screenshotting doesn't work.
|
| - return False
|
| - return True
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def Screenshot(self, timeout):
|
| - assert self.screenshot_supported, 'Browser does not support screenshotting'
|
| - return self._page.CaptureScreenshot(timeout)
|
| -
|
| - # Console public methods.
|
| -
|
| - @property
|
| - def message_output_stream(self):
|
| - return self._console.message_output_stream
|
| -
|
| - @message_output_stream.setter
|
| - def message_output_stream(self, stream):
|
| - self._console.message_output_stream = stream
|
| -
|
| - # Memory public methods.
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def GetDOMStats(self, timeout):
|
| - """Gets memory stats from the DOM.
|
| -
|
| - Raises:
|
| - inspector_memory.InspectorMemoryException
|
| - exceptions.TimeoutException
|
| - exceptions.DevtoolsTargetCrashException
|
| - """
|
| - dom_counters = self._memory.GetDOMCounters(timeout)
|
| - return {
|
| - 'document_count': dom_counters['documents'],
|
| - 'node_count': dom_counters['nodes'],
|
| - 'event_listener_count': dom_counters['jsEventListeners']
|
| - }
|
| -
|
| - # Page public methods.
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def WaitForNavigate(self, timeout):
|
| - self._page.WaitForNavigate(timeout)
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def Navigate(self, url, script_to_evaluate_on_commit, timeout):
|
| - self._page.Navigate(url, script_to_evaluate_on_commit, timeout)
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def GetCookieByName(self, name, timeout):
|
| - return self._page.GetCookieByName(name, timeout)
|
| -
|
| - # Runtime public methods.
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def ExecuteJavaScript(self, expr, context_id=None, timeout=60):
|
| - """Executes a javascript expression without returning the result.
|
| -
|
| - Raises:
|
| - exceptions.EvaluateException
|
| - exceptions.WebSocketDisconnected
|
| - exceptions.TimeoutException
|
| - exceptions.DevtoolsTargetCrashException
|
| - """
|
| - self._runtime.Execute(expr, context_id, timeout)
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def EvaluateJavaScript(self, expr, context_id=None, timeout=60):
|
| - """Evaluates a javascript expression and returns the result.
|
| -
|
| - Raises:
|
| - exceptions.EvaluateException
|
| - exceptions.WebSocketDisconnected
|
| - exceptions.TimeoutException
|
| - exceptions.DevtoolsTargetCrashException
|
| - """
|
| - return self._runtime.Evaluate(expr, context_id, timeout)
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def EnableAllContexts(self):
|
| - """Allows access to iframes.
|
| -
|
| - Raises:
|
| - exceptions.WebSocketDisconnected
|
| - exceptions.TimeoutException
|
| - exceptions.DevtoolsTargetCrashException
|
| - """
|
| - return self._runtime.EnableAllContexts()
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def SynthesizeScrollGesture(self, x=100, y=800, xDistance=0, yDistance=-500,
|
| - xOverscroll=None, yOverscroll=None,
|
| - preventFling=True, speed=None,
|
| - gestureSourceType=None, repeatCount=None,
|
| - repeatDelayMs=None, interactionMarkerName=None,
|
| - timeout=60):
|
| - """Runs an inspector command that causes a repeatable browser driven scroll.
|
| -
|
| - Args:
|
| - x: X coordinate of the start of the gesture in CSS pixels.
|
| - y: Y coordinate of the start of the gesture in CSS pixels.
|
| - xDistance: Distance to scroll along the X axis (positive to scroll left).
|
| - yDistance: Distance to scroll along the Y axis (positive to scroll up).
|
| - xOverscroll: Number of additional pixels to scroll back along the X axis.
|
| - xOverscroll: Number of additional pixels to scroll back along the Y axis.
|
| - preventFling: Prevents a fling gesture.
|
| - speed: Swipe speed in pixels per second.
|
| - gestureSourceType: Which type of input events to be generated.
|
| - repeatCount: Number of additional repeats beyond the first scroll.
|
| - repeatDelayMs: Number of milliseconds delay between each repeat.
|
| - interactionMarkerName: The name of the interaction markers to generate.
|
| -
|
| - Raises:
|
| - exceptions.TimeoutException
|
| - exceptions.DevtoolsTargetCrashException
|
| - """
|
| - params = {
|
| - 'x': x,
|
| - 'y': y,
|
| - 'xDistance': xDistance,
|
| - 'yDistance': yDistance,
|
| - 'preventFling': preventFling,
|
| - }
|
| -
|
| - if xOverscroll is not None:
|
| - params['xOverscroll'] = xOverscroll
|
| -
|
| - if yOverscroll is not None:
|
| - params['yOverscroll'] = yOverscroll
|
| -
|
| - if speed is not None:
|
| - params['speed'] = speed
|
| -
|
| - if repeatCount is not None:
|
| - params['repeatCount'] = repeatCount
|
| -
|
| - if gestureSourceType is not None:
|
| - params['gestureSourceType'] = gestureSourceType
|
| -
|
| - if repeatDelayMs is not None:
|
| - params['repeatDelayMs'] = repeatDelayMs
|
| -
|
| - if interactionMarkerName is not None:
|
| - params['interactionMarkerName'] = interactionMarkerName
|
| -
|
| - scroll_command = {
|
| - 'method': 'Input.synthesizeScrollGesture',
|
| - 'params': params
|
| - }
|
| - return self._runtime.RunInspectorCommand(scroll_command, timeout)
|
| -
|
| - # Methods used internally by other backends.
|
| -
|
| - def _HandleInspectorDomainNotification(self, res):
|
| - if (res['method'] == 'Inspector.detached' and
|
| - res.get('params', {}).get('reason', '') == 'replaced_with_devtools'):
|
| - self._WaitForInspectorToGoAway()
|
| - return
|
| - if res['method'] == 'Inspector.targetCrashed':
|
| - exception = exceptions.DevtoolsTargetCrashException(self.app)
|
| - self._AddDebuggingInformation(exception)
|
| - raise exception
|
| -
|
| - def _WaitForInspectorToGoAway(self):
|
| - self._websocket.Disconnect()
|
| - raw_input('The connection to Chrome was lost to the inspector ui.\n'
|
| - 'Please close the inspector and press enter to resume '
|
| - 'Telemetry run...')
|
| - raise exceptions.DevtoolsTargetCrashException(
|
| - self.app, 'Devtool connection with the browser was interrupted due to '
|
| - 'the opening of an inspector.')
|
| -
|
| - def _ConvertExceptionFromInspectorWebsocket(self, error):
|
| - """Converts an Exception from inspector_websocket.
|
| -
|
| - This method always raises a Telemetry exception. It appends debugging
|
| - information. The exact exception raised depends on |error|.
|
| -
|
| - Args:
|
| - error: An instance of socket.error or websocket.WebSocketException.
|
| - Raises:
|
| - exceptions.TimeoutException: A timeout occurred.
|
| - exceptions.DevtoolsTargetCrashException: On any other error, the most
|
| - likely explanation is that the devtool's target crashed.
|
| - """
|
| - if isinstance(error, websocket.WebSocketTimeoutException):
|
| - new_error = exceptions.TimeoutException()
|
| - else:
|
| - new_error = exceptions.DevtoolsTargetCrashException(self.app)
|
| -
|
| - original_error_msg = 'Original exception:\n' + str(error)
|
| - new_error.AddDebuggingMessage(original_error_msg)
|
| - self._AddDebuggingInformation(new_error)
|
| -
|
| - raise new_error, None, sys.exc_info()[2]
|
| -
|
| - def _AddDebuggingInformation(self, error):
|
| - """Adds debugging information to error.
|
| -
|
| - Args:
|
| - error: An instance of exceptions.Error.
|
| - """
|
| - if self.IsInspectable():
|
| - msg = (
|
| - 'Received a socket error in the browser connection and the tab '
|
| - 'still exists. The operation probably timed out.'
|
| - )
|
| - else:
|
| - msg = (
|
| - 'Received a socket error in the browser connection and the tab no '
|
| - 'longer exists. The tab probably crashed.'
|
| - )
|
| - error.AddDebuggingMessage(msg)
|
| - error.AddDebuggingMessage('Debugger url: %s' % self.debugger_url)
|
| -
|
| - @_HandleInspectorWebSocketExceptions
|
| - def CollectGarbage(self):
|
| - self._page.CollectGarbage()
|
|
|