| Index: tools/telemetry/telemetry/internal/platform/network_controller_backend.py
|
| diff --git a/tools/telemetry/telemetry/internal/platform/network_controller_backend.py b/tools/telemetry/telemetry/internal/platform/network_controller_backend.py
|
| index 57cc37d3679cb5f522fc8b86a85d668bc805eccd..a5e316d2b6226c14b889f9279191ed8e26b2234f 100644
|
| --- a/tools/telemetry/telemetry/internal/platform/network_controller_backend.py
|
| +++ b/tools/telemetry/telemetry/internal/platform/network_controller_backend.py
|
| @@ -27,28 +27,92 @@ class NetworkControllerBackend(object):
|
|
|
| def __init__(self, platform_backend):
|
| self._platform_backend = platform_backend
|
| - self._browser_backend = None
|
| - self._active_replay_args = {}
|
| - self._pending_replay_args = {}
|
| + self._is_android_platform = self._platform_backend.GetOSName() == 'android'
|
| + self._is_cros_platform = self._platform_backend.GetOSName() == 'chromeos'
|
| + self._wpr_mode = None
|
| + self._netsim = None
|
| + self._extra_wpr_args = None
|
| + self._wpr_port_pairs = None
|
| + self._archive_path = None
|
| + self._make_javascript_deterministic = None
|
| self._forwarder = None
|
| self._wpr_server = None
|
|
|
| - def SetReplayArgs(self, archive_path, wpr_mode, netsim, extra_wpr_args,
|
| - make_javascript_deterministic=False):
|
| - """Save the arguments needed for replay.
|
| + @property
|
| + def wpr_mode(self):
|
| + return self._wpr_mode
|
| +
|
| + @property
|
| + def wpr_device_ports(self):
|
| + try:
|
| + return self._forwarder.port_pairs.remote_ports
|
| + except AttributeError:
|
| + return None
|
| +
|
| + @property
|
| + def host_ip(self):
|
| + return self._platform_backend.forwarder_factory.host_ip
|
| +
|
| + def Open(self, wpr_mode, netsim, extra_wpr_args):
|
| + assert self._wpr_port_pairs is None, 'Network controller is already open'
|
| + self._wpr_mode = wpr_mode
|
| + self._netsim = netsim
|
| + self._extra_wpr_args = list(extra_wpr_args) # Keep a copy.
|
| +
|
| + if self._is_android_platform:
|
| + self._platform_backend.InstallTestCa()
|
| +
|
| + # Determine adequate WPR ports to use for the specific paltform and
|
| + # selected configuration.
|
| + if self._netsim:
|
| + if self._is_android_platform:
|
| + assert self._platform_backend.use_rndis_forwarder, (
|
| + 'Netsim requires RNDIS forwarding.')
|
| + self._wpr_port_pairs = forwarders.PortPairs.Make(
|
| + http=(0, 80), https=(0, 443), dns=(0, 53))
|
| + else:
|
| + self._wpr_port_pairs = forwarders.PortPairs.Make(
|
| + http=(80, 80), https=(443, 443), dns=(53, 53))
|
| + else:
|
| + self._wpr_port_pairs = forwarders.PortPairs.Make(
|
| + http=(0, 0), https=(0, 0))
|
| +
|
| + if self._is_cros_platform:
|
| + local_ports = self._wpr_port_pairs.local_ports
|
| + # TODO(perezju): Is this correct? local https pairs with remote http?
|
| + # Dns is never paired?
|
| + self._wpr_port_pairs = forwarders.PortPairs.Make(
|
| + http=(local_ports.http,
|
| + self._platform_backend.GetRemotePort(local_ports.http)),
|
| + https=(local_ports.https,
|
| + self._platform_backend.GetRemotePort(local_ports.http)))
|
| +
|
| + def Close(self):
|
| + if self._forwarder:
|
| + self._forwarder.Close()
|
| + self._forwarder = None
|
| + self.StopReplay()
|
|
|
| - To make the settings effective, this call must be followed by a call
|
| - to UpdateReplay.
|
| + if self._is_android_platform:
|
| + self._platform_backend.RemoveTestCa()
|
| +
|
| + self._wpr_mode = None
|
| + self._netsim = None
|
| + self._extra_wpr_args = None
|
| + self._wpr_port_pairs = None
|
| + self._archive_path = None
|
| + self._make_javascript_deterministic = None
|
| +
|
| + def StartReplay(self, archive_path, make_javascript_deterministic=False):
|
| + """Start (or reuse) the web page replay server.
|
|
|
| Args:
|
| archive_path: a path to a specific WPR archive.
|
| - wpr_mode: one of wpr_modes.WPR_OFF, wpr_modes.WPR_APPEND,
|
| - wpr_modes.WPR_REPLAY, or wpr_modes.WPR_RECORD.
|
| - netsim: a net_config string ('dialup', '3g', 'dsl', 'cable', or 'fios').
|
| - extra_wpr_args: a list of additional replay args (or an empty list).
|
| make_javascript_deterministic: True if replay should inject a script
|
| to make JavaScript behave deterministically (e.g., override Date()).
|
| """
|
| + if self._wpr_mode == wpr_modes.WPR_OFF:
|
| + return
|
| if not archive_path:
|
| # TODO(slamm, tonyg): Ideally, replay mode should be stopped when there is
|
| # no archive path. However, if the replay server already started, and
|
| @@ -57,160 +121,80 @@ class NetworkControllerBackend(object):
|
| # replay server forwards requests to it. (Chrome is configured to use
|
| # fixed ports fo all HTTP/HTTPS requests.)
|
| return
|
| - self._pending_replay_args = dict(
|
| - archive_path=archive_path,
|
| - wpr_mode=wpr_mode,
|
| - netsim=netsim,
|
| - extra_wpr_args=extra_wpr_args,
|
| - make_javascript_deterministic=make_javascript_deterministic)
|
| - # TODO(slamm): Update replay here when the browser_backend dependencies
|
| - # are moved to the platform. https://crbug.com/423962
|
| - # |self._pending_replay_args| can be removed at that time.
|
| -
|
| - def UpdateReplay(self, browser_backend=None):
|
| - """Start or reuse Web Page Replay.
|
| -
|
| - UpdateReplay must be called after every call to SetReplayArgs.
|
| -
|
| - TODO(slamm): Update replay in SetReplayArgs once the browser_backend
|
| - dependencies move to platform. https://crbug.com/423962
|
| - browser_backend properties used:
|
| - - Input: wpr_port_pairs
|
| - - Output: wpr_port_pairs (browser uses for --testing-fixed-* flags).
|
| - Args:
|
| - browser_backend: instance of telemetry.core.backends.browser_backend
|
| - """
|
| - if not self._pending_replay_args:
|
| - # In some cases (e.g., unit tests), the browser is used without replay.
|
| - return
|
| - if self._pending_replay_args == self._active_replay_args:
|
| - return
|
| -
|
| - pending_archive_path = self._pending_replay_args['archive_path']
|
| -
|
| -
|
| -
|
| - pending_wpr_mode = self._pending_replay_args['wpr_mode']
|
| - if pending_wpr_mode == wpr_modes.WPR_OFF:
|
| - return
|
| - if (pending_wpr_mode == wpr_modes.WPR_REPLAY and
|
| - not os.path.exists(pending_archive_path)):
|
| - raise ArchiveDoesNotExistError(
|
| - 'Archive path does not exist: %s' % pending_archive_path)
|
| - if browser_backend:
|
| - self._browser_backend = browser_backend
|
| - self.StopReplay() # stop any forwarder too
|
| - wpr_port_pairs = self._browser_backend.wpr_port_pairs
|
| - else:
|
| - # If no browser_backend, then this is an update for an existing browser.
|
| - assert self._browser_backend
|
| - self._StopReplayOnly() # leave existing forwarder in place
|
| - wpr_port_pairs = self._forwarder.port_pairs
|
| - wpr_http_port = wpr_port_pairs.http.local_port
|
| - wpr_https_port = wpr_port_pairs.https.local_port
|
| - wpr_dns_port = (wpr_port_pairs.dns.local_port
|
| - if wpr_port_pairs.dns else None)
|
| -
|
| - archive_path = self._pending_replay_args['archive_path']
|
| - wpr_mode = self._pending_replay_args['wpr_mode']
|
| - netsim = self._pending_replay_args['netsim']
|
| - extra_wpr_args = self._pending_replay_args['extra_wpr_args']
|
| - make_javascript_deterministic = self._pending_replay_args[
|
| - 'make_javascript_deterministic']
|
| -
|
| - if wpr_mode == wpr_modes.WPR_OFF:
|
| - return
|
| - if (wpr_mode == wpr_modes.WPR_REPLAY and
|
| - not os.path.exists(archive_path)):
|
| + if (self._wpr_mode == wpr_modes.WPR_REPLAY
|
| + and not os.path.exists(archive_path)):
|
| raise ArchiveDoesNotExistError(
|
| 'Archive path does not exist: %s' % archive_path)
|
| + if (self._wpr_server is not None and
|
| + self._archive_path == archive_path and
|
| + self._make_javascript_deterministic == make_javascript_deterministic):
|
| + return # We may reuse the existing server
|
|
|
| - wpr_args = _ReplayCommandLineArgs(
|
| - wpr_mode, netsim, extra_wpr_args, make_javascript_deterministic,
|
| - self._platform_backend.wpr_ca_cert_path)
|
| - self._wpr_server = self._ReplayServer(
|
| - archive_path, self._platform_backend.forwarder_factory.host_ip,
|
| - wpr_http_port, wpr_https_port, wpr_dns_port, wpr_args)
|
| - started_ports = self._wpr_server.StartServer()
|
| -
|
| - if not self._forwarder:
|
| - self._forwarder = self._platform_backend.forwarder_factory.Create(
|
| - _ForwarderPortPairs(started_ports, wpr_port_pairs))
|
| -
|
| - self._active_replay_args = self._pending_replay_args
|
| - self._pending_replay_args = None
|
| -
|
| - def _ReplayServer(
|
| - self, archive_path, host_ip, http_port, https_port, dns_port, wpr_args):
|
| - return webpagereplay.ReplayServer(
|
| - archive_path, host_ip, http_port, https_port, dns_port, wpr_args)
|
| + self._archive_path = archive_path
|
| + self._make_javascript_deterministic = make_javascript_deterministic
|
| + self.StopReplay() # Stop if it was already running.
|
| + started_ports = self._StartReplayServer()
|
| + self._StartForwarderIfNeeded(started_ports)
|
|
|
| def StopReplay(self):
|
| - if self._forwarder:
|
| - self._forwarder.Close()
|
| - self._forwarder = None
|
| - self._StopReplayOnly()
|
| -
|
| - def _StopReplayOnly(self):
|
| if self._wpr_server:
|
| self._wpr_server.StopServer()
|
| self._wpr_server = None
|
| - self._active_replay_args = {}
|
|
|
| - @property
|
| - def wpr_http_device_port(self):
|
| - if not self._forwarder or not self._forwarder.port_pairs.http:
|
| - return None
|
| - return self._forwarder.port_pairs.http.remote_port
|
| + def _StartReplayServer(self):
|
| + assert self._wpr_server is None
|
| + local_ports = self._wpr_port_pairs.local_ports
|
| + self._wpr_server = webpagereplay.ReplayServer(
|
| + self._archive_path,
|
| + self.host_ip,
|
| + local_ports.http,
|
| + local_ports.https,
|
| + local_ports.dns,
|
| + self._ReplayCommandLineArgs())
|
| + return self._wpr_server.StartServer()
|
| +
|
| + def _ReplayCommandLineArgs(self):
|
| + wpr_args = list(self._extra_wpr_args)
|
| + if self._netsim:
|
| + wpr_args.append('--net=%s' % self._netsim)
|
| + if self._wpr_mode == wpr_modes.WPR_APPEND:
|
| + wpr_args.append('--append')
|
| + elif self._wpr_mode == wpr_modes.WPR_RECORD:
|
| + wpr_args.append('--record')
|
| + if not self._make_javascript_deterministic:
|
| + wpr_args.append('--inject_scripts=')
|
| + if self._platform_backend.wpr_ca_cert_path:
|
| + wpr_args.extend([
|
| + '--should_generate_certs',
|
| + '--https_root_ca_cert_path=%s'
|
| + % self._platform_backend.wpr_ca_cert_path])
|
| + return wpr_args
|
| +
|
| + def _StartForwarderIfNeeded(self, started_ports):
|
| + """Start a forwarder from started local ports to requested remote ports.
|
| +
|
| + The local host is where Telemetry is run. The remote is host where
|
| + the target application is run. The local and remote hosts may be
|
| + the same (e.g., testing a desktop browser) or different (e.g., testing
|
| + an android browser).
|
| +
|
| + The remote ports may be zero. In that case, the forwarder determines
|
| + the remote ports.
|
| +
|
| + An existing forwarder for the same started ports may be reused.
|
|
|
| - @property
|
| - def wpr_https_device_port(self):
|
| - if not self._forwarder or not self._forwarder.port_pairs.https:
|
| - return None
|
| - return self._forwarder.port_pairs.https.remote_port
|
| -
|
| -
|
| -def _ReplayCommandLineArgs(wpr_mode, netsim, extra_wpr_args,
|
| - make_javascript_deterministic, wpr_ca_cert_path):
|
| - wpr_args = list(extra_wpr_args)
|
| - if netsim:
|
| - wpr_args.append('--net=%s' % netsim)
|
| - if wpr_mode == wpr_modes.WPR_APPEND:
|
| - wpr_args.append('--append')
|
| - elif wpr_mode == wpr_modes.WPR_RECORD:
|
| - wpr_args.append('--record')
|
| - if not make_javascript_deterministic:
|
| - wpr_args.append('--inject_scripts=')
|
| - if wpr_ca_cert_path:
|
| - wpr_args.extend([
|
| - '--should_generate_certs',
|
| - '--https_root_ca_cert_path=%s' % wpr_ca_cert_path,
|
| - ])
|
| - return wpr_args
|
| -
|
| -
|
| -def _ForwarderPortPairs(started_ports, wpr_port_pairs):
|
| - """Return PortPairs with started local ports and requested remote ports.
|
| -
|
| - The local host is where Telemetry is run. The remote is host where
|
| - the target application is run. The local and remote hosts may be
|
| - the same (e.g., testing a desktop browser) or different (e.g., testing
|
| - an android browser).
|
| -
|
| - The remote ports may be zero. In that case, the forwarder determines
|
| - the remote ports.
|
| -
|
| - Args:
|
| - started_ports: a tuple of of integer ports from which to forward:
|
| - (HTTP_PORT, HTTPS_PORT, DNS_PORT) # DNS_PORT may be None
|
| - wpr_port_pairs: a forwarders.PortPairs instance where the remote ports,
|
| - if set, are used.
|
| - Returns:
|
| - a forwarders.PortPairs instance used to create the forwarder.
|
| - """
|
| - local_http_port, local_https_port, local_dns_port = started_ports
|
| - return forwarders.PortPairs(
|
| - forwarders.PortPair(local_http_port, wpr_port_pairs.http.remote_port),
|
| - forwarders.PortPair(local_https_port, wpr_port_pairs.https.remote_port),
|
| - (forwarders.PortPair(local_dns_port, wpr_port_pairs.dns.remote_port)
|
| - if wpr_port_pairs.dns is not None else None))
|
| + Args:
|
| + started_ports: a PortSet tuple of integer ports from which to forward.
|
| + """
|
| + if self._forwarder is not None:
|
| + if started_ports == self._forwarder.port_pairs.local_ports:
|
| + return # Safe to reuse existing forwarder.
|
| + self._forwarder.Close()
|
| + remote_ports = self._wpr_port_pairs.remote_ports
|
| + self._forwarder = self._platform_backend.forwarder_factory.Create(
|
| + forwarders.PortPairs.Make(
|
| + http=(started_ports.http, remote_ports.http),
|
| + https=(started_ports.https, remote_ports.https),
|
| + dns=((started_ports.dns, remote_ports.dns)
|
| + if remote_ports.dns is not None else None)
|
| + ))
|
|
|