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

Unified Diff: telemetry/telemetry/internal/platform/network_controller_backend.py

Issue 1671903002: [Telemetry] Implement network_controller_backend new API (Closed) Base URL: git@github.com:catapult-project/catapult@master
Patch Set: 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 side-by-side diff with in-line comments
Download patch
Index: telemetry/telemetry/internal/platform/network_controller_backend.py
diff --git a/telemetry/telemetry/internal/platform/network_controller_backend.py b/telemetry/telemetry/internal/platform/network_controller_backend.py
index 57cc37d3679cb5f522fc8b86a85d668bc805eccd..5f4422e20b47e7dd731c5447688b8b7849dfd909 100644
--- a/telemetry/telemetry/internal/platform/network_controller_backend.py
+++ b/telemetry/telemetry/internal/platform/network_controller_backend.py
@@ -27,28 +27,118 @@ 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._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.
+ # TODO(perezju) Remove when SetReplayArgs is gone.
+ self._pending_replay_args = None
+
+ @property
+ def is_open(self):
+ return self._wpr_mode is not None
+
+ @property
+ def host_ip(self):
+ return self._platform_backend.forwarder_factory.host_ip
+
+ @property
+ def wpr_mode(self):
+ return self._wpr_mode
- To make the settings effective, this call must be followed by a call
- to UpdateReplay.
+ @property
+ def wpr_device_ports(self):
+ try:
+ return self._forwarder.port_pairs.remote_ports
+ except AttributeError:
+ return None
+
+ @property
+ def wpr_http_device_port(self):
+ # TODO(perezju): Remove and switch clients to wpr_device_ports.http
+ return self.wpr_device_ports.http
+
+ @property
+ def wpr_https_device_port(self):
+ # TODO(perezju): Remove and switch clients to wpr_device_ports.https
+ return self.wpr_device_ports.https
+
+ def Open(self, wpr_mode, netsim, extra_wpr_args):
+ """Configure and prepare target platform for network control.
+
+ This may, e.g., install test certificates and perform any needed setup
+ on the target platform.
+
+ After network interactions are over, clients should call the Close method.
+
+ Args:
+ wpr_mode: a mode for web page replay; available modes are
+ wpr_modes.WPR_OFF, wpr_modes.APPEND, wpr_modes.WPR_REPLAY, or
+ wpr_modes.WPR_RECORD.
+ netsim: a net_config string (e.g. 'dialup', '3g', 'dsl', 'cable', 'fios'),
+ may be None.
+ extra_wpr_args: an list of extra arguments for web page replay.
+ """
+ assert not self.is_open, 'Network controller is already open'
+ self._wpr_mode = wpr_mode
+ self._netsim = netsim
+ self._extra_wpr_args = extra_wpr_args
+
+ # TODO(perezju): Determine correct ports for different platform backends,
+ # and install test certificates if needed.
+ self._wpr_port_pairs = forwarders.PortPairs(
+ http=forwarders.PortPair(0, 0),
+ https=forwarders.PortPair(0, 0),
+ dns=forwarders.PortPair(0, 0))
+
+ def Close(self):
+ """Undo changes in the target platform used for network control.
+
+ Implicitly stops replay if currently active.
+ """
+ # TODO(perezju): Uninstall test certificates if needed.
+ self.StopReplay()
+ self._make_javascript_deterministic = None
+ self._archive_path = None
+ self._wpr_port_pairs = None
+ self._extra_wpr_args = None
+ self._netsim = None
+ self._wpr_mode = None
+
+ def StartReplay(self, archive_path, make_javascript_deterministic=False):
+ """Start web page replay from a given replay archive.
+
+ Starts as needed, and reuses if possible, the replay server on the host and
+ a forwarder from the host to the target platform.
+
+ Implementation details
+ ----------------------
+
+ 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).
+
+ A replay server is started on the local host using the local ports, while
+ a forwarder ties the local to the remote ports.
+
+ Both local and remote ports may be zero. In that case they are determined
+ by the replay server and the forwarder respectively. Setting dns to None
+ disables DNS traffic.
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()).
"""
+ assert self.is_open, 'Network controller is not open'
+ 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 +147,123 @@ 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
+ 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 replay 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
+ local_ports = self._StartReplayServer()
+ self._StartForwarder(local_ports)
def StopReplay(self):
+ """Stop web page replay.
+
+ Stops both the replay server and the forwarder if currently active.
+ """
if self._forwarder:
self._forwarder.Close()
self._forwarder = None
- self._StopReplayOnly()
-
- def _StopReplayOnly(self):
+ self._StopReplayServer()
+
+ def _StartReplayServer(self):
+ """Start the replay server and return the started local_ports."""
+ self._StopReplayServer() # In case it was already running.
+ 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 _StopReplayServer(self):
+ """Stop the replay server only."""
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 _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 _StartForwarder(self, local_ports):
+ """Start a forwarder from local_ports to the set WPR remote_ports."""
+ if self._forwarder is not None:
+ if local_ports == self._forwarder.port_pairs.local_ports:
+ return # Safe to reuse existing forwarder.
+ self._forwarder.Close()
+ self._forwarder = self._platform_backend.forwarder_factory.Create(
+ forwarders.PortPairs.Zip(local_ports,
+ self._wpr_port_pairs.remote_ports))
- @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))
+ def SetReplayArgs(self, archive_path, wpr_mode, netsim, extra_wpr_args,
+ make_javascript_deterministic=False):
+ """DEPRECATED: New clients should not call this method."""
+ if not archive_path:
+ return # Same as above. Keep an existing replay server running.
+ 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)
+
+ def UpdateReplay(self, browser_backend=None):
+ """DEPRECATED: New clients should not call this method."""
+ if not self._pending_replay_args:
+ # In some cases (e.g., unit tests), the browser is used without replay.
+ return
+
+ # TODO(perezju): Move code to figure out WPR port pairts out of browser
+ # backends and into the Open method above.
+ if browser_backend is None:
+ # If no browser_backend, then this is an update for an existing browser.
+ assert self.is_open and self._wpr_port_pairs is not None
+ wpr_port_pairs = self._wpr_port_pairs
+ may_reuse_session = (
+ self._pending_replay_args['wpr_mode'] in [wpr_modes.WPR_OFF,
+ self._wpr_mode] and
+ self._pending_replay_args['netsim'] == self._netsim and
+ self._pending_replay_args['extra_wpr_args'] == self._extra_wpr_args)
+ else:
+ # Use WPR port pairs selected by the browser backend.
+ wpr_port_pairs = browser_backend.wpr_port_pairs
+ may_reuse_session = False
+
+ if not may_reuse_session:
+ self.Close() # In case it is already open.
+ self.Open(self._pending_replay_args['wpr_mode'],
+ self._pending_replay_args['netsim'],
+ self._pending_replay_args['extra_wpr_args'])
+ # Override port pairs with those chosen by the browser.
+ self._wpr_port_pairs = wpr_port_pairs
+
+ self.StartReplay(self._pending_replay_args['archive_path'],
+ self._pending_replay_args['make_javascript_deterministic'])
+
+ # Remember actual port pairs being used after defaults have been resolved.
+ # Note: the forwarder would be None if WPR mode is set to off.
+ if self._forwarder is not None:
+ self._wpr_port_pairs = self._forwarder.port_pairs
+ self._pending_replay_args = None

Powered by Google App Engine
This is Rietveld 408576698