Bug 1373635 - Application profile has only be reset if explicitly requested. draft
authorHenrik Skupin <mail@hskupin.info>
Fri, 16 Jun 2017 15:31:45 +0200
changeset 595602 48eeaa15c2cab5468727bef386ec14dddd37d7b7
parent 595489 fe809f57bf2287bb937c3422ed03a63740b3448b
child 633740 1abdf4956e5d99714900837d2b56093d525c6ffe
push id64377
push userbmo:hskupin@gmail.com
push dateFri, 16 Jun 2017 13:32:09 +0000
bugs1373635
milestone56.0a1
Bug 1373635 - Application profile has only be reset if explicitly requested. For both quit() and restart() methods the profile should not be reset, unless it has been requested. The current behavior breaks various tests which make use of quit() and session_start() and which assume that previously set preferences are still set, eg. sessionrestore tests. MozReview-Commit-ID: 4BxSSJPrTYF
testing/marionette/client/marionette_driver/geckoinstance.py
testing/marionette/client/marionette_driver/marionette.py
testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
--- a/testing/marionette/client/marionette_driver/geckoinstance.py
+++ b/testing/marionette/client/marionette_driver/geckoinstance.py
@@ -246,46 +246,43 @@ class GeckoInstance(object):
             "binary": self.binary,
             "profile": self.profile,
             "cmdargs": ["-no-remote", "-marionette"] + self.app_args,
             "env": env,
             "symbols_path": self.symbols_path,
             "process_args": process_args
         }
 
-    def close(self, restart=False, clean=False):
+    def close(self, clean=False):
         """
         Close the managed Gecko process.
 
         Depending on self.runner_class, setting `clean` to True may also kill
         the emulator process in which this instance is running.
 
         :param restart: If True, assume this is being called by restart method.
         :param clean: If True, also perform runner cleanup.
         """
-        if not restart:
-            self.profile = None
-
         if self.runner:
             self.runner.stop()
             if clean:
                 self.runner.cleanup()
 
+        if clean and self.profile:
+            self.profile.cleanup()
+            self.profile = None
+
     def restart(self, prefs=None, clean=True):
         """
         Close then start the managed Gecko process.
 
         :param prefs: Dictionary of preference names and values.
         :param clean: If True, reset the profile before starting.
         """
-        self.close(restart=True)
-
-        if clean and self.profile:
-            self.profile.cleanup()
-            self.profile = None
+        self.close(clean=clean)
 
         if prefs:
             self.prefs = prefs
         else:
             self.prefs = None
         self.start()
 
 
--- a/testing/marionette/client/marionette_driver/marionette.py
+++ b/testing/marionette/client/marionette_driver/marionette.py
@@ -1059,23 +1059,26 @@ class Marionette(object):
         if len(flags) > 0:
             body = {"flags": list(flags)}
 
         # quitApplication was renamed quit in bug 1337743,
         # and this can safely be renamed when Firefox 56 becomes stable
         self._send_message("quitApplication", body)
 
     @do_process_check
-    def quit(self, in_app=False, callback=None):
+    def quit(self, clean=False, in_app=False, callback=None):
         """Terminate the currently running instance.
 
         This command will delete the active marionette session. It also allows
         manipulation of eg. the profile data while the application is not running.
         To start the application again, :func:`start_session` has to be called.
 
+        :param clean: If False the same profile will be used after the next start of
+                      the application. Note that the in app initiated restart always
+                      maintains the same profile.
         :param in_app: If True, marionette will cause a quit from within the
                        browser. Otherwise the browser will be quit immediately
                        by killing the process.
         :param callback: If provided and `in_app` is True, the callback will
                          be used to trigger the shutdown.
         """
         if not self.instance:
             raise errors.MarionetteException("quit() can only be called "
@@ -1098,17 +1101,17 @@ class Marionette(object):
                 self.cleanup()
 
                 message = ("Process killed because a requested application quit did not happen "
                            "within {}s. Check gecko.log for errors.")
                 raise IOError(message.format(self.DEFAULT_SHUTDOWN_TIMEOUT))
 
         else:
             self.delete_session(reset_session_id=True)
-            self.instance.close()
+            self.instance.close(clean=clean)
 
     @do_process_check
     def restart(self, clean=False, in_app=False, callback=None):
         """
         This will terminate the currently running instance, and spawn a new instance
         with the same profile and then reuse the session id when creating a session again.
 
         :param clean: If False the same profile will be used after the restart. Note
@@ -1187,18 +1190,18 @@ class Marionette(object):
         :returns: A dict of the capabilities offered.
 
         """
         self.crashed = 0
 
         if self.instance:
             returncode = self.instance.runner.returncode
             if returncode is not None:
-                # We're managing a binary which has terminated, so restart it.
-                self.instance.restart()
+                # We're managing a binary which has terminated, so start it again.
+                self.instance.start()
 
         self.client = transport.TcpTransport(
             self.host,
             self.port,
             self.socket_timeout)
 
         # Call wait_for_port() before attempting to connect in
         # the event gecko hasn't started yet.
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_quit_restart.py
@@ -65,16 +65,17 @@ class TestServerQuitApplication(Marionet
 
 
 class TestQuitRestart(MarionetteTestCase):
 
     def setUp(self):
         MarionetteTestCase.setUp(self)
 
         self.pid = self.marionette.process_id
+        self.profile = self.marionette.profile
         self.session_id = self.marionette.session_id
 
         # Use a preference to check that the restart was successful. If its
         # value has not been forced, a restart will cause a reset of it.
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:")
         self.marionette.set_pref("startup.homepage_welcome_url", "about:")
 
@@ -93,49 +94,75 @@ class TestQuitRestart(MarionetteTestCase
             Components.utils.import("resource://gre/modules/Services.jsm");
             let flags = Ci.nsIAppStartup.eAttemptQuit;
             if (arguments[0]) {
               flags |= Ci.nsIAppStartup.eRestart;
             }
             Services.startup.quit(flags);
         """, script_args=(restart,))
 
-    def test_force_restart(self):
-        self.marionette.restart()
+    def test_force_clean_restart(self):
+        self.marionette.restart(clean=True)
+        self.assertNotEqual(self.marionette.profile, self.profile)
         self.assertEqual(self.marionette.session_id, self.session_id)
 
         # A forced restart will cause a new process id
         self.assertNotEqual(self.marionette.process_id, self.pid)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:")
 
+    def test_force_restart(self):
+        self.marionette.restart()
+        self.assertEqual(self.marionette.profile, self.profile)
+        self.assertEqual(self.marionette.session_id, self.session_id)
+
+        # A forced restart will cause a new process id
+        self.assertNotEqual(self.marionette.process_id, self.pid)
+        self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
+                            "about:")
+
+    def test_force_clean_quit(self):
+        self.marionette.quit(clean=True)
+
+        self.assertEqual(self.marionette.session, None)
+        with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
+            self.marionette.get_url()
+
+        self.marionette.start_session()
+        self.assertNotEqual(self.marionette.profile, self.profile)
+        self.assertNotEqual(self.marionette.session_id, self.session_id)
+        self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
+                            "about:")
+
     def test_force_quit(self):
         self.marionette.quit()
 
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
+        self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:")
 
     @skip("Bug 1363368 - Wrong window handles after in_app restarts")
-    def test_in_app_clean_restart(self):
+    def test_no_in_app_clean_restart(self):
         # Test that in_app and clean cannot be used in combination
         with self.assertRaises(ValueError):
             self.marionette.restart(in_app=True, clean=True)
 
     @skip("Bug 1363368 - Wrong window handles after in_app restarts")
     def test_in_app_restart(self):
         if self.marionette.session_capabilities["platformName"] != "windows_nt":
             skip("Bug 1363368 - Wrong window handles after in_app restarts")
 
         self.marionette.restart(in_app=True)
+        self.assertEqual(self.marionette.profile, self.profile)
         self.assertEqual(self.marionette.session_id, self.session_id)
 
         # An in-app restart will keep the same process id only on Linux
         if self.marionette.session_capabilities["platformName"] == "linux":
             self.assertEqual(self.marionette.process_id, self.pid)
         else:
             self.assertNotEqual(self.marionette.process_id, self.pid)
 
@@ -145,16 +172,17 @@ class TestQuitRestart(MarionetteTestCase
     @skip("Bug 1363368 - Wrong window handles after in_app restarts")
     def test_in_app_restart_with_callback(self):
         if self.marionette.session_capabilities["platformName"] != "windows_nt":
             skip("Bug 1363368 - Wrong window handles after in_app restarts")
 
         self.marionette.restart(in_app=True,
                                 callback=lambda: self.shutdown(restart=True))
 
+        self.assertEqual(self.marionette.profile, self.profile)
         self.assertEqual(self.marionette.session_id, self.session_id)
 
         # An in-app restart will keep the same process id only on Linux
         if self.marionette.session_capabilities["platformName"] == "linux":
             self.assertEqual(self.marionette.process_id, self.pid)
         else:
             self.assertNotEqual(self.marionette.process_id, self.pid)
 
@@ -181,31 +209,33 @@ class TestQuitRestart(MarionetteTestCase
 
         self.marionette.quit(in_app=True)
 
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
+        self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:")
 
     @skip("Bug 1363368 - Wrong window handles after in_app restarts")
     def test_in_app_quit_with_callback(self):
         if self.marionette.session_capabilities["platformName"] != "windows_nt":
             skip("Bug 1363368 - Wrong window handles after in_app restarts")
 
         self.marionette.quit(in_app=True, callback=self.shutdown)
         self.assertEqual(self.marionette.session, None)
         with self.assertRaisesRegexp(errors.MarionetteException, "Please start a session"):
             self.marionette.get_url()
 
         self.marionette.start_session()
+        self.assertEqual(self.marionette.profile, self.profile)
         self.assertNotEqual(self.marionette.session_id, self.session_id)
         self.assertNotEqual(self.marionette.get_pref("startup.homepage_welcome_url"),
                             "about:")
 
     def test_in_app_quit_with_callback_no_shutdown(self):
         try:
             timeout = self.marionette.DEFAULT_SHUTDOWN_TIMEOUT
             self.marionette.DEFAULT_SHUTDOWN_TIMEOUT = 10