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.
4
5import json
6
7from telemetry.core import exceptions
8from telemetry.core import util
9from telemetry.internal.backends.chrome_inspector import inspector_backend_list
10from telemetry.internal.browser import tab
11
12
13class TabUnexpectedResponseException(exceptions.DevtoolsTargetCrashException):
14  pass
15
16
17class TabListBackend(inspector_backend_list.InspectorBackendList):
18  """A dynamic sequence of tab.Tabs in UI order."""
19
20  def __init__(self, browser_backend):
21    super(TabListBackend, self).__init__(browser_backend)
22
23  def New(self, timeout):
24    """Makes a new tab.
25
26    Returns:
27      A Tab object.
28
29    Raises:
30      devtools_http.DevToolsClientConnectionError
31    """
32    if not self._browser_backend.supports_tab_control:
33      raise NotImplementedError("Browser doesn't support tab control.")
34    response = self._browser_backend.devtools_client.RequestNewTab(timeout)
35    try:
36      response = json.loads(response)
37      context_id = response['id']
38    except (KeyError, ValueError):
39      raise TabUnexpectedResponseException(
40          app=self._browser_backend.browser,
41          msg='Received response: %s' % response)
42    return self.GetBackendFromContextId(context_id)
43
44  def CloseTab(self, tab_id, timeout=300):
45    """Closes the tab with the given debugger_url.
46
47    Raises:
48      devtools_http.DevToolsClientConnectionError
49      devtools_client_backend.TabNotFoundError
50      TabUnexpectedResponseException
51      exceptions.TimeoutException
52    """
53    assert self._browser_backend.supports_tab_control
54    # TODO(dtu): crbug.com/160946, allow closing the last tab on some platforms.
55    # For now, just create a new tab before closing the last tab.
56    if len(self) <= 1:
57      self.New(timeout)
58
59    response = self._browser_backend.devtools_client.CloseTab(tab_id, timeout)
60
61    if response != 'Target is closing':
62      raise TabUnexpectedResponseException(
63          app=self._browser_backend.browser,
64          msg='Received response: %s' % response)
65
66    util.WaitFor(lambda: tab_id not in self.IterContextIds(), timeout=5)
67
68  def ActivateTab(self, tab_id, timeout=30):
69    """Activates the tab with the given debugger_url.
70
71    Raises:
72      devtools_http.DevToolsClientConnectionError
73      devtools_client_backend.TabNotFoundError
74      TabUnexpectedResponseException
75    """
76    assert self._browser_backend.supports_tab_control
77
78    response = self._browser_backend.devtools_client.ActivateTab(tab_id,
79                                                                 timeout)
80
81    if response != 'Target activated':
82      raise TabUnexpectedResponseException(
83          app=self._browser_backend.browser,
84          msg='Received response: %s' % response)
85
86  def Get(self, index, ret):
87    """Returns self[index] if it exists, or ret if index is out of bounds."""
88    if len(self) <= index:
89      return ret
90    return self[index]
91
92  def ShouldIncludeContext(self, context):
93    if 'type' in context:
94      return (context['type'] == 'page' or
95              context['url'] == 'chrome://media-router/')
96    # TODO: For compatibility with Chrome before r177683.
97    # This check is not completely correct, see crbug.com/190592.
98    return not context['url'].startswith('chrome-extension://')
99
100  def CreateWrapper(self, inspector_backend):
101    return tab.Tab(inspector_backend, self, self._browser_backend.browser)
102
103  def _HandleDevToolsConnectionError(self, error):
104    if not self._browser_backend.IsAppRunning():
105      error.AddDebuggingMessage('The browser is not running. It probably '
106                                'crashed.')
107    elif not self._browser_backend.HasBrowserFinishedLaunching():
108      error.AddDebuggingMessage('The browser exists but cannot be reached.')
109    else:
110      error.AddDebuggingMessage('The browser exists and can be reached. '
111                                'The devtools target probably crashed.')
112