Bug 1534788 - add the playback_args option r=Bebe,rwood
authorTarek Ziadé <tarek@mozilla.com>
Wed, 13 Mar 2019 14:50:03 +0000
changeset 521752 19e13e0edc40bffa1443a45d99af455a486ed70c
parent 521751 6e4bbb9168097809542143faab0e357ebad42909
child 521753 cbb4a76be84b534152b242877555c60fdcb3fa07
push id10867
push userdvarga@mozilla.com
push dateThu, 14 Mar 2019 15:20:45 +0000
treeherdermozilla-beta@abad13547875 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBebe, rwood
bugs1534788
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1534788 - add the playback_args option r=Bebe,rwood This patch also removes custom_script and stops executing start() in the constructor. Differential Revision: https://phabricator.services.mozilla.com/D23288
testing/mozbase/docs/mozproxy.rst
testing/mozbase/mozproxy/mozproxy/backends/mitm.py
testing/mozbase/mozproxy/tests/test_proxy.py
testing/raptor/raptor/raptor.py
testing/raptor/test/test_playback.py
--- a/testing/mozbase/docs/mozproxy.rst
+++ b/testing/mozbase/docs/mozproxy.rst
@@ -21,25 +21,24 @@ Mozproxy provide a function that returns
    try:
      # do your test
    finally:
      pb.stop()
 
 **config** is a dict with the following options:
 
 - **playback_tool**: name of the backend. can be "mitmproxy", "mitmproxy-android"
-- **playback_recordings**: list of recording files
+- **playback_tool_args**: extra options to pass to the playback tool
 - **playback_binary_manifest**: tooltool manifests for the proxy backend binary
 - **playback_pageset_manifest**: tooltool manifest for the pagesets archive
 - **playback_artifacts**: links to downloadable artifacts
 - **binary**: path of the browser binary
 - **obj_path**: build dir
 - **platform**: platform name (provided by mozinfo.os)
 - **run_local**: if True, the test is running locally.
-- **custom_script**: name of the mitm custom script (-s option)
 - **app**: tested app. Can be "firefox",  "geckoview", "refbrow", "fenix" or  "firefox"
 - **host**: hostname for the policies.json file
 - **local_profile_dir**: profile dir
 
 
 Supported environment variables:
 
 - **MOZPROXY_DIR**: directory used by mozproxy for all data files, set by mozproxy
--- a/testing/mozbase/mozproxy/mozproxy/backends/mitm.py
+++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm.py
@@ -70,17 +70,16 @@ POLICIES_CONTENT_OFF = """{
 }"""
 
 
 class Mitmproxy(Playback):
     def __init__(self, config):
         self.config = config
         self.mitmproxy_proc = None
         self.mitmdump_path = None
-        self.recordings = config.get("playback_recordings")
         self.browser_path = config.get("binary")
         self.policies_dir = None
 
         # mozproxy_dir is where we will download all mitmproxy required files
         # when running locally it comes from obj_path via mozharness/mach
         if self.config.get("obj_path") is not None:
             self.mozproxy_dir = self.config.get("obj_path")
         else:
@@ -89,28 +88,33 @@ class Mitmproxy(Playback):
             # ../tasks/task_N/build/blobber_upload_dir so take that and go up 1 level
             self.mozproxy_dir = os.path.dirname(
                 os.path.dirname(os.environ["MOZ_UPLOAD_DIR"])
             )
 
         self.mozproxy_dir = os.path.join(self.mozproxy_dir, "testing", "mozproxy")
         self.upload_dir = os.environ.get("MOZ_UPLOAD_DIR", self.mozproxy_dir)
 
-        self.recordings_path = self.mozproxy_dir
         LOG.info(
             "mozproxy_dir used for mitmproxy downloads and exe files: %s"
             % self.mozproxy_dir
         )
         # setting up the MOZPROXY_DIR env variable so custom scripts know
         # where to get the data
         os.environ["MOZPROXY_DIR"] = self.mozproxy_dir
+
+    def start(self):
         # go ahead and download and setup mitmproxy
         self.download()
+
         # mitmproxy must be started before setup, so that the CA cert is available
-        self.start()
+        self.mitmdump_path = os.path.join(self.mozproxy_dir, "mitmdump")
+        self.mitmproxy_proc = self.start_mitmproxy_playback(
+            self.mitmdump_path, self.browser_path
+        )
 
         # In case the setup fails, we want to stop the process before raising.
         try:
             self.setup()
         except Exception:
             self.stop()
             raise
 
@@ -140,78 +144,36 @@ class Mitmproxy(Playback):
             for artifact in artifacts:
                 artifact = artifact.strip()
                 if not artifact:
                     continue
                 artifact_name = artifact.split("/")[-1]
                 dest = os.path.join(self.mozproxy_dir, artifact_name)
                 download_file_from_url(artifact, dest, extract=True)
 
-    def start(self):
-        """Start playing back the mitmproxy recording."""
-
-        self.mitmdump_path = os.path.join(self.mozproxy_dir, "mitmdump")
-
-        recordings_list = self.recordings.split()
-        self.mitmproxy_proc = self.start_mitmproxy_playback(
-            self.mitmdump_path, self.recordings_path, recordings_list, self.browser_path
-        )
-
     def stop(self):
         self.stop_mitmproxy_playback()
 
     def start_mitmproxy_playback(
         self,
         mitmdump_path,
-        mitmproxy_recording_path,
-        mitmproxy_recordings_list,
         browser_path,
     ):
         """Startup mitmproxy and replay the specified flow file"""
 
         LOG.info("mitmdump path: %s" % mitmdump_path)
-        LOG.info("recording path: %s" % mitmproxy_recording_path)
-        LOG.info("recordings list: %s" % mitmproxy_recordings_list)
         LOG.info("browser path: %s" % browser_path)
-        mitmproxy_recordings = []
-        # recording names can be provided in comma-separated list; build py list including path
-        for recording in mitmproxy_recordings_list:
-            if not os.path.isfile(os.path.join(mitmproxy_recording_path, recording)):
-                LOG.critical(
-                    "Recording file {} cannot be found!".format(
-                        os.path.join(mitmproxy_recording_path, recording)
-                    )
-                )
-                raise Exception(
-                    "Recording file {} cannot be found!".format(
-                        os.path.join(mitmproxy_recording_path, recording)
-                    )
-                )
-
-            mitmproxy_recordings.append(
-                os.path.join(mitmproxy_recording_path, recording)
-            )
 
         # mitmproxy needs some DLL's that are a part of Firefox itself, so add to path
         env = os.environ.copy()
         env["PATH"] = os.path.dirname(browser_path) + ";" + env["PATH"]
         command = [mitmdump_path, "-k"]
 
-        if "custom_script" in self.config:
-            # cmd line to start mitmproxy playback using custom playback script is as follows:
-            # <path>/mitmdump -s "<path>/alternate-server-replay.py
-            #  <path>recording-1.mp <path>recording-2.mp..."
-            custom_script = self.config["custom_script"] + " " + " ".join(mitmproxy_recordings)
-
-            # this part is platform-specific
-            if mozinfo.os == "win":
-                custom_script = '""' + custom_script.replace("\\", "\\\\\\") + '""'
-                sys.path.insert(1, mitmdump_path)
-
-            command.extend(["-s", custom_script])
+        if "playback_tool_args" in self.config:
+            command.extend(self.config["playback_tool_args"])
 
         LOG.info("Starting mitmproxy playback using env path: %s" % env["PATH"])
         LOG.info("Starting mitmproxy playback using command: %s" % " ".join(command))
         # to turn off mitmproxy log output, use these params for Popen:
         # Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
         mitmproxy_proc = ProcessHandler(command,
                                         logfile=os.path.join(self.upload_dir,
                                                              "mitmproxy.log"),
--- a/testing/mozbase/mozproxy/tests/test_proxy.py
+++ b/testing/mozbase/mozproxy/tests/test_proxy.py
@@ -44,17 +44,20 @@ def test_mitm(*args):
         "obj_path": here,  # XXX tmp?
         "binary": "firefox",
         "app": "firefox",
         "host": "example.com",
     }
 
     playback = get_playback(config)
     assert playback is not None
-    playback.stop()
+    try:
+        playback.start()
+    finally:
+        playback.stop()
 
 
 @mock.patch("mozprocess.processhandler.ProcessHandlerMixin.Process", new=Process)
 @mock.patch("mozproxy.backends.mitm.tooltool_download", new=mock.DEFAULT)
 def test_playback_setup_failed(*args):
     class SetupFailed(Exception):
         pass
 
@@ -80,17 +83,18 @@ def test_playback_setup_failed(*args):
         "app": "firefox",
         "host": "example.com",
     }
 
     prefix = "mozproxy.backends.mitm.MitmproxyDesktop."
     with mock.patch(prefix + "setup", new_callable=setup):
         with mock.patch(prefix + "stop_mitmproxy_playback") as p:
             try:
-                get_playback(config)
+                pb = get_playback(config)
+                pb.start()
             except SetupFailed:
                 assert p.call_count == 1
             except Exception:
                 raise
 
 
 if __name__ == "__main__":
     mozunit.main(runwith="pytest")
--- a/testing/raptor/raptor/raptor.py
+++ b/testing/raptor/raptor/raptor.py
@@ -189,29 +189,26 @@ class Raptor(object):
                 self.config['host'] in ('localhost', '127.0.0.1'):
             self.log.info("making the raptor control server port available to device")
             _tcp_port = "tcp:%s" % self.control_server.port
             self.device.create_socket_connection('reverse', _tcp_port, _tcp_port)
 
     def get_playback_config(self, test):
         self.config['playback_tool'] = test.get('playback')
         self.log.info("test uses playback tool: %s " % self.config['playback_tool'])
-        self.config['playback_binary_manifest'] = test.get('playback_binary_manifest', None)
-        _key = 'playback_binary_zip_%s' % self.config['platform']
-        self.config['playback_binary_zip'] = test.get(_key, None)
-        self.config['playback_pageset_manifest'] = test.get('playback_pageset_manifest', None)
-        _key = 'playback_pageset_zip_%s' % self.config['platform']
-        self.config['playback_pageset_zip'] = test.get(_key, None)
-        self.config['playback_recordings'] = test.get('playback_recordings', None)
+        platform = self.config['platform']
+        self.config['playback_binary_zip'] = test.get('playback_binary_zip_%s' % platform)
+        self.config['playback_pageset_zip'] = test.get('playback_pageset_zip_%s' % platform)
         playback_dir = os.path.join(here, 'playback')
+        self.config['playback_binary_manifest'] = test.get('playback_binary_manifest')
+        self.config['playback_pageset_manifest'] = test.get('playback_pageset_manifest')
         for key in ('playback_pageset_manifest', 'playback_pageset_zip'):
             if self.config.get(key) is None:
                 continue
             self.config[key] = os.path.join(playback_dir, self.config[key])
-        self.config['custom_script'] = os.path.join(playback_dir, 'alternate-server-replay.py')
 
     def serve_benchmark_source(self, test):
         # benchmark-type tests require the benchmark test to be served out
         self.benchmark = Benchmark(self.config, test)
         self.benchmark_port = int(self.benchmark.port)
 
         # for android we must make the benchmarks server available to the device
         if self.config['app'] in self.firefox_android_apps and \
@@ -249,20 +246,41 @@ class Raptor(object):
         # if the test has any specific browser prefs specified, set those in browser profiile
         if self.config['app'] == "firefox":
             self.profile.set_preferences(json.loads(test_prefs))
         else:
             self.log.info("preferences were configured for the test, \
                           but we do not install them on non Firefox browsers.")
 
     def start_playback(self, test):
-        # startup the playback tool
+        # creating the playback tool
         self.get_playback_config(test)
         self.playback = get_playback(self.config, self.device)
 
+        # finish its configuration
+        script = os.path.join(here, "playback", "alternate-server-replay.py")
+        recordings = test.get("playback_recordings")
+        if recordings:
+            script_args = []
+            proxy_dir = self.playback.mozproxy_dir
+            for recording in recordings.split():
+                if not recording:
+                    continue
+                script_args.append(os.path.join(proxy_dir, recording))
+            script = '""%s %s""' % (script, " ".join(script_args))
+
+        # this part is platform-specific
+        if mozinfo.os == "win":
+            script = script.replace("\\", "\\\\\\")
+
+        self.playback.config['playback_tool_args'] = ["-s", script]
+
+        # let's start it!
+        self.playback.start()
+
         # for android we must make the playback server available to the device
         if self.config['app'] in self.firefox_android_apps and self.config['host'] \
                 in ('localhost', '127.0.0.1'):
             self.log.info("making the raptor playback server port available to device")
             _tcp_port = "tcp:8080"
             self.device.create_socket_connection('reverse', _tcp_port, _tcp_port)
 
     def delete_proxy_settings_from_profile(self):
--- a/testing/raptor/test/test_playback.py
+++ b/testing/raptor/test/test_playback.py
@@ -32,16 +32,17 @@ def test_get_playback(get_binary):
     config['playback_recordings'] = 'amazon.mp'
     config['binary'] = get_binary('firefox')
     config['run_local'] = run_local
     config['app'] = 'firefox'
     config['host'] = 'example.com'
 
     playback = get_playback(config)
     assert isinstance(playback, MitmproxyDesktop)
+    playback.start()
     playback.stop()
 
 
 def test_get_unsupported_playback():
     config['playback_tool'] = 'unsupported'
     playback = get_playback(config)
     assert playback is None