Bug 1480612: Test Register Application Restart more thoroughly. r=whimboo
authorAdam Gashlin <agashlin@mozilla.com>
Mon, 06 Aug 2018 14:40:00 -0700
changeset 430401 e669c95818bdd82332bcfe99f8a1d7a73e116639
parent 430400 834bd9d6c31b60b7331ef893801e32563f4f82b4
child 430402 09871ad4c346bb477b4c2346b8971bb57329351c
push id106155
push useragashlin@mozilla.com
push dateTue, 07 Aug 2018 19:09:33 +0000
treeherdermozilla-inbound@e669c95818bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo
bugs1480612
milestone63.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 1480612: Test Register Application Restart more thoroughly. r=whimboo
testing/firefox-ui/tests/functional/sessionstore/session_store_test_case.py
testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_windows_shutdown.py
--- a/testing/firefox-ui/tests/functional/sessionstore/session_store_test_case.py
+++ b/testing/firefox-ui/tests/functional/sessionstore/session_store_test_case.py
@@ -3,17 +3,18 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 from firefox_puppeteer import PuppeteerMixin
 from marionette_harness import MarionetteTestCase
 
 
 class SessionStoreTestCase(PuppeteerMixin, MarionetteTestCase):
 
-    def setUp(self, startup_page=1, include_private=True, no_auto_updates=True):
+    def setUp(self, startup_page=1, include_private=True, no_auto_updates=True,
+              win_register_restart=False):
         super(SessionStoreTestCase, self).setUp()
         # Each list element represents a window of tabs loaded at
         # some testing URL
         self.test_windows = set([
             # Window 1. Note the comma after the absolute_url call -
             # this is Python's way of declaring a 1 item tuple.
             (self.marionette.absolute_url('layout/mozilla.html'), ),
 
@@ -40,16 +41,18 @@ class SessionStoreTestCase(PuppeteerMixi
             'browser.startup.page': startup_page,
             # Make the content load right away instead of waiting for
             # the user to click on the background tabs
             'browser.sessionstore.restore_on_demand': False,
             # Avoid race conditions by having the content process never
             # send us session updates unless the parent has explicitly asked
             # for them via the TabStateFlusher.
             'browser.sessionstore.debug.no_auto_updates': no_auto_updates,
+            # Whether to enable the register application restart mechanism.
+            'toolkit.winRegisterApplicationRestart': win_register_restart,
         })
 
         self.all_windows = self.test_windows.copy()
         self.open_windows(self.test_windows)
 
         if include_private:
             self.all_windows.update(self.private_windows)
             self.open_windows(self.private_windows, is_private=True)
@@ -87,17 +90,16 @@ class SessionStoreTestCase(PuppeteerMixi
                This would take the currently open window, and load
                mozilla_1.html and mozilla_2.html in new tabs. It would
                then open a new, second window, and load tabs at
                mozilla_3.html and mozilla_4.html.
         @param is_private (boolean, optional)
                Whether or not any new windows should be a private browsing
                windows.
         """
-
         if (is_private):
             win = self.browser.open_browser(is_private=True)
             win.switch_to()
         else:
             win = self.browser
 
         for index, urls in enumerate(window_sets):
             if index > 0:
@@ -147,17 +149,16 @@ class SessionStoreTestCase(PuppeteerMixi
         return opened_windows
 
     def simulate_os_shutdown(self):
         """ Simulate an OS shutdown.
 
         :raises: Exception: if not supported on the current platform
         :raises: WindowsError: if a Windows API call failed
         """
-
         if self.marionette.session_capabilities['platformName'] != 'windows':
             raise Exception('Unsupported platform for simulate_os_shutdown')
 
         self._shutdown_with_windows_restart_manager(self.marionette.process_id)
 
     def _shutdown_with_windows_restart_manager(self, pid):
         """ Shut down a process using the Windows Restart Manager.
 
@@ -170,17 +171,16 @@ class SessionStoreTestCase(PuppeteerMixi
 
         This function starts a Restart Manager session, registers the
         process as a resource, and shuts down the process.
 
         :param pid: The process id (int) of the process to shutdown
 
         :raises: WindowsError: if a Windows API call fails
         """
-
         import ctypes
         from ctypes import Structure, POINTER, WINFUNCTYPE, windll, pointer, WinError
         from ctypes.wintypes import HANDLE, DWORD, BOOL, WCHAR, UINT, ULONG, LPCWSTR
 
         # set up Windows SDK types
         OpenProcess = windll.kernel32.OpenProcess
         OpenProcess.restype = HANDLE
         OpenProcess.argtypes = [DWORD,  # dwDesiredAccess
@@ -278,8 +278,55 @@ class SessionStoreTestCase(PuppeteerMixi
 
             # Shut down all processes using registered resources
             if RmShutdown(dwSessionHandle, 0,
                           ctypes.cast(None, RM_WRITE_STATUS_CALLBACK)) != ERROR_SUCCESS:
                 raise WinError()
 
         finally:
             RmEndSession(dwSessionHandle)
+
+    def windows_shutdown_with_variety(self, restart_by_os, expect_restore):
+        """ Test restoring windows after Windows shutdown.
+
+        Opens a set of windows, both standard and private, with
+        some number of tabs in them. Once the tabs have loaded, shuts down
+        the browser with the Windows Restart Manager and restarts the browser.
+
+        This specifically exercises the Windows synchronous shutdown mechanism,
+        which terminates the process in response to the Restart Manager's
+        WM_ENDSESSION message.
+
+        If restart_by_os is True, the -os-restarted arg is passed when restarting,
+        simulating being automatically restarted by the Restart Manager.
+
+        If expect_restore is True, this ensures that the standard tabs have been
+        restored, and that the private ones have not. Otherwise it ensures that
+        no tabs and windows have been restored.
+        """
+        current_windows_set = self.convert_open_windows_to_set()
+        self.assertEqual(current_windows_set, self.all_windows,
+                         msg='Not all requested windows have been opened. Expected {}, got {}.'
+                         .format(self.all_windows, current_windows_set))
+
+        self.marionette.quit(in_app=True, callback=lambda: self.simulate_os_shutdown())
+
+        saved_args = self.marionette.instance.app_args
+        try:
+            if restart_by_os:
+                self.marionette.instance.app_args = ['-os-restarted']
+
+            self.marionette.start_session()
+            self.marionette.set_context('chrome')
+        finally:
+            self.marionette.instance.app_args = saved_args
+
+        current_windows_set = self.convert_open_windows_to_set()
+        if expect_restore:
+            self.assertEqual(current_windows_set, self.test_windows,
+                             msg="""Non private browsing windows should have
+                             been restored. Expected {}, got {}.
+                             """.format(self.test_windows, current_windows_set))
+        else:
+            self.assertEqual(len(self.puppeteer.windows.all), 1,
+                             msg='Windows from last session shouldn`t have been restored.')
+            self.assertEqual(len(self.puppeteer.windows.current.tabbar.tabs), 1,
+                             msg='Tabs from last session shouldn`t have been restored.')
--- a/testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_windows_shutdown.py
+++ b/testing/firefox-ui/tests/functional/sessionstore/test_restore_windows_after_windows_shutdown.py
@@ -1,45 +1,69 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# add this directory to the path
-import sys
-import os
-sys.path.append(os.path.dirname(__file__))
-
-from session_store_test_case import SessionStoreTestCase
-
-
-class TestSessionStoreWindowsShutdown(SessionStoreTestCase):
-
-    def setUp(self):
-        super(TestSessionStoreWindowsShutdown, self).setUp(startup_page=3, no_auto_updates=False)
-
-    def test_with_variety(self):
-        """ Test restoring a set of windows across Windows shutdown.
-
-        Opens a set of windows, both standard and private, with
-        some number of tabs in them. Once the tabs have loaded, shuts down
-        the browser with the Windows Restart Manager, restarts the browser,
-        and then ensures that the standard tabs have been restored,
-        and that the private ones have not.
-
-        This specifically exercises the Windows synchronous shutdown
-        mechanism, which terminates the process in response to the
-        Restart Manager's WM_ENDSESSION message.
-        """
-
-        current_windows_set = self.convert_open_windows_to_set()
-        self.assertEqual(current_windows_set, self.all_windows,
-                         msg='Not all requested windows have been opened. Expected {}, got {}.'
-                         .format(self.all_windows, current_windows_set))
-
-        self.marionette.quit(in_app=True, callback=lambda: self.simulate_os_shutdown())
-        self.marionette.start_session()
-        self.marionette.set_context('chrome')
-
-        current_windows_set = self.convert_open_windows_to_set()
-        self.assertEqual(current_windows_set, self.test_windows,
-                         msg="""Non private browsing windows should have
-                         been restored. Expected {}, got {}.
-                         """.format(self.test_windows, current_windows_set))
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# add this directory to the path
+import sys
+import os
+sys.path.append(os.path.dirname(__file__))
+
+from session_store_test_case import SessionStoreTestCase
+
+# We test the following combinations with simulated Windows shutdown:
+# - Start page = restore session (expect restore in all cases)
+#   - RAR (toolkit.winRegisterApplicationRestart) disabled
+#   - RAR enabled, restarted manually
+#
+# - Start page = home
+#   - RAR disabled (no restore)
+#   - RAR enabled:
+#     - restarted by OS (restore)
+#     - restarted manually (no restore)
+
+
+class TestWindowsShutdown(SessionStoreTestCase):
+    def setUp(self):
+        super(TestWindowsShutdown, self).setUp(
+                startup_page=3,
+                no_auto_updates=False)
+
+    def test_with_variety(self):
+        """Test session restore selected by user."""
+        self.windows_shutdown_with_variety(restart_by_os=False, expect_restore=True)
+
+
+class TestWindowsShutdownRegisterRestart(SessionStoreTestCase):
+    def setUp(self):
+        super(TestWindowsShutdownRegisterRestart, self).setUp(
+                startup_page=3,
+                no_auto_updates=False,
+                win_register_restart=True)
+
+    def test_manual_restart(self):
+        """Test that restore tabs works in case of register restart failure."""
+        self.windows_shutdown_with_variety(restart_by_os=False, expect_restore=True)
+
+
+class TestWindowsShutdownNormal(SessionStoreTestCase):
+    def setUp(self):
+        super(TestWindowsShutdownNormal, self).setUp(
+                no_auto_updates=False)
+
+    def test_with_variety(self):
+        """Test that windows are not restored on a normal restart."""
+        self.windows_shutdown_with_variety(restart_by_os=False, expect_restore=False)
+
+
+class TestWindowsShutdownForcedSessionRestore(SessionStoreTestCase):
+    def setUp(self):
+        super(TestWindowsShutdownForcedSessionRestore, self).setUp(
+                no_auto_updates=False,
+                win_register_restart=True)
+
+    def test_os_restart(self):
+        """Test that register application restart restores the session."""
+        self.windows_shutdown_with_variety(restart_by_os=True, expect_restore=True)
+
+    def test_manual_restart(self):
+        """Test that OS shutdown is ignored on manual start."""
+        self.windows_shutdown_with_variety(restart_by_os=False, expect_restore=False)