Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: tools/telemetry/telemetry/internal/platform/network_controller_backend.py

Issue 1491183003: [Telemetry] Move WPR life cycle from browser to platform (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: work in progress Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import os 5 import os
6 6
7 from telemetry.internal import forwarders 7 from telemetry.internal import forwarders
8 from telemetry.internal.util import webpagereplay 8 from telemetry.internal.util import webpagereplay
9 from telemetry.util import wpr_modes 9 from telemetry.util import wpr_modes
10 10
11 class ArchiveDoesNotExistError(Exception): 11 class ArchiveDoesNotExistError(Exception):
12 """Raised when the archive path does not exist for replay mode.""" 12 """Raised when the archive path does not exist for replay mode."""
13 pass 13 pass
14 14
15 15
16 class ReplayAndBrowserPortsError(Exception): 16 class ReplayAndBrowserPortsError(Exception):
17 """Raised an existing browser would get different remote replay ports.""" 17 """Raised an existing browser would get different remote replay ports."""
18 pass 18 pass
19 19
20 20
21 class NetworkControllerBackend(object): 21 class NetworkControllerBackend(object):
22 """Control network settings and servers to simulate the Web. 22 """Control network settings and servers to simulate the Web.
23 23
24 Network changes include forwarding device ports to host platform ports. 24 Network changes include forwarding device ports to host platform ports.
25 Web Page Replay is used to record and replay HTTP/HTTPS responses. 25 Web Page Replay is used to record and replay HTTP/HTTPS responses.
26 """ 26 """
27 27
28 def __init__(self, platform_backend): 28 def __init__(self, platform_backend):
29 self._platform_backend = platform_backend 29 self._platform_backend = platform_backend
30 self._browser_backend = None 30 self._is_android_platform = self._platform_backend.GetOSName() == 'android'
31 self._active_replay_args = {} 31 self._is_cros_platform = self._platform_backend.GetOSName() == 'chromeos'
32 self._pending_replay_args = {} 32 self._wpr_mode = None
33 self._netsim = None
34 self._extra_wpr_args = None
35 self._wpr_port_pairs = None
36 self._archive_path = None
37 self._make_javascript_deterministic = None
33 self._forwarder = None 38 self._forwarder = None
34 self._wpr_server = None 39 self._wpr_server = None
35 40
36 def SetReplayArgs(self, archive_path, wpr_mode, netsim, extra_wpr_args, 41 @property
37 make_javascript_deterministic=False): 42 def wpr_mode(self):
38 """Save the arguments needed for replay. 43 return self._wpr_mode
39 44
40 To make the settings effective, this call must be followed by a call 45 @property
41 to UpdateReplay. 46 def wpr_device_ports(self):
47 try:
48 return self._forwarder.port_pairs.remote_ports
49 except AttributeError:
50 return None
51
52 @property
53 def host_ip(self):
54 return self._platform_backend.forwarder_factory.host_ip
55
56 def Open(self, wpr_mode, netsim, extra_wpr_args):
57 assert self._wpr_port_pairs is None, 'Network controller is already open'
58 self._wpr_mode = wpr_mode
59 self._netsim = netsim
60 self._extra_wpr_args = list(extra_wpr_args) # Keep a copy.
61
62 if self._is_android_platform:
63 self._platform_backend.InstallTestCa()
64
65 # Determine adequate WPR ports to use for the specific paltform and
66 # selected configuration.
67 if self._netsim:
68 if self._is_android_platform:
69 assert self._platform_backend.use_rndis_forwarder, (
70 'Netsim requires RNDIS forwarding.')
71 self._wpr_port_pairs = forwarders.PortPairs.Make(
72 http=(0, 80), https=(0, 443), dns=(0, 53))
73 else:
74 self._wpr_port_pairs = forwarders.PortPairs.Make(
75 http=(80, 80), https=(443, 443), dns=(53, 53))
76 else:
77 self._wpr_port_pairs = forwarders.PortPairs.Make(
78 http=(0, 0), https=(0, 0))
79
80 if self._is_cros_platform:
81 local_ports = self._wpr_port_pairs.local_ports
82 # TODO(perezju): Is this correct? local https pairs with remote http?
83 # Dns is never paired?
84 self._wpr_port_pairs = forwarders.PortPairs.Make(
85 http=(local_ports.http,
86 self._platform_backend.GetRemotePort(local_ports.http)),
87 https=(local_ports.https,
88 self._platform_backend.GetRemotePort(local_ports.http)))
89
90 def Close(self):
91 if self._forwarder:
92 self._forwarder.Close()
93 self._forwarder = None
94 self.StopReplay()
95
96 if self._is_android_platform:
97 self._platform_backend.RemoveTestCa()
98
99 self._wpr_mode = None
100 self._netsim = None
101 self._extra_wpr_args = None
102 self._wpr_port_pairs = None
103 self._archive_path = None
104 self._make_javascript_deterministic = None
105
106 def StartReplay(self, archive_path, make_javascript_deterministic=False):
107 """Start (or reuse) the web page replay server.
42 108
43 Args: 109 Args:
44 archive_path: a path to a specific WPR archive. 110 archive_path: a path to a specific WPR archive.
45 wpr_mode: one of wpr_modes.WPR_OFF, wpr_modes.WPR_APPEND,
46 wpr_modes.WPR_REPLAY, or wpr_modes.WPR_RECORD.
47 netsim: a net_config string ('dialup', '3g', 'dsl', 'cable', or 'fios').
48 extra_wpr_args: a list of additional replay args (or an empty list).
49 make_javascript_deterministic: True if replay should inject a script 111 make_javascript_deterministic: True if replay should inject a script
50 to make JavaScript behave deterministically (e.g., override Date()). 112 to make JavaScript behave deterministically (e.g., override Date()).
51 """ 113 """
114 if self._wpr_mode == wpr_modes.WPR_OFF:
115 return
52 if not archive_path: 116 if not archive_path:
53 # TODO(slamm, tonyg): Ideally, replay mode should be stopped when there is 117 # TODO(slamm, tonyg): Ideally, replay mode should be stopped when there is
54 # no archive path. However, if the replay server already started, and 118 # no archive path. However, if the replay server already started, and
55 # a file URL is tested with the 119 # a file URL is tested with the
56 # telemetry.core.local_server.LocalServerController, then the 120 # telemetry.core.local_server.LocalServerController, then the
57 # replay server forwards requests to it. (Chrome is configured to use 121 # replay server forwards requests to it. (Chrome is configured to use
58 # fixed ports fo all HTTP/HTTPS requests.) 122 # fixed ports fo all HTTP/HTTPS requests.)
59 return 123 return
60 self._pending_replay_args = dict( 124 if (self._wpr_mode == wpr_modes.WPR_REPLAY
61 archive_path=archive_path, 125 and not os.path.exists(archive_path)):
62 wpr_mode=wpr_mode,
63 netsim=netsim,
64 extra_wpr_args=extra_wpr_args,
65 make_javascript_deterministic=make_javascript_deterministic)
66 # TODO(slamm): Update replay here when the browser_backend dependencies
67 # are moved to the platform. https://crbug.com/423962
68 # |self._pending_replay_args| can be removed at that time.
69
70 def UpdateReplay(self, browser_backend=None):
71 """Start or reuse Web Page Replay.
72
73 UpdateReplay must be called after every call to SetReplayArgs.
74
75 TODO(slamm): Update replay in SetReplayArgs once the browser_backend
76 dependencies move to platform. https://crbug.com/423962
77 browser_backend properties used:
78 - Input: wpr_port_pairs
79 - Output: wpr_port_pairs (browser uses for --testing-fixed-* flags).
80 Args:
81 browser_backend: instance of telemetry.core.backends.browser_backend
82 """
83 if not self._pending_replay_args:
84 # In some cases (e.g., unit tests), the browser is used without replay.
85 return
86 if self._pending_replay_args == self._active_replay_args:
87 return
88
89 pending_archive_path = self._pending_replay_args['archive_path']
90
91
92
93 pending_wpr_mode = self._pending_replay_args['wpr_mode']
94 if pending_wpr_mode == wpr_modes.WPR_OFF:
95 return
96 if (pending_wpr_mode == wpr_modes.WPR_REPLAY and
97 not os.path.exists(pending_archive_path)):
98 raise ArchiveDoesNotExistError(
99 'Archive path does not exist: %s' % pending_archive_path)
100 if browser_backend:
101 self._browser_backend = browser_backend
102 self.StopReplay() # stop any forwarder too
103 wpr_port_pairs = self._browser_backend.wpr_port_pairs
104 else:
105 # If no browser_backend, then this is an update for an existing browser.
106 assert self._browser_backend
107 self._StopReplayOnly() # leave existing forwarder in place
108 wpr_port_pairs = self._forwarder.port_pairs
109 wpr_http_port = wpr_port_pairs.http.local_port
110 wpr_https_port = wpr_port_pairs.https.local_port
111 wpr_dns_port = (wpr_port_pairs.dns.local_port
112 if wpr_port_pairs.dns else None)
113
114 archive_path = self._pending_replay_args['archive_path']
115 wpr_mode = self._pending_replay_args['wpr_mode']
116 netsim = self._pending_replay_args['netsim']
117 extra_wpr_args = self._pending_replay_args['extra_wpr_args']
118 make_javascript_deterministic = self._pending_replay_args[
119 'make_javascript_deterministic']
120
121 if wpr_mode == wpr_modes.WPR_OFF:
122 return
123 if (wpr_mode == wpr_modes.WPR_REPLAY and
124 not os.path.exists(archive_path)):
125 raise ArchiveDoesNotExistError( 126 raise ArchiveDoesNotExistError(
126 'Archive path does not exist: %s' % archive_path) 127 'Archive path does not exist: %s' % archive_path)
128 if (self._wpr_server is not None and
129 self._archive_path == archive_path and
130 self._make_javascript_deterministic == make_javascript_deterministic):
131 return # We may reuse the existing server
127 132
128 wpr_args = _ReplayCommandLineArgs( 133 self._archive_path = archive_path
129 wpr_mode, netsim, extra_wpr_args, make_javascript_deterministic, 134 self._make_javascript_deterministic = make_javascript_deterministic
130 self._platform_backend.wpr_ca_cert_path) 135 self.StopReplay() # Stop if it was already running.
131 self._wpr_server = self._ReplayServer( 136 started_ports = self._StartReplayServer()
132 archive_path, self._platform_backend.forwarder_factory.host_ip, 137 self._StartForwarderIfNeeded(started_ports)
133 wpr_http_port, wpr_https_port, wpr_dns_port, wpr_args)
134 started_ports = self._wpr_server.StartServer()
135
136 if not self._forwarder:
137 self._forwarder = self._platform_backend.forwarder_factory.Create(
138 _ForwarderPortPairs(started_ports, wpr_port_pairs))
139
140 self._active_replay_args = self._pending_replay_args
141 self._pending_replay_args = None
142
143 def _ReplayServer(
144 self, archive_path, host_ip, http_port, https_port, dns_port, wpr_args):
145 return webpagereplay.ReplayServer(
146 archive_path, host_ip, http_port, https_port, dns_port, wpr_args)
147 138
148 def StopReplay(self): 139 def StopReplay(self):
149 if self._forwarder:
150 self._forwarder.Close()
151 self._forwarder = None
152 self._StopReplayOnly()
153
154 def _StopReplayOnly(self):
155 if self._wpr_server: 140 if self._wpr_server:
156 self._wpr_server.StopServer() 141 self._wpr_server.StopServer()
157 self._wpr_server = None 142 self._wpr_server = None
158 self._active_replay_args = {}
159 143
160 @property 144 def _StartReplayServer(self):
161 def wpr_http_device_port(self): 145 assert self._wpr_server is None
162 if not self._forwarder or not self._forwarder.port_pairs.http: 146 local_ports = self._wpr_port_pairs.local_ports
163 return None 147 self._wpr_server = webpagereplay.ReplayServer(
164 return self._forwarder.port_pairs.http.remote_port 148 self._archive_path,
149 self.host_ip,
150 local_ports.http,
151 local_ports.https,
152 local_ports.dns,
153 self._ReplayCommandLineArgs())
154 return self._wpr_server.StartServer()
165 155
166 @property 156 def _ReplayCommandLineArgs(self):
167 def wpr_https_device_port(self): 157 wpr_args = list(self._extra_wpr_args)
168 if not self._forwarder or not self._forwarder.port_pairs.https: 158 if self._netsim:
169 return None 159 wpr_args.append('--net=%s' % self._netsim)
170 return self._forwarder.port_pairs.https.remote_port 160 if self._wpr_mode == wpr_modes.WPR_APPEND:
161 wpr_args.append('--append')
162 elif self._wpr_mode == wpr_modes.WPR_RECORD:
163 wpr_args.append('--record')
164 if not self._make_javascript_deterministic:
165 wpr_args.append('--inject_scripts=')
166 if self._platform_backend.wpr_ca_cert_path:
167 wpr_args.extend([
168 '--should_generate_certs',
169 '--https_root_ca_cert_path=%s'
170 % self._platform_backend.wpr_ca_cert_path])
171 return wpr_args
171 172
173 def _StartForwarderIfNeeded(self, started_ports):
174 """Start a forwarder from started local ports to requested remote ports.
172 175
173 def _ReplayCommandLineArgs(wpr_mode, netsim, extra_wpr_args, 176 The local host is where Telemetry is run. The remote is host where
174 make_javascript_deterministic, wpr_ca_cert_path): 177 the target application is run. The local and remote hosts may be
175 wpr_args = list(extra_wpr_args) 178 the same (e.g., testing a desktop browser) or different (e.g., testing
176 if netsim: 179 an android browser).
177 wpr_args.append('--net=%s' % netsim)
178 if wpr_mode == wpr_modes.WPR_APPEND:
179 wpr_args.append('--append')
180 elif wpr_mode == wpr_modes.WPR_RECORD:
181 wpr_args.append('--record')
182 if not make_javascript_deterministic:
183 wpr_args.append('--inject_scripts=')
184 if wpr_ca_cert_path:
185 wpr_args.extend([
186 '--should_generate_certs',
187 '--https_root_ca_cert_path=%s' % wpr_ca_cert_path,
188 ])
189 return wpr_args
190 180
181 The remote ports may be zero. In that case, the forwarder determines
182 the remote ports.
191 183
192 def _ForwarderPortPairs(started_ports, wpr_port_pairs): 184 An existing forwarder for the same started ports may be reused.
193 """Return PortPairs with started local ports and requested remote ports.
194 185
195 The local host is where Telemetry is run. The remote is host where 186 Args:
196 the target application is run. The local and remote hosts may be 187 started_ports: a PortSet tuple of integer ports from which to forward.
197 the same (e.g., testing a desktop browser) or different (e.g., testing 188 """
198 an android browser). 189 if self._forwarder is not None:
199 190 if started_ports == self._forwarder.port_pairs.local_ports:
200 The remote ports may be zero. In that case, the forwarder determines 191 return # Safe to reuse existing forwarder.
201 the remote ports. 192 self._forwarder.Close()
202 193 remote_ports = self._wpr_port_pairs.remote_ports
203 Args: 194 self._forwarder = self._platform_backend.forwarder_factory.Create(
204 started_ports: a tuple of of integer ports from which to forward: 195 forwarders.PortPairs.Make(
205 (HTTP_PORT, HTTPS_PORT, DNS_PORT) # DNS_PORT may be None 196 http=(started_ports.http, remote_ports.http),
206 wpr_port_pairs: a forwarders.PortPairs instance where the remote ports, 197 https=(started_ports.https, remote_ports.https),
207 if set, are used. 198 dns=((started_ports.dns, remote_ports.dns)
208 Returns: 199 if remote_ports.dns is not None else None)
209 a forwarders.PortPairs instance used to create the forwarder. 200 ))
210 """
211 local_http_port, local_https_port, local_dns_port = started_ports
212 return forwarders.PortPairs(
213 forwarders.PortPair(local_http_port, wpr_port_pairs.http.remote_port),
214 forwarders.PortPair(local_https_port, wpr_port_pairs.https.remote_port),
215 (forwarders.PortPair(local_dns_port, wpr_port_pairs.dns.remote_port)
216 if wpr_port_pairs.dns is not None else None))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698