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.
4from telemetry.core import exceptions
5
6
7class InspectorRuntime(object):
8  def __init__(self, inspector_websocket):
9    self._inspector_websocket = inspector_websocket
10    self._inspector_websocket.RegisterDomain('Runtime', self._OnNotification)
11    self._contexts_enabled = False
12    self._max_context_id = None
13
14  def _OnNotification(self, msg):
15    if (self._contexts_enabled and
16        msg['method'] == 'Runtime.executionContextCreated'):
17      self._max_context_id = max(self._max_context_id,
18                                 msg['params']['context']['id'])
19
20  def Execute(self, expr, context_id, timeout):
21    self.Evaluate(expr + '; 0;', context_id, timeout)
22
23  def Evaluate(self, expr, context_id, timeout):
24    """Evaluates a javascript expression and returns the result.
25
26    |context_id| can refer to an iframe. The main page has context_id=1, the
27    first iframe context_id=2, etc.
28
29    Raises:
30      exceptions.EvaluateException
31      exceptions.WebSocketDisconnected
32      websocket.WebSocketException
33      socket.error
34    """
35    request = {
36      'method': 'Runtime.evaluate',
37      'params': {
38        'expression': expr,
39        'returnByValue': True
40        }
41      }
42    if context_id is not None:
43      self.EnableAllContexts()
44      request['params']['contextId'] = context_id
45    res = self._inspector_websocket.SyncRequest(request, timeout)
46    if 'error' in res:
47      raise exceptions.EvaluateException(res['error']['message'])
48
49    if 'wasThrown' in res['result'] and res['result']['wasThrown']:
50      # TODO(nduca): propagate stacks from javascript up to the python
51      # exception.
52      raise exceptions.EvaluateException(res['result']['result']['description'])
53    if res['result']['result']['type'] == 'undefined':
54      return None
55    return res['result']['result']['value']
56
57  def EnableAllContexts(self):
58    """Allow access to iframes.
59
60    Raises:
61      exceptions.WebSocketDisconnected
62      websocket.WebSocketException
63      socket.error
64    """
65    if not self._contexts_enabled:
66      self._contexts_enabled = True
67      self._inspector_websocket.SyncRequest({'method': 'Runtime.enable'},
68                                            timeout=30)
69    return self._max_context_id
70
71  def RunInspectorCommand(self, command, timeout):
72    """Runs an inspector command.
73
74    Raises:
75      exceptions.WebSocketDisconnected
76      websocket.WebSocketException
77      socket.error
78    """
79    res = self._inspector_websocket.SyncRequest(command, timeout)
80    return res
81