tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / uitest / libreoffice / connection.py
blob1d1730d98d3ea15f70a46fcfb64adb25223c7651
1 # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 import subprocess
9 import time
10 import traceback
11 import uuid
12 import os
13 import platform
14 import signal
16 try:
17 import pyuno
18 import uno
19 except ImportError:
20 print("pyuno not found: try to set PYTHONPATH and URE_BOOTSTRAP variables", flush=True)
21 print("PYTHONPATH=/installation/opt/program", flush=True)
22 print("URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc", flush=True)
23 raise
25 def signal_handler(signal_num, frame):
26 signal_name = signal.Signals(signal_num).name
27 #print(f'Signal handler called with signal {signal_name} ({signal_num})', flush=True)
29 class OfficeConnection:
30 def __init__(self, args):
31 self.args = args
32 self.soffice = None
33 self.xContext = None
35 def setUp(self):
36 """ Create a new connection to a LibreOffice process
38 If the connection method is path the instance will be created as a
39 new subprocess. If the connection method is connect the instance tries
40 to connect to an existing instance with the specified socket string """
41 if platform.system() != "Windows":
42 signal.signal(signal.SIGCHLD, signal_handler)
43 signal.signal(signal.SIGPIPE, signal_handler)
45 (method, sep, rest) = self.args["--soffice"].partition(":")
46 if sep != ":":
47 raise Exception("soffice parameter does not specify method")
48 if method == "path":
49 socket = "pipe,name=pytest" + str(uuid.uuid1())
50 try:
51 userdir = self.args["--userdir"]
52 except KeyError:
53 raise Exception("'path' method requires --userdir")
54 if not(userdir.startswith("file://")):
55 raise Exception("--userdir must be file URL")
56 self.soffice = self.bootstrap(rest, userdir, socket)
57 elif method == "connect":
58 socket = rest
59 else:
60 raise Exception("unsupported connection method: " + method)
62 # connect to the soffice instance
63 success = False
64 try:
65 self.xContext = self.connect(socket)
66 success = True
67 finally:
68 if not success and self.soffice:
69 self.soffice.terminate()
70 self.soffice.wait()
71 self.soffice = None
73 def bootstrap(self, soffice, userdir, socket):
74 """ Creates a new LibreOffice process
76 @param soffice Path to the soffice installation
77 @param userdir Directory of the user profile, only one process per user
78 profile is possible
79 @param socket The socket string used for the PyUNO connection """
81 argv = [soffice, "--accept=" + socket + ";urp",
82 "-env:UserInstallation=" + userdir,
83 "--quickstart=no", "--nofirststartwizard",
84 "--norestore", "--nologo"]
85 if "--valgrind" in self.args:
86 argv.append("--valgrind")
88 if "--gdb" in self.args:
89 argv.insert(0, "gdb")
90 argv.insert(1, "-ex")
91 argv.insert(2, "run")
92 argv.insert(3, "--args")
93 argv[4] = argv[4].replace("soffice", "soffice.bin")
95 env = None
96 environ = dict(os.environ)
97 if 'LIBO_LANG' in environ:
98 env = environ
99 env['LC_ALL'] = environ['LIBO_LANG']
101 return subprocess.Popen(argv, env=env)
103 def connect(self, socket):
104 """ Tries to connect to the LibreOffice instance through the specified socket"""
105 xLocalContext = uno.getComponentContext()
106 xUnoResolver = xLocalContext.ServiceManager.createInstanceWithContext(
107 "com.sun.star.bridge.UnoUrlResolver", xLocalContext)
108 url = "uno:" + socket + ";urp;StarOffice.ComponentContext"
109 print("OfficeConnection: connecting to: " + url, flush=True)
110 while True:
111 if self.soffice and self.soffice.poll() is not None:
112 raise Exception("soffice has stopped.")
114 try:
115 xContext = xUnoResolver.resolve(url)
116 return xContext
117 except pyuno.getClass("com.sun.star.connection.NoConnectException"):
118 print("NoConnectException: sleeping...", flush=True)
119 time.sleep(1)
121 def tearDown(self):
122 """Terminate a LibreOffice instance created with the path connection method.
124 Tries to terminate the soffice instance through the normal
125 XDesktop::terminate method and waits indefinitely for the subprocess
126 to terminate """
128 if self.soffice:
129 if self.xContext:
130 try:
131 print("tearDown: calling terminate()...", flush=True)
132 xMgr = self.xContext.ServiceManager
133 xDesktop = xMgr.createInstanceWithContext(
134 "com.sun.star.frame.Desktop", self.xContext)
135 xDesktop.terminate()
136 print("...done", flush=True)
137 except pyuno.getClass("com.sun.star.beans.UnknownPropertyException"):
138 print("caught while TearDown:\n", traceback.format_exc(), flush=True)
139 pass # ignore, also means disposed
140 except pyuno.getClass("com.sun.star.lang.DisposedException"):
141 print("caught while TearDown:\n", traceback.format_exc(), flush=True)
142 pass # ignore
143 else:
144 self.soffice.terminate()
146 ret = self.soffice.wait()
147 self.xContext = None
148 self.soffice = None
149 if ret != 0:
150 raise Exception("Exit status indicates failure: " + str(ret))
152 @classmethod
153 def getHelpText(cls):
154 message = """
155 --soffice=method:location
156 specify soffice instance to connect to
157 supported methods: 'path', 'connect'
158 --userdir=URL specify user installation directory for 'path' method
159 --valgrind pass --valgrind to soffice for 'path' method
161 'location' is a pathname, not a URL. 'userdir' is a URL.
163 return message
166 class PersistentConnection:
167 def __init__(self, args):
168 self.args = args
169 self.connection = None
171 def getContext(self):
172 """ Returns the XContext corresponding to the LibreOffice instance
174 This is the starting point for any PyUNO access to the LibreOffice
175 instance."""
176 return self.connection.xContext
178 def setUp(self):
179 # don't create two connections
180 if self.connection:
181 return
183 conn = OfficeConnection(self.args)
184 conn.setUp()
185 self.connection = conn
187 def tearDown(self):
188 if self.connection:
189 try:
190 self.connection.tearDown()
191 finally:
192 self.connection = None
194 def kill(self):
195 """ Kills the LibreOffice instance if it was created through the connection
197 Only works with the connection method path"""
198 if self.connection and self.connection.soffice:
199 self.connection.soffice.kill()
201 # vim: set shiftwidth=4 softtabstop=4 expandtab: