solenv/gbuild/UITest.mk        |    6 ++++++
 sw/UITest_sw_styleInspector.mk |    2 ++
 uitest/test_main.py            |   12 ++++++++++--
 uitest/uitest/framework.py     |   28 ++++++++++++++++++++--------
 uitest/uitest/test.py          |   13 ++++++++++++-
 5 files changed, 50 insertions(+), 11 deletions(-)

New commits:
commit f5d97d14a2169c23b801d5d09ea19c001d36bba1
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Mar 20 08:14:13 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Mar 20 12:40:22 2023 +0000

    uitest: add a way to optionally use the same soffice process for a testsuite
    
    A uitest suite may have several testcases and we spend a lot of time
    spinning up a new soffice process for each testcase, while we typically
    do such initialization only once for per testsuites in the cppunit case,
    slowing down uitests.
    
    The problem is that this way today's uitest cases don't really have to
    clean up after themselves, since they know that the next testcase will
    gets its own clean state (back to the start center).
    
    Fix the problem by adding an opt-in way, so that a uitest suite can
    declare that it's safe to run the entire suite with the same soffice
    process. To be more specific:
    - add a new --oneprocess for test_main.py, which will create a shared
      connection to a soffice process
    - UITest then closes the document (returning to the start center)
      instead of disposing the component in the oneprocess case
    - UITestCase won't create its own soffice connection in the oneprocess
      case
    - add a new gb_UITest_use_oneprocess method to gbuild, to request this
      new, faster behavior
    E.g. on my machine this means UITest_sw_styleInspector takes 26,345s
    instead of 40,652s, probably such a speedup is worth the added
    complexity.
    
    This works nicely when the testsuite is a list of simple/boring test
    cases, always loading one component/document at a time and always using
    close_doc() to close it. It may not be safe for testsuites that do
    something special (they may fail or hang), we'll see.
    
    Change-Id: Ib14439d48aa547c92652245ee1c0cf37d2d7b6e7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149134
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/solenv/gbuild/UITest.mk b/solenv/gbuild/UITest.mk
index 0a08939239b8..3b78b1356d90 100644
--- a/solenv/gbuild/UITest.mk
+++ b/solenv/gbuild/UITest.mk
@@ -80,6 +80,7 @@ else
                $(gb_TEST_ENV_VARS) \
                $(gb_UITest_COMMAND) \
                --soffice="$(gb_UITest_SOFFICEARG)" \
+               $(if $(ONEPROCESS),--oneprocess) \
                --userdir=$(call gb_Helper_make_url,$(dir $(call 
gb_UITest_get_target,$*))user) \
                --dir=$(strip $(MODULES)) \
                $(gb_UITest_GDBTRACE) \
@@ -104,6 +105,7 @@ $(call gb_UITest_get_target,$(1)) : MODULES :=
 $(eval $(call gb_TestHelpers_use_more_fonts,$(call gb_UITest_get_target,$(1))))
 $(eval $(call gb_Module_register_target,$(call 
gb_UITest_get_target,$(1)),$(call gb_UITest_get_clean_target,$(1))))
 $(call gb_Helper_make_userfriendly_targets,$(1),UITest)
+$(call gb_UITest_get_target,$(1)) : ONEPROCESS := $(false)
 
 endef
 
@@ -133,6 +135,10 @@ define gb_UITest_use_configuration
 $(call gb_UITest_get_target,$(1)) : gb_UITest_use_config := $(2)
 endef
 
+define gb_UITest_use_oneprocess
+$(call gb_UITest_get_target,$(1)) : ONEPROCESS := $(true)
+endef
+
 
 else # DISABLE_PYTHON
 
diff --git a/sw/UITest_sw_styleInspector.mk b/sw/UITest_sw_styleInspector.mk
index d255dfbd756f..667482649619 100644
--- a/sw/UITest_sw_styleInspector.mk
+++ b/sw/UITest_sw_styleInspector.mk
@@ -14,3 +14,5 @@ $(eval $(call 
gb_UITest_add_modules,sw_styleInspector,$(SRCDIR)/sw/qa/uitest,\
 $(eval $(call gb_UITest_set_defs,sw_styleInspector, \
     TDOC="$(SRCDIR)/sw/qa/uitest/data" \
 ))
+
+$(eval $(call gb_UITest_use_oneprocess,sw_styleInspector))
diff --git a/uitest/test_main.py b/uitest/test_main.py
index 511f2a5c8bd4..1957f54dc373 100644
--- a/uitest/test_main.py
+++ b/uitest/test_main.py
@@ -16,12 +16,13 @@ import types
 from uitest.framework import UITestCase
 
 from libreoffice.connection import OfficeConnection
+from libreoffice.connection import PersistentConnection
 
 test_name_limit_found = False
 
 def parseArgs(argv):
     (optlist,args) = getopt.getopt(argv[1:], "hr",
-            ["help", "soffice=", "userdir=", "dir=", "file=", "gdb"])
+            ["help", "soffice=", "oneprocess", "userdir=", "dir=", "file=", 
"gdb"])
     return (dict(optlist), args)
 
 def usage():
@@ -94,7 +95,7 @@ def add_tests_for_file(test_file, test_suite):
                     continue
                 test_name_limit_found = True
 
-            obj = c(test_name, opts)
+            obj = c(test_name, opts, connection)
             test_suite.addTest(obj)
 
 def get_test_suite_for_dir(opts):
@@ -108,6 +109,10 @@ def get_test_suite_for_dir(opts):
 
 if __name__ == '__main__':
     (opts,args) = parseArgs(sys.argv)
+    connection = None
+    if "--oneprocess" in opts:
+        connection = PersistentConnection(opts)
+        connection.setUp()
     if "-h" in opts or "--help" in opts:
         usage()
         sys.exit()
@@ -135,6 +140,9 @@ if __name__ == '__main__':
     print("Tests failed: %d" % len(result.failures))
     print("Tests errors: %d" % len(result.errors))
     print("Tests skipped: %d" % len(result.skipped))
+    if connection:
+        connection.tearDown()
+        connection.kill()
     if not result.wasSuccessful():
         sys.exit(1)
     sys.exit(0)
diff --git a/uitest/uitest/framework.py b/uitest/uitest/framework.py
index 072ff5097dbf..0bb6d3ecdbf7 100644
--- a/uitest/uitest/framework.py
+++ b/uitest/uitest/framework.py
@@ -15,19 +15,29 @@ from libreoffice.connection import PersistentConnection
 
 class UITestCase(unittest.TestCase):
 
-    def __init__(self, test_name, opts):
+    def __init__(self, test_name, opts, connection=None):
         unittest.TestCase.__init__(self, test_name)
         self.opts = opts
+        self.parent_connection = connection
+        self.connection = None
+
+    def getConnection(self):
+        if self.parent_connection:
+            return self.parent_connection
+        return self.connection
 
     def setUp(self):
         self.setSignalHandler()
-        self.connection = PersistentConnection(self.opts)
-        self.connection.setUp()
-        self.xContext = self.connection.getContext()
+        if not self.getConnection():
+            self.connection = PersistentConnection(self.opts)
+            self.connection.setUp()
+        self.xContext = self.getConnection().getContext()
         self.xUITest = self.xContext.ServiceManager.createInstanceWithContext(
                 "org.libreoffice.uitest.UITest", self.xContext)
 
         self.ui_test = UITest(self.xUITest, self.xContext)
+        if self.parent_connection:
+            self.ui_test.set_use_dispose(False)
         self.startTime = time.time()
 
     def tearDown(self):
@@ -43,14 +53,16 @@ class UITestCase(unittest.TestCase):
                 except Exception as e:
                     print(e)
 
-            self.connection.tearDown()
+            if self.connection:
+                self.connection.tearDown()
         finally:
             self.resetSignalHandler()
-            self.connection.kill()
+            if self.connection:
+                self.connection.kill()
 
     def signalHandler(self, signum, frame):
-        if self.connection:
-            self.connection.kill()
+        if self.getConnection():
+            self.getConnection().kill()
 
     def setSignalHandler(self):
         signal.signal(signal.SIGABRT, self.signalHandler)
diff --git a/uitest/uitest/test.py b/uitest/uitest/test.py
index b718c84bee5e..207969d5213b 100644
--- a/uitest/uitest/test.py
+++ b/uitest/uitest/test.py
@@ -22,6 +22,10 @@ class UITest(object):
         self._xUITest = xUITest
         self._xContext = xContext
         self._desktop = None
+        self.use_dispose = True
+
+    def set_use_dispose(self, use_dispose):
+        self.use_dispose = use_dispose
 
     def get_desktop(self):
         if self._desktop:
@@ -207,7 +211,14 @@ class UITest(object):
         if not component:
             print("close_doc: active frame has no component")
             return
-        component.dispose()
+        if self.use_dispose:
+            component.dispose()
+        else:
+            if component.isModified():
+                with self.execute_dialog_through_command('.uno:CloseDoc', 
close_button="discard") as xConfirmationDialog:
+                    pass
+            else:
+                self._xUITest.executeCommand(".uno:CloseDoc")
         frames = desktop.getFrames()
         if frames:
             frames[0].activate()

Reply via email to