8ed755cfb0
The problem was that running UITest_xmlsecurity_gpg changed the files in test/signing-keys/ ... prevent that by copying the directory in that test, which is more complicated than initially expected. Change-Id: Ie3be922e0b2e9dae49f9a70e35ad5270c90b4fc4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171322 Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de> Reviewed-by: Michael Stahl <michael.stahl@allotropia.de> Tested-by: Jenkins
201 lines
7.3 KiB
Python
201 lines
7.3 KiB
Python
# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
|
|
#
|
|
# 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/.
|
|
#
|
|
|
|
import subprocess
|
|
import time
|
|
import traceback
|
|
import uuid
|
|
import os
|
|
import platform
|
|
import signal
|
|
|
|
try:
|
|
import pyuno
|
|
import uno
|
|
except ImportError:
|
|
print("pyuno not found: try to set PYTHONPATH and URE_BOOTSTRAP variables", flush=True)
|
|
print("PYTHONPATH=/installation/opt/program", flush=True)
|
|
print("URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc", flush=True)
|
|
raise
|
|
|
|
def signal_handler(signal_num, frame):
|
|
signal_name = signal.Signals(signal_num).name
|
|
#print(f'Signal handler called with signal {signal_name} ({signal_num})', flush=True)
|
|
|
|
class OfficeConnection:
|
|
def __init__(self, args):
|
|
self.args = args
|
|
self.soffice = None
|
|
self.xContext = None
|
|
|
|
def setUp(self):
|
|
""" Create a new connection to a LibreOffice process
|
|
|
|
If the connection method is path the instance will be created as a
|
|
new subprocess. If the connection method is connect the instance tries
|
|
to connect to an existing instance with the specified socket string """
|
|
if platform.system() != "Windows":
|
|
signal.signal(signal.SIGCHLD, signal_handler)
|
|
signal.signal(signal.SIGPIPE, signal_handler)
|
|
|
|
(method, sep, rest) = self.args["--soffice"].partition(":")
|
|
if sep != ":":
|
|
raise Exception("soffice parameter does not specify method")
|
|
if method == "path":
|
|
socket = "pipe,name=pytest" + str(uuid.uuid1())
|
|
try:
|
|
userdir = self.args["--userdir"]
|
|
except KeyError:
|
|
raise Exception("'path' method requires --userdir")
|
|
if not(userdir.startswith("file://")):
|
|
raise Exception("--userdir must be file URL")
|
|
self.soffice = self.bootstrap(rest, userdir, socket)
|
|
elif method == "connect":
|
|
socket = rest
|
|
else:
|
|
raise Exception("unsupported connection method: " + method)
|
|
|
|
# connect to the soffice instance
|
|
success = False
|
|
try:
|
|
self.xContext = self.connect(socket)
|
|
success = True
|
|
finally:
|
|
if not success and self.soffice:
|
|
self.soffice.terminate()
|
|
self.soffice.wait()
|
|
self.soffice = None
|
|
|
|
def bootstrap(self, soffice, userdir, socket):
|
|
""" Creates a new LibreOffice process
|
|
|
|
@param soffice Path to the soffice installation
|
|
@param userdir Directory of the user profile, only one process per user
|
|
profile is possible
|
|
@param socket The socket string used for the PyUNO connection """
|
|
|
|
argv = [soffice, "--accept=" + socket + ";urp",
|
|
"-env:UserInstallation=" + userdir,
|
|
"--quickstart=no", "--nofirststartwizard",
|
|
"--norestore", "--nologo"]
|
|
if "--valgrind" in self.args:
|
|
argv.append("--valgrind")
|
|
|
|
if "--gdb" in self.args:
|
|
argv.insert(0, "gdb")
|
|
argv.insert(1, "-ex")
|
|
argv.insert(2, "run")
|
|
argv.insert(3, "--args")
|
|
argv[4] = argv[4].replace("soffice", "soffice.bin")
|
|
|
|
env = None
|
|
environ = dict(os.environ)
|
|
if 'LIBO_LANG' in environ:
|
|
env = environ
|
|
env['LC_ALL'] = environ['LIBO_LANG']
|
|
|
|
return subprocess.Popen(argv, env=env)
|
|
|
|
def connect(self, socket):
|
|
""" Tries to connect to the LibreOffice instance through the specified socket"""
|
|
xLocalContext = uno.getComponentContext()
|
|
xUnoResolver = xLocalContext.ServiceManager.createInstanceWithContext(
|
|
"com.sun.star.bridge.UnoUrlResolver", xLocalContext)
|
|
url = "uno:" + socket + ";urp;StarOffice.ComponentContext"
|
|
print("OfficeConnection: connecting to: " + url, flush=True)
|
|
while True:
|
|
if self.soffice and self.soffice.poll() is not None:
|
|
raise Exception("soffice has stopped.")
|
|
|
|
try:
|
|
xContext = xUnoResolver.resolve(url)
|
|
return xContext
|
|
except pyuno.getClass("com.sun.star.connection.NoConnectException"):
|
|
print("NoConnectException: sleeping...", flush=True)
|
|
time.sleep(1)
|
|
|
|
def tearDown(self):
|
|
"""Terminate a LibreOffice instance created with the path connection method.
|
|
|
|
Tries to terminate the soffice instance through the normal
|
|
XDesktop::terminate method and waits indefinitely for the subprocess
|
|
to terminate """
|
|
|
|
if self.soffice:
|
|
if self.xContext:
|
|
try:
|
|
print("tearDown: calling terminate()...", flush=True)
|
|
xMgr = self.xContext.ServiceManager
|
|
xDesktop = xMgr.createInstanceWithContext(
|
|
"com.sun.star.frame.Desktop", self.xContext)
|
|
xDesktop.terminate()
|
|
print("...done", flush=True)
|
|
except pyuno.getClass("com.sun.star.beans.UnknownPropertyException"):
|
|
print("caught while TearDown:\n", traceback.format_exc(), flush=True)
|
|
pass # ignore, also means disposed
|
|
except pyuno.getClass("com.sun.star.lang.DisposedException"):
|
|
print("caught while TearDown:\n", traceback.format_exc(), flush=True)
|
|
pass # ignore
|
|
else:
|
|
self.soffice.terminate()
|
|
|
|
ret = self.soffice.wait()
|
|
self.xContext = None
|
|
self.soffice = None
|
|
if ret != 0:
|
|
raise Exception("Exit status indicates failure: " + str(ret))
|
|
|
|
@classmethod
|
|
def getHelpText(cls):
|
|
message = """
|
|
--soffice=method:location
|
|
specify soffice instance to connect to
|
|
supported methods: 'path', 'connect'
|
|
--userdir=URL specify user installation directory for 'path' method
|
|
--valgrind pass --valgrind to soffice for 'path' method
|
|
|
|
'location' is a pathname, not a URL. 'userdir' is a URL.
|
|
"""
|
|
return message
|
|
|
|
|
|
class PersistentConnection:
|
|
def __init__(self, args):
|
|
self.args = args
|
|
self.connection = None
|
|
|
|
def getContext(self):
|
|
""" Returns the XContext corresponding to the LibreOffice instance
|
|
|
|
This is the starting point for any PyUNO access to the LibreOffice
|
|
instance."""
|
|
return self.connection.xContext
|
|
|
|
def setUp(self):
|
|
# don't create two connections
|
|
if self.connection:
|
|
return
|
|
|
|
conn = OfficeConnection(self.args)
|
|
conn.setUp()
|
|
self.connection = conn
|
|
|
|
def tearDown(self):
|
|
if self.connection:
|
|
try:
|
|
self.connection.tearDown()
|
|
finally:
|
|
self.connection = None
|
|
|
|
def kill(self):
|
|
""" Kills the LibreOffice instance if it was created through the connection
|
|
|
|
Only works with the connection method path"""
|
|
if self.connection and self.connection.soffice:
|
|
self.connection.soffice.kill()
|
|
|
|
# vim: set shiftwidth=4 softtabstop=4 expandtab:
|