include/unotest/macros_test.hxx          |    7 --
 pyuno/source/module/pyuno_impl.hxx       |    1 
 pyuno/source/module/pyuno_module.cxx     |   61 ++++++++++++++++++++
 solenv/gbuild/UITest.mk                  |    7 +-
 uitest/libreoffice/connection.py         |    2 
 unotest/source/cpp/macros_test.cxx       |   93 ++++++++++++++++++++++++-------
 xmlsecurity/UITest_xmlsecurity_gpg.mk    |    3 +
 xmlsecurity/qa/uitest/gpg/encrypt.py     |   20 ++++++
 xmlsecurity/qa/unit/signing/signing.cxx  |    2 
 xmlsecurity/qa/unit/signing/signing2.cxx |    2 
 10 files changed, 168 insertions(+), 30 deletions(-)

New commits:
commit 8ed755cfb0779c3e1119d17a7877768af1a01682
Author:     Michael Stahl <[email protected]>
AuthorDate: Wed Jul 31 14:42:57 2024 +0200
Commit:     Michael Stahl <[email protected]>
CommitDate: Thu Aug 1 11:18:30 2024 +0200

    pyuno,unotest,xmlsecurity: copy GPG test files for UITtest
    
    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 <[email protected]>
    Reviewed-by: Michael Stahl <[email protected]>
    Tested-by: Jenkins

diff --git a/include/unotest/macros_test.hxx b/include/unotest/macros_test.hxx
index cf667125e8f0..663fcf22b68d 100644
--- a/include/unotest/macros_test.hxx
+++ b/include/unotest/macros_test.hxx
@@ -98,8 +98,8 @@ public:
 
     // note: there is no tearDownX509
     void setUpX509(const test::Directories& rDirectories, const OUString& 
rTestName);
-    void setUpGpg(const test::Directories& rDirectories, const OUString& 
rTestName);
-    void tearDownGpg();
+    static void setUpGpg(const test::Directories& rDirectories, 
std::u16string_view rTestName);
+    static void tearDownGpg();
 
     static bool IsValid(const 
css::uno::Reference<css::security::XCertificate>& cert,
                         const 
css::uno::Reference<css::xml::crypto::XSecurityEnvironment>& env);
@@ -113,9 +113,6 @@ protected:
 
 private:
     std::unique_ptr<BasicDLL> mpDll;
-#if HAVE_GPGCONF_SOCKETDIR
-    OString m_gpgconfCommandPrefix;
-#endif
 };
 }
 
diff --git a/pyuno/source/module/pyuno_impl.hxx 
b/pyuno/source/module/pyuno_impl.hxx
index 946991c3864b..878367d3764a 100644
--- a/pyuno/source/module/pyuno_impl.hxx
+++ b/pyuno/source/module/pyuno_impl.hxx
@@ -222,6 +222,7 @@ struct RuntimeCargo
     css::uno::Reference< css::beans::XIntrospection > xIntrospection;
     PyRef dictUnoModule;
     osl::Module testModule;
+    osl::Module unoTestModule;
     bool valid;
     ExceptionClassMap exceptionMap;
     ClassSet interfaceSet;
diff --git a/pyuno/source/module/pyuno_module.cxx 
b/pyuno/source/module/pyuno_module.cxx
index b3cdc07b4703..1fc2e8bf00a2 100644
--- a/pyuno/source/module/pyuno_module.cxx
+++ b/pyuno/source/module/pyuno_module.cxx
@@ -383,6 +383,65 @@ static PyObject* deinitTestEnvironment(
     return Py_None;
 }
 
+static PyObject* initTestEnvironmentGPG(
+    SAL_UNUSED_PARAMETER PyObject*, PyObject* args)
+{
+    // this tries to set up certificate stores for unit tests
+    // which is only possible indirectly because pyuno is URE
+    // so load "unotest" library and invoke a function there to do the work
+    Runtime const runtime;
+    osl::Module & rModule(runtime.getImpl()->cargo->unoTestModule);
+    assert(!rModule.is());
+    try
+    {
+        char *const testlib = getenv("UNOTEST_LIB");
+        if (!testlib) { abort(); }
+#ifdef _WIN32
+        OString const libname = OString(testlib, strlen(testlib))
+            .replaceAll(OString('/'), OString('\'));
+#else
+        OString const libname(testlib, strlen(testlib));
+#endif
+
+        rModule.load(OStringToOUString(libname, osl_getThreadTextEncoding()),
+                                SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL);
+        if (!rModule.is()) { abort(); }
+        oslGenericFunction const 
pFunc(rModule.getFunctionSymbol("test_init_gpg"));
+        if (!pFunc) { abort(); }
+        char * pTestDirURL;
+        if (!PyArg_ParseTuple(args, "s", &pTestDirURL)) { abort(); }
+        OUString const testDirURL(OUString::createFromAscii(pTestDirURL));
+        reinterpret_cast<void (SAL_CALL *)(OUString 
const&)>(pFunc)(testDirURL);
+    }
+    catch (const css::uno::Exception &)
+    {
+        abort();
+    }
+    return Py_None;
+}
+
+static PyObject* deinitTestEnvironmentGPG(
+    SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*)
+{
+    Runtime const runtime;
+    osl::Module & rModule(runtime.getImpl()->cargo->unoTestModule);
+    if (rModule.is())
+    {
+        try
+        {
+            oslGenericFunction const pFunc(
+                    rModule.getFunctionSymbol("test_deinit_gpg"));
+            if (!pFunc) { abort(); }
+            reinterpret_cast<void (SAL_CALL *)()>(pFunc)();
+        }
+        catch (const css::uno::Exception &)
+        {
+            abort();
+        }
+    }
+    return Py_None;
+}
+
 PyObject * extractOneStringArg( PyObject *args, char const *funcName )
 {
     if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 )
@@ -852,6 +911,8 @@ struct PyMethodDef PyUNOModule_methods [] =
 {
     {"private_initTestEnvironment", initTestEnvironment, METH_VARARGS, 
nullptr},
     {"private_deinitTestEnvironment", deinitTestEnvironment, METH_VARARGS, 
nullptr},
+    {"private_initTestEnvironmentGPG", initTestEnvironmentGPG, METH_VARARGS, 
nullptr},
+    {"private_deinitTestEnvironmentGPG", deinitTestEnvironmentGPG, 
METH_VARARGS, nullptr},
     {"getComponentContext", getComponentContext, METH_VARARGS, nullptr},
 #if defined __clang__
 #pragma clang diagnostic push
diff --git a/solenv/gbuild/UITest.mk b/solenv/gbuild/UITest.mk
index 300c28b350ea..282df21b9112 100644
--- a/solenv/gbuild/UITest.mk
+++ b/solenv/gbuild/UITest.mk
@@ -41,9 +41,6 @@ gb_UITest_COMMAND = $(ICECREAM_RUN) 
$(gb_CppunitTest_coredumpctl_run) $(gb_Cppun
 
 gb_TEST_ENV_VARS += LIBO_LANG=C
 
-# GNUPGHOME is needed for tests using the LibreOffice GPG features.
-gb_TEST_ENV_VARS += GNUPGHOME="$(SRCDIR)/test/signing-keys"
-
 .PHONY : $(call gb_UITest_get_clean_target,%)
 $(call gb_UITest_get_clean_target,%) :
        $(call gb_Helper_abbreviate_dirs,\
@@ -51,6 +48,9 @@ $(call gb_UITest_get_clean_target,%) :
 
 ifneq ($(DISABLE_PYTHON),TRUE)
 
+# dlopening unotest requires this
+gb_UITest_PRECOMMAND = $(gb_PythonTest_PRECOMMAND)
+
 # qadevOOo/qa/registrymodifications.xcu is copied to user profile directory to 
ensure en_US locale;
 # this might be overwritten later when gb_UITest_use_config is set
 .PHONY : $(call gb_UITest_get_target,%)
@@ -73,6 +73,7 @@ else
                $(DEFS) \
                $(if $(filter WNT,$(OS)),SAL_LOG_FILE="$(dir $(call 
gb_UITest_get_target,$*))/soffice.out.log") \
                TEST_LIB=$(call gb_Library_get_target,test) \
+               UNOTEST_LIB=$(call gb_Library_get_target,unotest) \
                URE_BOOTSTRAP=vnd.sun.star.pathname:$(call 
gb_Helper_get_rcfile,$(INSTROOT)/$(LIBO_ETC_FOLDER)/fundamental) \
                PYTHONPATH="$(PYPATH)" \
                TestUserDir="$(call gb_Helper_make_url,$(dir $(call 
gb_UITest_get_target,$*)))" \
diff --git a/uitest/libreoffice/connection.py b/uitest/libreoffice/connection.py
index 4f901130f223..1d1730d98d3e 100644
--- a/uitest/libreoffice/connection.py
+++ b/uitest/libreoffice/connection.py
@@ -24,7 +24,7 @@ except ImportError:
 
 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)
+    #print(f'Signal handler called with signal {signal_name} ({signal_num})', 
flush=True)
 
 class OfficeConnection:
     def __init__(self, args):
diff --git a/unotest/source/cpp/macros_test.cxx 
b/unotest/source/cpp/macros_test.cxx
index 3cf6a406735e..245ef13e5e8d 100644
--- a/unotest/source/cpp/macros_test.cxx
+++ b/unotest/source/cpp/macros_test.cxx
@@ -145,27 +145,61 @@ void MacrosTest::setUpX509(const test::Directories& 
rDirectories, const OUString
 #endif
 }
 
-void MacrosTest::setUpGpg(const test::Directories& rDirectories, const 
OUString& rTestName)
+#if HAVE_GPGCONF_SOCKETDIR
+// mutable global should be tolerable in test lib
+static OString g_gpgconfCommandPrefix;
+#endif
+
+extern "C" {
+
+SAL_DLLPUBLIC_EXPORT
+void test_init_gpg(OUString const& rTargetDir)
 {
-    OUString aSourceDir = rDirectories.getURLFromSrc(u"/test/signing-keys/");
-    OUString aTargetDir
-        = rDirectories.getURLFromWorkdir(Concat2View("CppunitTest/" + 
rTestName + ".test.user"));
+    const char* pSrcRoot = getenv("SRC_ROOT");
+    if (!pSrcRoot)
+    {
+        abort();
+    }
+    OUString const srcRootPath(OUString(pSrcRoot, strlen(pSrcRoot), 
osl_getThreadTextEncoding()));
+    OUString const sourcePath(srcRootPath + "/test/signing-keys/");
+    OUString aSourceDir;
+    osl::FileBase::RC e = osl::FileBase::getFileURLFromSystemPath(sourcePath, 
aSourceDir);
+    if (osl::FileBase::E_None != e)
+    {
+        abort();
+    }
 
     OUString aTargetPath;
-    osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath);
+    osl::FileBase::getSystemPathFromFileURL(rTargetDir, aTargetPath);
+
+    auto const rc = osl::Directory::create(rTargetDir);
+    if (osl::FileBase::E_None != rc && osl::FileBase::E_EXIST != rc)
+    {
+        SAL_WARN("test", "creating target dir failed, aborting");
+        abort();
+    }
 
     // Make gpg use our own defined setup & keys
-    osl::File::copy(aSourceDir + "pubring.gpg", aTargetDir + "/pubring.gpg");
-    osl::File::copy(aSourceDir + "random_seed", aTargetDir + "/random_seed");
-    osl::File::copy(aSourceDir + "secring.gpg", aTargetDir + "/secring.gpg");
-    osl::File::copy(aSourceDir + "trustdb.gpg", aTargetDir + "/trustdb.gpg");
+    if (osl::FileBase::E_None
+            != osl::File::copy(aSourceDir + "pubring.gpg", rTargetDir + 
"/pubring.gpg")
+        || osl::FileBase::E_None
+               != osl::File::copy(aSourceDir + "random_seed", rTargetDir + 
"/random_seed")
+        || osl::FileBase::E_None
+               != osl::File::copy(aSourceDir + "secring.gpg", rTargetDir + 
"/secring.gpg")
+        || osl::FileBase::E_None
+               != osl::File::copy(aSourceDir + "trustdb.gpg", rTargetDir + 
"/trustdb.gpg"))
+    {
+        SAL_WARN("test", "copying files failed, aborting");
+        abort();
+    }
 
+    // note: this doesn't work for UITest because "os.environ" is a copy :(
     OUString gpgHomeVar(u"GNUPGHOME"_ustr);
     osl_setEnvironment(gpgHomeVar.pData, aTargetPath.pData);
 
 #if HAVE_GPGCONF_SOCKETDIR
     auto const ldPath = std::getenv("LIBO_LD_PATH");
-    m_gpgconfCommandPrefix
+    g_gpgconfCommandPrefix
         = ldPath == nullptr ? OString() : OString::Concat("LD_LIBRARY_PATH=") 
+ ldPath + " ";
     OString path;
     bool ok = aTargetPath.convertToString(&path, osl_getThreadTextEncoding(),
@@ -173,32 +207,53 @@ void MacrosTest::setUpGpg(const test::Directories& 
rDirectories, const OUString&
                                               | 
RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
     // if conversion fails, at least provide a best-effort conversion in the 
message here, for
     // context
-    CPPUNIT_ASSERT_MESSAGE(OUStringToOString(aTargetPath, 
RTL_TEXTENCODING_UTF8).getStr(), ok);
-    m_gpgconfCommandPrefix += "GNUPGHOME=" + path + " " GPGME_GPGCONF;
+    if (!ok)
+    {
+        SAL_WARN("test", "converting path failed, aborting: " << aTargetPath);
+        abort();
+    }
+    g_gpgconfCommandPrefix += "GNUPGHOME=" + path + " " GPGME_GPGCONF;
     // HAVE_GPGCONF_SOCKETDIR is only defined in configure.ac for Linux for 
now, so (a) std::system
     // behavior will conform to POSIX (and the relevant env var to set is 
named LD_LIBRARY_PATH), and
     // (b) gpgconf --create-socketdir should return zero:
-    OString cmd = m_gpgconfCommandPrefix + " --create-socketdir";
+    OString cmd = g_gpgconfCommandPrefix + " --create-socketdir";
     int res = std::system(cmd.getStr());
-    CPPUNIT_ASSERT_EQUAL_MESSAGE(cmd.getStr(), 0, res);
+    if (res != 0)
+    {
+        SAL_WARN("test", "invoking gpgconf failed, aborting: " << cmd);
+        abort();
+    }
 #else
-    (void)this;
+    (void)rTargetDir;
 #endif
 }
 
-void MacrosTest::tearDownGpg()
+SAL_DLLPUBLIC_EXPORT void test_deinit_gpg()
 {
 #if HAVE_GPGCONF_SOCKETDIR
     // HAVE_GPGCONF_SOCKETDIR is only defined in configure.ac for Linux for 
now, so (a) std::system
     // behavior will conform to POSIX, and (b) gpgconf --remove-socketdir 
should return zero:
-    OString cmd = m_gpgconfCommandPrefix + " --remove-socketdir";
+    CPPUNIT_ASSERT(!g_gpgconfCommandPrefix.isEmpty());
+    OString cmd = g_gpgconfCommandPrefix + " --remove-socketdir";
     int res = std::system(cmd.getStr());
     CPPUNIT_ASSERT_EQUAL_MESSAGE(cmd.getStr(), 0, res);
-#else
-    (void)this;
+    g_gpgconfCommandPrefix.clear();
 #endif
 }
 
+} // extern "C"
+
+void MacrosTest::setUpGpg(const test::Directories& rDirectories,
+                          std::u16string_view const rTestName)
+{
+    OUString aTargetDir = rDirectories.getURLFromWorkdir(
+        Concat2View("CppunitTest/" + OUString(rTestName.data(), 
rTestName.size()) + ".test.user"));
+
+    return test_init_gpg(aTargetDir);
+}
+
+void MacrosTest::tearDownGpg() { return test_deinit_gpg(); }
+
 namespace
 {
 struct Valid
diff --git a/xmlsecurity/UITest_xmlsecurity_gpg.mk 
b/xmlsecurity/UITest_xmlsecurity_gpg.mk
index 90cb75bee813..4603ca7ede6a 100644
--- a/xmlsecurity/UITest_xmlsecurity_gpg.mk
+++ b/xmlsecurity/UITest_xmlsecurity_gpg.mk
@@ -17,4 +17,7 @@ $(eval $(call gb_UITest_set_defs,xmlsecurity_gpg, \
     TDOC="$(SRCDIR)/xmlsecurity/qa/uitest/data" \
 ))
 
+# oneprocess prevents setting GNUPGHOME
+$(eval $(call gb_UITest_avoid_oneprocess,xmlsecurity_gpg))
+
 # vim: set noet sw=4 ts=4:
diff --git a/xmlsecurity/qa/uitest/gpg/encrypt.py 
b/xmlsecurity/qa/uitest/gpg/encrypt.py
index ca2fa5f87f9c..70c9c0e9ffc1 100644
--- a/xmlsecurity/qa/uitest/gpg/encrypt.py
+++ b/xmlsecurity/qa/uitest/gpg/encrypt.py
@@ -9,8 +9,11 @@
 
 from uitest.framework import UITestCase
 from libreoffice.uno.propertyvalue import mkPropertyValues
+import pyuno
 
 from tempfile import TemporaryDirectory
+from urllib.parse import urljoin, urlparse
+from urllib.request import url2pathname
 import os.path
 
 
@@ -19,6 +22,23 @@ import os.path
 # Requires the environment variable GNUPGHOME to be set correctly.
 # See solenv/gbuild/UITest.mk
 class GpgEncryptTest(UITestCase):
+
+    # should this be setUp() or setUpClass()?
+    # as setUp(), any test's change to the files should be overwritten before
+    # the next test, which could be an advantage.
+    def setUp(self):
+        testdir = os.getenv("TestUserDir")
+        certdir = urljoin(testdir, "signing-keys")
+        # this sets GNUPGHOME so do it before starting soffice
+        pyuno.private_initTestEnvironmentGPG(certdir)
+        # ugly: set var here again because "os.environ" is a copy :(
+        os.environ["GNUPGHOME"] = url2pathname(urlparse(certdir).path)
+        super().setUp()
+
+    def tearDown(self):
+        super().tearDown()
+        pyuno.private_deinitTestEnvironmentGPG()
+
     def test_gpg_encrypt(self):
         # TODO: Maybe deduplicate with 
sw/qa/uitest/writer_tests8/save_with_password_test_policy.py
         with TemporaryDirectory() as tempdir:
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx 
b/xmlsecurity/qa/unit/signing/signing.cxx
index 9f303e0286ff..25da7b3eb334 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -92,7 +92,7 @@ void SigningTest::setUp()
     UnoApiXmlTest::setUp();
 
     MacrosTest::setUpX509(m_directories, u"xmlsecurity_signing"_ustr);
-    MacrosTest::setUpGpg(m_directories, u"xmlsecurity_signing"_ustr);
+    MacrosTest::setUpGpg(m_directories, 
std::u16string_view(u"xmlsecurity_signing"));
 
     // Initialize crypto after setting up the environment variables.
     mxSEInitializer = xml::crypto::SEInitializer::create(m_xContext);
diff --git a/xmlsecurity/qa/unit/signing/signing2.cxx 
b/xmlsecurity/qa/unit/signing/signing2.cxx
index c84fa0b1051a..e4b7aa89f881 100644
--- a/xmlsecurity/qa/unit/signing/signing2.cxx
+++ b/xmlsecurity/qa/unit/signing/signing2.cxx
@@ -57,7 +57,7 @@ void SigningTest2::setUp()
     UnoApiXmlTest::setUp();
 
     MacrosTest::setUpX509(m_directories, u"xmlsecurity_signing2"_ustr);
-    MacrosTest::setUpGpg(m_directories, u"xmlsecurity_signing2"_ustr);
+    MacrosTest::setUpGpg(m_directories, 
std::u16string_view(u"xmlsecurity_signing2"));
 
     // Initialize crypto after setting up the environment variables.
     mxSEInitializer = xml::crypto::SEInitializer::create(m_xContext);

Reply via email to