[Libreoffice-commits] online.git: Branch 'feature/paralleltest' - 16 commits - android/app common/FileUtil.cpp common/FileUtil.hpp common/Unit.cpp common/Unit.hpp common/Util.cpp kit/ForKit.cpp loleaflet/css loleaflet/images loleaflet/po loleaflet/src test/data test/DeltaTests.cpp test/helpers.hpp test/httpcrashtest.cpp test/integration-http-server.cpp test/Makefile.am test/run_unit.sh.in test/test.cpp test/test.hpp test/TileCacheTests.cpp test/UnitClient.cpp test/UnitWOPITemplate.cpp tools/Stress.cpp wsd/DocumentBroker.cpp wsd/FileServer.cpp wsd/LOOLWSD.cpp wsd/LOOLWSD.hpp wsd/Storage.cpp wsd/TraceFile.hpp

Michael Meeks (via logerrit) logerrit at kemper.freedesktop.org
Tue Jan 21 12:09:00 UTC 2020


Rebased ref, commits from common ancestor:
commit cdb5e8303aa678d066fcb6239bde4df3ec074872
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jan 21 12:08:06 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:08:06 2020 +0000

    test: forcibly serialize more.
    
    Change-Id: I2fd370c5bdd440e3be2c065f9b834ffa4e7f856b

diff --git a/test/Makefile.am b/test/Makefile.am
index a31e557b6..7f15ef069 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -240,6 +240,7 @@ unit-wopi-documentconflict.log : unit-wopi-versionrestore.log
 unit_wopi_renamefile.log : unit-wopi-documentconflict.log
 unit_wopi_watermark.log : unit_wopi_renamefile.log
 
+# parallelize a couple at least.
 unit-http.log : unit_wopi_watermark.log
 unit-tiff-load.log : unit_wopi_watermark.log
 
@@ -248,12 +249,10 @@ unit-paste.log : unit-large-paste.log
 unit-load-torture.log : unit-paste.log
 unit-rendering-options.log : unit-load-torture.log
 unit-password-protected.log : unit-rendering-options.log
-
 unit-render-shape.log : unit-password-protected.log
-unit-each-view.log : unit-password-protected.log
-unit-session.log : unit-password-protected.log
-unit-uno-command.log : unit-password-protected.log
-
+unit-each-view.log : unit-render-shape.log
+unit-session.log : unit-each-view.log
+unit-uno-command.log : unit-session.log
 unit-load.log : unit-uno-command.log
 unit-cursor.log : unit-load.log
 unit-calc.log : unit-cursor.log
commit 104fb0573c1d7a3541c10cdd388ffabb27b74a5f
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jan 21 11:55:32 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    reduce verbosity of FileServer trace logging.
    
    Change-Id: I5a57e91742be504bcb2e51b45f6890420e52bb91

diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp
index 95bd54f90..55942611e 100644
--- a/wsd/FileServer.cpp
+++ b/wsd/FileServer.cpp
@@ -474,12 +474,14 @@ void FileServerRequestHandler::readDirToHash(const std::string &basePath, const
     struct stat fileStat;
     DIR *workingdir;
 
-    LOG_TRC("Pre-reading directory: " << basePath << path);
     workingdir = opendir((basePath + path).c_str());
 
     if (!workingdir)
         return;
 
+    size_t fileCount = 0;
+    std::string filesRead;
+
     while ((currentFile = readdir(workingdir)) != nullptr)
     {
         if (currentFile->d_name[0] == '.')
@@ -493,7 +495,9 @@ void FileServerRequestHandler::readDirToHash(const std::string &basePath, const
 
         else if (S_ISREG(fileStat.st_mode))
         {
-            LOG_TRC("Reading file: '" << basePath << relPath << " as '" << relPath << "'");
+            fileCount++;
+            filesRead.append(currentFile->d_name);
+            filesRead.append(" ");
 
             std::ifstream file(basePath + relPath, std::ios::binary);
 
@@ -539,6 +543,9 @@ void FileServerRequestHandler::readDirToHash(const std::string &basePath, const
         }
     }
     closedir(workingdir);
+
+    if (fileCount > 0)
+        LOG_TRC("Pre-read " << fileCount << " file(s) from directory: " << basePath << path << ": " << filesRead);
 }
 
 void FileServerRequestHandler::initialize()
commit 5f66cc71452f94f581820d4d19013f30e7d106ab
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jan 21 11:21:08 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: simplify and remove obsolete /proc grokking code.
    
    Change-Id: I482c56dd76067019d83196aa305d14703e25bb44

diff --git a/test/Makefile.am b/test/Makefile.am
index e4b621755..a31e557b6 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -81,7 +81,7 @@ test_base_source = \
 	DeltaTests.cpp \
 	$(wsd_sources)
 
-unittest_CPPFLAGS = -I$(top_srcdir) -DBUILDING_TESTS
+unittest_CPPFLAGS = -I$(top_srcdir) -DBUILDING_TESTS -DSTANDALONE_CPPUNIT
 unittest_SOURCES = $(test_base_source) test.cpp
 unittest_LDADD = $(CPPUNIT_LIBS)
 
diff --git a/test/UnitClient.cpp b/test/UnitClient.cpp
index 03682fdc5..bd2378eb3 100644
--- a/test/UnitClient.cpp
+++ b/test/UnitClient.cpp
@@ -72,7 +72,9 @@ UnitBase *unit_create_wsd(void)
 }
 
 // Allows re-use of UnitClient in test.cpp impls.
-#define UNIT_CLIENT_TESTS
+#ifdef STANDALONE_CPPUNIT
+#  error "Should never be compiled this way";
+#endif
 #include <test.cpp>
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/test.cpp b/test/test.cpp
index 57a7c8ff9..6613fb9b2 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -30,6 +30,9 @@
 #include <Poco/FileStream.h>
 #include <Poco/StreamCopier.h>
 
+#include <Unit.hpp>
+#include <wsd/LOOLWSD.hpp>
+
 #include <Log.hpp>
 
 #include "common/Protocol.hpp"
@@ -172,16 +175,10 @@ bool runClientTests(bool standalone, bool verbose)
     if (!envar && failures.size() > 0)
     {
         std::cerr << "\nTo reproduce the first test failure use:\n\n";
-#ifndef UNIT_CLIENT_TESTS
-        const char *cmd = "./run_unit.sh --verbose";
-        if (getenv("UNITTEST"))
-            cmd = "./unittest";
-        std::cerr << "  (cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" " << cmd << ")\n\n";
-        if (getenv("UNITTEST"))
-        {
-            std::cerr << "To debug:\n\n";
-            std::cerr << "  (cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" gdb --args " << cmd << ")\n\n";
-        }
+#ifdef STANDALONE_CPPUNIT // unittest
+        const char *cmd = "./unittest";
+        std::cerr << "To debug:\n\n";
+        std::cerr << "  (cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" gdb --args " << cmd << ")\n\n";
 #else
         std::string aLib = UnitBase::get().getUnitLibPath();
         size_t lastSlash = aLib.rfind('/');
@@ -195,108 +192,8 @@ bool runClientTests(bool standalone, bool verbose)
     return result.wasSuccessful();
 }
 
-// Versions assuming a single user, on a single machine
-#ifndef UNIT_CLIENT_TESTS
-
-std::vector<int> getProcPids(const char* exec_filename)
-{
-    std::vector<int> pids;
-
-    // Ensure we're in the same group.
-    const int grp = getpgrp();
-
-    // Get all lokit processes.
-    for (auto it = Poco::DirectoryIterator(std::string("/proc")); it != Poco::DirectoryIterator(); ++it)
-    {
-        try
-        {
-            const Poco::Path& procEntry = it.path();
-            const std::string& fileName = procEntry.getFileName();
-            int pid;
-            std::size_t endPos = 0;
-            try
-            {
-                pid = std::stoi(fileName, &endPos);
-            }
-            catch (const std::invalid_argument&)
-            {
-                pid = 0;
-            }
-
-            if (pid > 1 && endPos == fileName.length())
-            {
-                Poco::FileInputStream stat(procEntry.toString() + "/stat");
-                std::string statString;
-                Poco::StreamCopier::copyToString(stat, statString);
-                std::vector<std::string> tokens(LOOLProtocol::tokenize(statString, ' '));
-                if (tokens.size() > 6 && tokens[1].find(exec_filename) == 0)
-                {
-                    // We could have several make checks running at once.
-                    int kidGrp = std::atoi(tokens[4].c_str());
-                    // Don't require matching grp for --debugrun invocations.
-                    if (kidGrp != grp && !IsDebugrun)
-                        continue;
-
-                    switch (tokens[2].c_str()[0])
-                    {
-                    // Dead & zombie markers for old and new kernels.
-                    case 'x':
-                    case 'X':
-                    case 'Z':
-                        break;
-                    default:
-                        pids.push_back(pid);
-                        break;
-                    }
-                }
-            }
-        }
-        catch (const Poco::Exception&)
-        {
-        }
-    }
-    return pids;
-}
-
-std::vector<int> getSpareKitPids()
-{
-    return getProcPids("(kit_spare_");
-}
-
-std::vector<int> getDocKitPids()
-{
-    return getProcPids("(kitbroker_");
-}
-
-std::vector<int> getKitPids()
-{
-    std::vector<int> pids = getSpareKitPids();
-    for (int pid : getDocKitPids())
-        pids.push_back(pid);
-
-    return pids;
-}
-
-int getLoolKitProcessCount()
-{
-    return getKitPids().size();
-}
-
-std::vector<int> getForKitPids()
-{
-    std::vector<int> pids, pids2;
-
-    pids = getProcPids("(loolforkit)");
-    pids2 = getProcPids("(forkit)");
-    pids.insert(pids.end(), pids2.begin(), pids2.end());
-
-    return pids;
-}
-
-#else // UNIT_CLIENT_TESTS
-
-// Here we are compiled inside UnitClient.cpp and we have
-// full access to the WSD process internals.
+// Standalone tests don't really use WSD
+#ifndef STANDALONE_CPPUNIT
 
 std::vector<int> getKitPids()
 {
@@ -317,12 +214,6 @@ int getLoolKitProcessCount()
 {
     return getKitPids().size();
 }
-
-int getClientPort()
-{
-    return LOOLWSD::getClientPortNumber();
-}
-
-#endif // UNIT_CLIENT_TESTS
+#endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 6e1ce6a65a9425b8447eb0fdac8e5512ad9ef5fb
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Tue Jan 21 09:00:52 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: switch to using ClientPortNumber to allow parallelism.
    
    Change-Id: Ifef3bce1b217605000300b240ea74df4d264e0df

diff --git a/test/DeltaTests.cpp b/test/DeltaTests.cpp
index 6e230e17b..9c3eef273 100644
--- a/test/DeltaTests.cpp
+++ b/test/DeltaTests.cpp
@@ -14,7 +14,6 @@
 #include <Delta.hpp>
 #include <Util.hpp>
 #include <Png.hpp>
-#include <helpers.hpp>
 
 /// Delta unit-tests.
 class DeltaTests : public CPPUNIT_NS::TestFixture
diff --git a/test/Makefile.am b/test/Makefile.am
index f5804139e..e4b621755 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -194,7 +194,7 @@ TESTS = \
         unit-wopi-documentconflict.la unit_wopi_renamefile.la unit_wopi_watermark.la \
 	unit-http.la \
 	unit-tiff-load.la \
-	unit.large-paste.la \
+	unit-large-paste.la \
 	unit-paste.la \
 	unit-load-torture.la \
 	unit-rendering-options.la \
@@ -214,7 +214,7 @@ TESTS = \
 # TESTS += unit-admin.test
 # TESTS += unit-storage.test
 
-# force serialization for now:
+# mostly force serialization for now:
 
 # unit-base.log
 unit-tiletest.log : unit-base.log
@@ -226,8 +226,11 @@ unit-copy-paste.log : unit-crash.log
 unit-typing.log : unit-copy-paste.log
 unit-convert.log : unit-typing.log
 unit-prefork.log : unit-convert.log
+
+# try a couple in parallel
 unit-tilecache.log : unit-prefork.log
-unit-timeout.log : unit-tilecache.log
+unit-timeout.log : unit-prefork.log
+
 unit-oauth.log : unit-timeout.log
 unit-wopi.log : unit-oauth.log
 unit-wopi-saveas.log : unit-wopi.log
@@ -236,17 +239,21 @@ unit-wopi-versionrestore.log : unit-wopi-ownertermination.log
 unit-wopi-documentconflict.log : unit-wopi-versionrestore.log
 unit_wopi_renamefile.log : unit-wopi-documentconflict.log
 unit_wopi_watermark.log : unit_wopi_renamefile.log
+
 unit-http.log : unit_wopi_watermark.log
-unit-tiff-load.log : unit-http.log
-unit.logrge-paste.log : unit-tiff-load.log
-unit-paste.log : unit.logrge-paste.log
+unit-tiff-load.log : unit_wopi_watermark.log
+
+unit-large-paste.log : unit-tiff-load.log
+unit-paste.log : unit-large-paste.log
 unit-load-torture.log : unit-paste.log
 unit-rendering-options.log : unit-load-torture.log
 unit-password-protected.log : unit-rendering-options.log
+
 unit-render-shape.log : unit-password-protected.log
-unit-each-view.log : unit-render-shape.log
-unit-session.log : unit-each-view.log
-unit-uno-command.log : unit-session.log
+unit-each-view.log : unit-password-protected.log
+unit-session.log : unit-password-protected.log
+unit-uno-command.log : unit-password-protected.log
+
 unit-load.log : unit-uno-command.log
 unit-cursor.log : unit-load.log
 unit-calc.log : unit-cursor.log
@@ -257,10 +264,8 @@ unit-hosting.log : unit-bad-doc-load.log
 unit-wopi-loadencoded.log : unit-hosting.log
 unit-wopi-temp.log : unit-wopi-loadencoded.log
 
-# end force serialization
+# end forced serialization
 
-else
-TESTS = ${top_builddir}/test/test
 endif
 
 TEST_EXTENSIONS = .la
diff --git a/test/UnitWOPITemplate.cpp b/test/UnitWOPITemplate.cpp
index d133178ec..efe4574be 100644
--- a/test/UnitWOPITemplate.cpp
+++ b/test/UnitWOPITemplate.cpp
@@ -46,7 +46,7 @@ public:
             Poco::LocalDateTime now;
             Poco::JSON::Object::Ptr fileInfo = new Poco::JSON::Object();
             fileInfo->set("BaseFileName", "test.odt");
-            fileInfo->set("TemplateSource", std::string("http://127.0.0.1:") + std::to_string(helpers::getClientPort()) + "/test.ott"); // must be http, otherwise Neon in the core complains
+            fileInfo->set("TemplateSource", std::string("http://127.0.0.1:") + std::to_string(ClientPortNumber) + "/test.ott"); // must be http, otherwise Neon in the core complains
             fileInfo->set("Size", getFileContent().size());
             fileInfo->set("Version", "1.0");
             fileInfo->set("OwnerId", "test");
diff --git a/test/helpers.hpp b/test/helpers.hpp
index 32608b5a2..9aa15d518 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -31,6 +31,7 @@
 
 #include <Common.hpp>
 #include "common/FileUtil.hpp"
+#include "test/test.hpp"
 #include <LOOLWebSocket.hpp>
 #include <Util.hpp>
 
@@ -187,15 +188,6 @@ Poco::Net::HTTPClientSession* createSession(const Poco::URI& uri)
     return new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort());
 }
 
-#ifndef UNIT_CLIENT_TESTS
-
-inline int getClientPort()
-{
-    return DEFAULT_CLIENT_PORT_NUMBER;
-}
-
-#endif
-
 inline std::shared_ptr<Poco::Net::StreamSocket> createRawSocket()
 {
     return
@@ -204,7 +196,7 @@ inline std::shared_ptr<Poco::Net::StreamSocket> createRawSocket()
 #else
         std::make_shared<Poco::Net::StreamSocket>
 #endif
-            (Poco::Net::SocketAddress("127.0.0.1", getClientPort()));
+        (Poco::Net::SocketAddress("127.0.0.1", ClientPortNumber));
 }
 
 inline
@@ -216,7 +208,7 @@ std::string const & getTestServerURI()
 #else
             "http://127.0.0.1:"
 #endif
-            + std::to_string(getClientPort()));
+            + std::to_string(ClientPortNumber));
 
     return serverURI;
 }
diff --git a/test/httpcrashtest.cpp b/test/httpcrashtest.cpp
index 1d271725b..904b4330e 100644
--- a/test/httpcrashtest.cpp
+++ b/test/httpcrashtest.cpp
@@ -39,9 +39,9 @@
 #include <Util.hpp>
 #include <Protocol.hpp>
 #include <LOOLWebSocket.hpp>
+#include <test.hpp>
 #include <helpers.hpp>
 #include <countloolkits.hpp>
-#include <test.hpp>
 
 using namespace helpers;
 
diff --git a/tools/Stress.cpp b/tools/Stress.cpp
index 1a4d17124..b298951db 100644
--- a/tools/Stress.cpp
+++ b/tools/Stress.cpp
@@ -34,6 +34,8 @@
 #include <TraceFile.hpp>
 #include <test/helpers.hpp>
 
+int ClientPortNumber = DEFAULT_CLIENT_PORT_NUMBER;
+
 /// Stress testing and performance/scalability benchmarking tool.
 class Stress: public Poco::Util::Application
 {
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 090cde1c0..bcb0ca141 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -3254,7 +3254,6 @@ private:
         LOG_INF("Listening to prisoner connections on " << location);
         MasterLocation = location;
 #else
-        // TESTME ...
         constexpr int DEFAULT_MASTER_PORT_NUMBER = 9981;
         std::shared_ptr<ServerSocket> socket = getServerSocket(
             ServerSocket::Type::Public, DEFAULT_MASTER_PORT_NUMBER, PrisonerPoll, factory);
commit f8b82995a237924b61c7d273815ad50a48f1c6d9
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jan 20 15:26:54 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: serialize tests for now.
    
    Change-Id: I6309976f324a66a57baf4678e49c0c1e09b9dc48

diff --git a/test/Makefile.am b/test/Makefile.am
index e10cb7d8c..f5804139e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -213,6 +213,52 @@ TESTS = \
 	unit-wopi-loadencoded.la unit-wopi-temp.la
 # TESTS += unit-admin.test
 # TESTS += unit-storage.test
+
+# force serialization for now:
+
+# unit-base.log
+unit-tiletest.log : unit-base.log
+unit-integration.log : unit-tiletest.log
+unit-httpws.log : unit-integration.log
+unit-crash.log : unit-httpws.log
+
+unit-copy-paste.log : unit-crash.log
+unit-typing.log : unit-copy-paste.log
+unit-convert.log : unit-typing.log
+unit-prefork.log : unit-convert.log
+unit-tilecache.log : unit-prefork.log
+unit-timeout.log : unit-tilecache.log
+unit-oauth.log : unit-timeout.log
+unit-wopi.log : unit-oauth.log
+unit-wopi-saveas.log : unit-wopi.log
+unit-wopi-ownertermination.log : unit-wopi-saveas.log
+unit-wopi-versionrestore.log : unit-wopi-ownertermination.log
+unit-wopi-documentconflict.log : unit-wopi-versionrestore.log
+unit_wopi_renamefile.log : unit-wopi-documentconflict.log
+unit_wopi_watermark.log : unit_wopi_renamefile.log
+unit-http.log : unit_wopi_watermark.log
+unit-tiff-load.log : unit-http.log
+unit.logrge-paste.log : unit-tiff-load.log
+unit-paste.log : unit.logrge-paste.log
+unit-load-torture.log : unit-paste.log
+unit-rendering-options.log : unit-load-torture.log
+unit-password-protected.log : unit-rendering-options.log
+unit-render-shape.log : unit-password-protected.log
+unit-each-view.log : unit-render-shape.log
+unit-session.log : unit-each-view.log
+unit-uno-command.log : unit-session.log
+unit-load.log : unit-uno-command.log
+unit-cursor.log : unit-load.log
+unit-calc.log : unit-cursor.log
+unit-insert-delete.log : unit-calc.log
+unit-close.log : unit-insert-delete.log
+unit-bad-doc-load.log : unit-close.log
+unit-hosting.log : unit-bad-doc-load.log
+unit-wopi-loadencoded.log : unit-hosting.log
+unit-wopi-temp.log : unit-wopi-loadencoded.log
+
+# end force serialization
+
 else
 TESTS = ${top_builddir}/test/test
 endif
commit 60da722cbbae364e4b45331ff947d09eaa6103ea
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jan 20 15:16:36 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: simplify the timeout logic.
    
    Change-Id: I0c253629b983f2813237536e6e2c6d04d5b97dd1

diff --git a/test/data/convert-to.xlsx b/test/data/convert-to.xlsx
index 7af9e7063..344ee0d13 100644
Binary files a/test/data/convert-to.xlsx and b/test/data/convert-to.xlsx differ
diff --git a/test/helpers.hpp b/test/helpers.hpp
index 19bd8804d..32608b5a2 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -261,22 +261,22 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi
     try
     {
         int flags = 0;
-        int retries = timeoutMs / 500;
-        const Poco::Timespan waitTime(retries ? timeoutMs * 1000 / retries : timeoutMs * 1000);
         std::vector<char> response;
 
-        bool timedout = false;
+        auto endTime = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeoutMs);
+
         ws.setReceiveTimeout(0);
         do
         {
-            if (ws.poll(waitTime, Poco::Net::Socket::SELECT_READ))
+            auto now = std::chrono::steady_clock::now();
+            if (now > endTime) // timedout
+            {
+                TST_LOG("Timeout.");
+                break;
+            }
+            long waitTimeUs = std::chrono::duration_cast<std::chrono::microseconds>(endTime - now).count();
+            if (ws.poll(Poco::Timespan(waitTimeUs), Poco::Net::Socket::SELECT_READ))
             {
-                if (timedout)
-                {
-                    TST_LOG_END;
-                    timedout = false;
-                }
-
                 response.resize(READ_BUFFER_SIZE * 8);
                 const int bytes = ws.receiveFrame(response.data(), response.size(), flags);
                 response.resize(std::max(bytes, 0));
@@ -312,31 +312,11 @@ std::vector<char> getResponseMessage(LOOLWebSocket& ws, const std::string& prefi
                             LOOLProtocol::getAbbreviatedFrameDump(response.data(), bytes, flags));
                 }
             }
-            else
-            {
-                if (!timedout)
-                {
-                    TST_LOG_BEGIN("Timeout (" << (retries > 1 ? "retrying" : "giving up") << ") ");
-                }
-                else
-                {
-                    TST_LOG_APPEND(retries << ' ');
-                }
-
-                --retries;
-                timedout = true;
-            }
-        }
-        while (retries > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);
-
-        if (timedout)
-        {
-            TST_LOG_END;
         }
+        while ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE);
     }
     catch (const Poco::Net::WebSocketException& exc)
     {
-        TST_LOG_END;
         TST_LOG(exc.message());
     }
 
commit e99f3d5e770c95b747ea85c6211502085bd3d0db
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Jan 17 21:18:42 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: dung out redundant LOOL_TEST_CLIENT_PORT.
    
    And cleanup other related oddities.
    
    Change-Id: I2d179a2ece6a8553e10e406ad4e5da08a2ff58e5

diff --git a/kit/ForKit.cpp b/kit/ForKit.cpp
index 164489589..ac0191e33 100644
--- a/kit/ForKit.cpp
+++ b/kit/ForKit.cpp
@@ -396,15 +396,6 @@ int main(int argc, char** argv)
     std::string sysTemplate;
     std::string loTemplate;
 
-#if ENABLE_DEBUG
-    static const char* clientPort = std::getenv("LOOL_TEST_CLIENT_PORT");
-    if (clientPort)
-        ClientPortNumber = std::stoi(clientPort);
-    static const char* masterPort = std::getenv("LOOL_TEST_MASTER_PORT");
-    if (masterPort)
-        MasterLocation = masterPort;
-#endif
-
     for (int i = 0; i < argc; ++i)
     {
         char *cmd = argv[i];
diff --git a/test/Makefile.am b/test/Makefile.am
index 2b369465a..e10cb7d8c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -2,12 +2,10 @@
 export MAX_CONCURRENCY=4
 AUTOMAKE_OPTION = serial-tests
 
-# unittest: tests that do not need loolwsd running, and that are run during a
-# normal build
-# test: tests that need loolwsd running, and that are run via 'make check'
-check_PROGRAMS = test fakesockettest
+# unittest: tests that run a captive loolwsd as part of themselves.
+check_PROGRAMS = fakesockettest
 
-noinst_PROGRAMS = test fakesockettest unittest
+noinst_PROGRAMS = fakesockettest unittest
 
 AM_CXXFLAGS = $(CPPUNIT_CFLAGS) -DTDOC=\"$(abs_top_srcdir)/test/data\" \
 	-I${top_srcdir}/common -I${top_srcdir}/net -I${top_srcdir}/wsd -I${top_srcdir}/kit
@@ -87,10 +85,6 @@ unittest_CPPFLAGS = -I$(top_srcdir) -DBUILDING_TESTS
 unittest_SOURCES = $(test_base_source) test.cpp
 unittest_LDADD = $(CPPUNIT_LIBS)
 
-test_CPPFLAGS = -I$(top_srcdir) -DBUILDING_TESTS
-test_SOURCES = $(test_all_source) test.cpp
-test_LDADD = $(CPPUNIT_LIBS)
-
 fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp
 fakesockettest_LDADD = $(CPPUNIT_LIBS)
 
diff --git a/test/TileCacheTests.cpp b/test/TileCacheTests.cpp
index 7dc7d1500..a69099bd5 100644
--- a/test/TileCacheTests.cpp
+++ b/test/TileCacheTests.cpp
@@ -432,6 +432,8 @@ void TileCacheTests::testUnresponsiveClient()
 {
     const std::string testname = "unresponsiveClient-";
 
+    TST_LOG("testUnresponsiveClient.");
+
     std::string documentPath, documentURL;
     getDocumentPathAndURL("hello.odt", documentPath, documentURL, testname);
 
diff --git a/test/helpers.hpp b/test/helpers.hpp
index dd638d191..19bd8804d 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -187,12 +187,15 @@ Poco::Net::HTTPClientSession* createSession(const Poco::URI& uri)
     return new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort());
 }
 
+#ifndef UNIT_CLIENT_TESTS
+
 inline int getClientPort()
 {
-    static const char* clientPort = std::getenv("LOOL_TEST_CLIENT_PORT");
-    return clientPort? atoi(clientPort) : DEFAULT_CLIENT_PORT_NUMBER;
+    return DEFAULT_CLIENT_PORT_NUMBER;
 }
 
+#endif
+
 inline std::shared_ptr<Poco::Net::StreamSocket> createRawSocket()
 {
     return
diff --git a/test/integration-http-server.cpp b/test/integration-http-server.cpp
index 4db04737a..8c0c87ac2 100644
--- a/test/integration-http-server.cpp
+++ b/test/integration-http-server.cpp
@@ -92,15 +92,13 @@ public:
     // A server URI which was not added to loolwsd.xml as post_allow IP or a wopi storage host
     Poco::URI getNotAllowedTestServerURI()
     {
-        static const char* clientPort = std::getenv("LOOL_TEST_CLIENT_PORT");
-
         static std::string serverURI(
 #if ENABLE_SSL
-        "https://165.227.162.232:"
+            "https://165.227.162.232:9980"
 #else
-        "http://165.227.162.232:"
+            "http://165.227.162.232:9980"
 #endif
-            + (clientPort? std::string(clientPort) : std::to_string(DEFAULT_CLIENT_PORT_NUMBER)));
+            );
 
         return Poco::URI(serverURI);
     }
@@ -236,9 +234,12 @@ void HTTPServerTest::testScriptsAndLinksPost()
 
 void HTTPServerTest::testConvertTo()
 {
+    const char *testname = "testConvertTo";
     const std::string srcPath = FileUtil::getTempFilePath(TDOC, "hello.odt", "convertTo_");
     std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
-    session->setTimeout(Poco::Timespan(2, 0)); // 2 seconds.
+    session->setTimeout(Poco::Timespan(5, 0)); // 5 seconds.
+
+    TST_LOG("Convert-to odt -> txt");
 
     Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/lool/convert-to");
     Poco::Net::HTMLForm form;
@@ -253,7 +254,7 @@ void HTTPServerTest::testConvertTo()
     catch (const std::exception& ex)
     {
         // In case the server is still starting up.
-        sleep(2);
+        sleep(5);
         form.write(session->sendRequest(request));
     }
 
@@ -279,9 +280,12 @@ void HTTPServerTest::testConvertTo()
 
 void HTTPServerTest::testConvertTo2()
 {
+    const char *testname = "testConvertTo2";
     const std::string srcPath = FileUtil::getTempFilePath(TDOC, "convert-to.xlsx", "convertTo_");
     std::unique_ptr<Poco::Net::HTTPClientSession> session(helpers::createSession(_uri));
-    session->setTimeout(Poco::Timespan(5, 0)); // 5 seconds.
+    session->setTimeout(Poco::Timespan(10, 0)); // 10 seconds.
+
+    TST_LOG("Convert-to #2 xlsx -> png");
 
     Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/lool/convert-to");
     Poco::Net::HTMLForm form;
@@ -296,7 +300,7 @@ void HTTPServerTest::testConvertTo2()
     catch (const std::exception& ex)
     {
         // In case the server is still starting up.
-        sleep(2);
+        sleep(5);
         form.write(session->sendRequest(request));
     }
 
diff --git a/test/run_unit.sh.in b/test/run_unit.sh.in
index 5fb8a6936..4b893f23c 100755
--- a/test/run_unit.sh.in
+++ b/test/run_unit.sh.in
@@ -70,55 +70,10 @@ fi
 echo "Test output is '$test_output'"
 echo > $test_output
 
-if test "z$tst" == "z"; then
-     # run the test on a dedicated port
-     export LOOL_TEST_CLIENT_PORT=9984
-     export LOOL_TEST_MASTER_PORT=9985
-
-     echo "Executing external tests"
-     ${trace} \
-     ${abs_top_builddir}/loolwsd --o:sys_template_path="$systemplate_path" \
-                                 --o:child_root_path="$jails_path" \
-                                 --o:storage.filesystem[@allow]=true \
-                                 --o:logging.level=trace \
-                                 --o:logging.file[@enable]=false \
-                                 --o:ssl.key_file_path="${abs_top_builddir}/etc/key.pem" \
-                                 --o:ssl.cert_file_path="${abs_top_builddir}/etc/cert.pem" \
-                                 --o:ssl.ca_file_path="${abs_top_builddir}/etc/ca-chain.cert.pem" \
-                                 --o:admin_console.username=admin --o:admin_console.password=admin \
-                                 --o:storage.ssl.enable=false \
-                                 > "$tst_log" 2>&1 &
-     if test "z${SLEEPFORDEBUGGER}${SLEEPKITFORDEBUGGER}" != "z"; then
-	  echo "sleeping for debugger"
-          sleep ${SLEEPFORDEBUGGER:-0}
-          sleep ${SLEEPKITFORDEBUGGER:-0}
-     fi
-
-     echo "  executing test"
-
-     oldpath=`pwd`
-     cd "${abs_top_builddir}/test"
-     if eval ${trace} ./test ${verbose}; then
-	 echo "Test run_test.sh passed."
-	 echo ":test-result: PASS run_test.sh" >> $oldpath/$test_output
-	 retval=0
-     else
-	 echo ":test-result: FAIL run_test.sh" >> $oldpath/$test_output
-	 retval=1
-     fi
-
-     if test "z${SLEEPFORDEBUGGER}${SLEEPKITFORDEBUGGER}" == "z"; then
-         echo "killing $!"
-         kill $!
-     fi
-
-     exit $retval
-
-else # newer unit tests.
-    echo "Running $tst | $tst_log ...";
-    if ${trace} \
+echo "Running $tst | $tst_log ...";
+if ${trace} \
        ${abs_top_builddir}/loolwsd --o:sys_template_path="$systemplate_path" \
-                                   --o:child_root_path="$jails_path" \
+       --o:child_root_path="$jails_path" \
                                    --o:storage.filesystem[@allow]=true \
                                    --o:logging.level=trace \
                                    --o:ssl.key_file_path="${abs_top_builddir}/etc/key.pem" \
@@ -129,7 +84,7 @@ else # newer unit tests.
                                    --unitlib="${abs_top_builddir}/test/.libs/$tst.so" 2> "$tst_log"; then
         echo "Test $tst passed."
         echo ":test-result: PASS $tst" >> $test_output
-    else
+else
 	cat $tst_log
         echo "============================================================="
         echo "Test failed on unit: $tst re-run with:"
@@ -147,7 +102,6 @@ else # newer unit tests.
 	echo "   $ less $tst_log # for detailed failure log files"
         echo "============================================================="
         echo ":test-result: FAIL $tst" >> $test_output
-    fi
 fi
 
 # vim:set shiftwidth=4 expandtab:
diff --git a/test/test.cpp b/test/test.cpp
index 4a5b0f6d0..57a7c8ff9 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -183,8 +183,12 @@ bool runClientTests(bool standalone, bool verbose)
             std::cerr << "  (cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" gdb --args " << cmd << ")\n\n";
         }
 #else
+        std::string aLib = UnitBase::get().getUnitLibPath();
+        size_t lastSlash = aLib.rfind('/');
+        if (lastSlash != std::string::npos)
+            aLib = aLib.substr(lastSlash + 1, aLib.length() - lastSlash - 4) + ".la";
         std::cerr << "(cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() <<
-            "\" ./run_unit.sh --test-name " << UnitBase::get().getUnitLibPath() << ")\n\n";
+            "\" ./run_unit.sh --test-name " << aLib << ")\n\n";
 #endif
     }
 
@@ -314,6 +318,11 @@ int getLoolKitProcessCount()
     return getKitPids().size();
 }
 
+int getClientPort()
+{
+    return LOOLWSD::getClientPortNumber();
+}
+
 #endif // UNIT_CLIENT_TESTS
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/test/test.hpp b/test/test.hpp
index 29b6e76d3..a5a2b2280 100644
--- a/test/test.hpp
+++ b/test/test.hpp
@@ -31,6 +31,9 @@ std::vector<int> getDocKitPids();
 /// Get the PID of the forkit
 std::vector<int> getForKitPids();
 
+/// Which port should we connect to get to WSD.
+int getClientPort();
+
 /// How many live loolkit processes do we have ?
 int getLoolKitProcessCount();
 
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 4a4a61302..090cde1c0 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1404,10 +1404,6 @@ void LOOLWSD::handleOption(const std::string& optionName,
     else if (optionName == "careerspan")
         careerSpanMs = std::stoi(value) * 1000; // Convert second to ms
 
-    static const char* clientPort = std::getenv("LOOL_TEST_CLIENT_PORT");
-    if (clientPort)
-        ClientPortNumber = std::stoi(clientPort);
-
     static const char* latencyMs = std::getenv("LOOL_DELAY_SOCKET_MS");
     if (latencyMs)
         SimulatedLatencyMs = std::stoi(latencyMs);
@@ -3670,6 +3666,11 @@ std::vector<std::shared_ptr<DocumentBroker>> LOOLWSD::getBrokersTestOnly()
     return result;
 }
 
+int LOOLWSD::getClientPortNumber()
+{
+    return ClientPortNumber;
+}
+
 std::vector<int> LOOLWSD::getKitPids()
 {
     std::vector<int> pids;
diff --git a/wsd/LOOLWSD.hpp b/wsd/LOOLWSD.hpp
index 71ddb2155..35c283288 100644
--- a/wsd/LOOLWSD.hpp
+++ b/wsd/LOOLWSD.hpp
@@ -80,6 +80,8 @@ public:
     static std::set<const Poco::Util::AbstractConfiguration*> PluginConfigurations;
     static std::chrono::time_point<std::chrono::system_clock> StartTime;
 
+    /// For testing only [!]
+    static int getClientPortNumber();
     /// For testing only [!]
     static std::vector<int> getKitPids();
     /// For testing only [!] DocumentBrokers are mostly single-threaded with their own thread
commit 1c19c5d653ea8e86c3ee872f2cb6cc36a168b1cd
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Jan 17 20:49:38 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    test: switch to parallel tests based on Unit framework.
    
    Increase a few timeouts, bin old-style standalone unit tests,
    fix a number of bugs.
    
    Change-Id: Ia3d59466ecb9a9443807ba3445d04dd5f77e3dba

diff --git a/common/Unit.cpp b/common/Unit.cpp
index 5dc01d4ea..875c97686 100644
--- a/common/Unit.cpp
+++ b/common/Unit.cpp
@@ -26,7 +26,7 @@
 #include <common/SigUtil.hpp>
 
 UnitBase *UnitBase::Global = nullptr;
-
+char * UnitBase::UnitLibPath;
 static std::thread TimeoutThread;
 static std::atomic<bool> TimeoutThreadRunning(false);
 std::timed_mutex TimeoutThreadMutex;
@@ -41,6 +41,9 @@ UnitBase *UnitBase::linkAndCreateUnit(UnitType type, const std::string &unitLibP
         return nullptr;
     }
 
+    // avoid std:string de-allocation during failure / exit.
+    UnitLibPath = strdup(unitLibPath.c_str());
+
     const char *symbol = nullptr;
     switch (type)
     {
diff --git a/common/Unit.hpp b/common/Unit.hpp
index 63975514b..c403100c2 100644
--- a/common/Unit.hpp
+++ b/common/Unit.hpp
@@ -138,11 +138,17 @@ public:
         return *Global;
     }
 
+    static std::string getUnitLibPath() { return std::string(UnitLibPath); }
+
 private:
-    void setHandle(void *dlHandle) { _dlHandle = dlHandle; }
+    void setHandle(void *dlHandle)
+    {
+        _dlHandle = dlHandle;
+    }
     static UnitBase *linkAndCreateUnit(UnitType type, const std::string& unitLibPath);
 
     void *_dlHandle;
+    static char *UnitLibPath;
     bool _setRetValue;
     int _retValue;
     int _timeoutMilliSeconds;
diff --git a/test/Makefile.am b/test/Makefile.am
index f1d4963b1..2b369465a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,9 +13,10 @@ AM_CXXFLAGS = $(CPPUNIT_CFLAGS) -DTDOC=\"$(abs_top_srcdir)/test/data\" \
 	-I${top_srcdir}/common -I${top_srcdir}/net -I${top_srcdir}/wsd -I${top_srcdir}/kit
 
 noinst_LTLIBRARIES = \
+	unit-base.la unit-tiletest.la \
+	unit-integration.la unit-httpws.la unit-crash.la \
 	unit-convert.la unit-typing.la unit-copy-paste.la \
-	unit-timeout.la unit-prefork.la \
-	unit-storage.la unit-client.la \
+	unit-timeout.la unit-prefork.la unit-storage.la \
 	unit-admin.la unit-tilecache.la \
 	unit-fuzz.la unit-oob.la unit-http.la unit-oauth.la \
 	unit-wopi.la unit-wopi-saveas.la \
@@ -82,13 +83,6 @@ test_base_source = \
 	DeltaTests.cpp \
 	$(wsd_sources)
 
-test_all_source = \
-	$(test_base_source) \
-	TileCacheTests.cpp \
-	integration-http-server.cpp \
-	httpwstest.cpp \
-	httpcrashtest.cpp
-
 unittest_CPPFLAGS = -I$(top_srcdir) -DBUILDING_TESTS
 unittest_SOURCES = $(test_base_source) test.cpp
 unittest_LDADD = $(CPPUNIT_LIBS)
@@ -100,6 +94,18 @@ test_LDADD = $(CPPUNIT_LIBS)
 fakesockettest_SOURCES = fakesockettest.cpp ../net/FakeSocket.cpp
 fakesockettest_LDADD = $(CPPUNIT_LIBS)
 
+# old-style unit tests - bootstrapped via UnitClient
+unit_base_la_SOURCES = UnitClient.cpp ${test_base_source}
+unit_base_la_LIBADD = $(CPPUNIT_LIBS)
+unit_tiletest_la_SOURCES = UnitClient.cpp TileCacheTests.cpp
+unit_tiletest_la_LIBADD = $(CPPUNIT_LIBS)
+unit_integration_la_SOURCES = UnitClient.cpp integration-http-server.cpp
+unit_integration_la_LIBADD = $(CPPUNIT_LIBS)
+unit_httpws_la_SOURCES = UnitClient.cpp httpwstest.cpp
+unit_httpws_la_LIBADD = $(CPPUNIT_LIBS)
+unit_crash_la_SOURCES = UnitClient.cpp httpcrashtest.cpp
+unit_crash_la_LIBADD = $(CPPUNIT_LIBS)
+
 # unit test modules:
 unit_oob_la_SOURCES = UnitOOB.cpp
 unit_http_la_SOURCES = UnitHTTP.cpp
@@ -107,8 +113,6 @@ unit_http_la_LIBADD = $(CPPUNIT_LIBS)
 unit_fuzz_la_SOURCES = UnitFuzz.cpp
 unit_admin_la_SOURCES = UnitAdmin.cpp
 unit_admin_la_LIBADD = $(CPPUNIT_LIBS)
-unit_client_la_SOURCES = UnitClient.cpp ${test_all_source}
-unit_client_la_LIBADD = $(CPPUNIT_LIBS)
 unit_typing_la_SOURCES = UnitTyping.cpp
 unit_typing_la_LIBADD = $(CPPUNIT_LIBS)
 unit_copy_paste_la_SOURCES = UnitCopyPaste.cpp
@@ -183,16 +187,20 @@ if HAVE_LO_PATH
 check-local:
 	./fakesockettest
 	@fc-cache "@LO_PATH@"/share/fonts/truetype
-	./run_unit.sh --log-file test.log --trs-file test.trs
+
 # FIXME 2: unit-oob.la fails with symbol undefined:
 # UnitWSD::testHandleRequest(UnitWSD::TestRequest, UnitHTTPServerRequest&, UnitHTTPServerResponse&) ,
-TESTS = unit-copy-paste.la unit-typing.la unit-convert.la unit-prefork.la unit-tilecache.la unit-timeout.la \
+TESTS = \
+	unit-base.la unit-tiletest.la \
+	unit-integration.la unit-httpws.la unit-crash.la \
+	\
+	unit-copy-paste.la unit-typing.la unit-convert.la unit-prefork.la unit-tilecache.la unit-timeout.la \
         unit-oauth.la unit-wopi.la unit-wopi-saveas.la \
         unit-wopi-ownertermination.la unit-wopi-versionrestore.la \
         unit-wopi-documentconflict.la unit_wopi_renamefile.la unit_wopi_watermark.la \
 	unit-http.la \
 	unit-tiff-load.la \
-	unit-large-paste.la \
+	unit.large-paste.la \
 	unit-paste.la \
 	unit-load-torture.la \
 	unit-rendering-options.la \
@@ -209,9 +217,8 @@ TESTS = unit-copy-paste.la unit-typing.la unit-convert.la unit-prefork.la unit-t
 	unit-bad-doc-load.la \
 	unit-hosting.la \
 	unit-wopi-loadencoded.la unit-wopi-temp.la
-# TESTS = unit-client.la
-# TESTS += unit-admin.la
-# TESTS += unit-storage.la
+# TESTS += unit-admin.test
+# TESTS += unit-storage.test
 else
 TESTS = ${top_builddir}/test/test
 endif
diff --git a/test/UnitClient.cpp b/test/UnitClient.cpp
index e3580f90e..03682fdc5 100644
--- a/test/UnitClient.cpp
+++ b/test/UnitClient.cpp
@@ -7,7 +7,9 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-// Runs client tests in their own thread inside a WSD process.
+// Runs old-style CPPUNIT tests in their own thread inside a WSD process.
+// Depending which cppunit objects this is linked with this runs different
+// tests.
 
 #include <config.h>
 
diff --git a/test/helpers.hpp b/test/helpers.hpp
index f09de8bbb..dd638d191 100644
--- a/test/helpers.hpp
+++ b/test/helpers.hpp
@@ -390,8 +390,12 @@ inline
 bool isDocumentLoaded(LOOLWebSocket& ws, const std::string& testname, bool isView = true)
 {
     const std::string prefix = isView ? "status:" : "statusindicatorfinish:";
-    const auto message = getResponseString(ws, prefix, testname);
-    return LOOLProtocol::matchPrefix(prefix, message);
+    // Allow 20 secs to load
+    const auto message = getResponseString(ws, prefix, testname, 30 * 1000);
+    bool success = LOOLProtocol::matchPrefix(prefix, message);
+    if (!success)
+        TST_LOG("ERR: Timed out loading document");
+    return success;
 }
 
 inline
diff --git a/test/test.cpp b/test/test.cpp
index cc00b2fde..4a5b0f6d0 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -183,7 +183,8 @@ bool runClientTests(bool standalone, bool verbose)
             std::cerr << "  (cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" gdb --args " << cmd << ")\n\n";
         }
 #else
-        std::cerr << "(cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() << "\" make check)\n\n";
+        std::cerr << "(cd test; CPPUNIT_TEST_NAME=\"" << (*failures.begin())->failedTestName() <<
+            "\" ./run_unit.sh --test-name " << UnitBase::get().getUnitLibPath() << ")\n\n";
 #endif
     }
 
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 9bf7088c6..876436abe 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -309,9 +309,9 @@ void DocumentBroker::pollThread()
 
         if (!_isLoaded && (limit_load_secs > 0) && (now > loadDeadline))
         {
-            LOG_WRN("Doc [" << _docKey << "] is taking too long to load. Will kill process ["
-                            << _childProcess->getPid() << "]. per_document.limit_load_secs set to "
-                            << limit_load_secs << " secs.");
+            LOG_ERR("Doc [" << _docKey << "] is taking too long to load. Will kill process ["
+                    << _childProcess->getPid() << "]. per_document.limit_load_secs set to "
+                    << limit_load_secs << " secs.");
             broadcastMessage("error: cmd=load kind=docloadtimeout");
 
             // Brutal but effective.
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index e39bfa9d0..4a4a61302 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -3283,14 +3283,19 @@ private:
 
         std::shared_ptr<ServerSocket> socket = getServerSocket(
             ClientListenAddr, port, WebServerPoll, factory);
+
+        while (!socket &&
 #ifdef BUILDING_TESTS
-        while (!socket)
+               true
+#else
+               UnitWSD::isUnitTesting()
+#endif
+            )
         {
             ++port;
             LOG_INF("Client port " << (port - 1) << " is busy, trying " << port << ".");
-            socket = getServerSocket(port, WebServerPoll, factory);
+            socket = getServerSocket(ClientListenAddr, port, WebServerPoll, factory);
         }
-#endif
 
         if (!socket)
         {
commit 4b09164962c9f7dd16e9a512df9057dcc3438c83
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Jan 18 15:56:01 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Tue Jan 21 12:07:53 2020 +0000

    copyFile: de-poco-ize and handle EINTR and short writes.
    
    Change-Id: I2046881c786a9f31f45c53f282de9ddd9a9cebcf

diff --git a/common/FileUtil.cpp b/common/FileUtil.cpp
index 5066d2938..84f4085a1 100644
--- a/common/FileUtil.cpp
+++ b/common/FileUtil.cpp
@@ -88,6 +88,80 @@ namespace FileUtil
         return name;
     }
 
+    void copyFileTo(const std::string &fromPath, const std::string &toPath)
+    {
+        int from = -1, to = -1;
+        try {
+            from = open(fromPath.c_str(), O_RDONLY);
+            if (from < 0)
+            {
+                LOG_SYS("Failed to open src " << anonymizeUrl(fromPath));
+                throw;
+            }
+
+            struct stat st;
+            if (fstat(from, &st) != 0)
+            {
+                LOG_SYS("Failed to fstat src " << anonymizeUrl(fromPath));
+                throw;
+            }
+
+            to = open(toPath.c_str(), O_CREAT | O_TRUNC | O_WRONLY, st.st_mode);
+            if (to < 0)
+            {
+                LOG_SYS("Failed to fstat dest " << anonymizeUrl(toPath));
+                throw;
+            }
+
+            LOG_INF("Copying " << st.st_size << " bytes from " << anonymizeUrl(fromPath) << " to " << anonymizeUrl(toPath));
+
+            char buffer[64 * 1024];
+
+            int n;
+            off_t bytesIn = 0;
+            do {
+                while ((n = ::read(from, buffer, sizeof(buffer))) < 0 && errno == EINTR)
+                    LOG_TRC("EINTR reading from " << anonymizeUrl(fromPath));
+                if (n < 0)
+                {
+                    LOG_SYS("Failed to read from " << anonymizeUrl(fromPath) << " at " << bytesIn << " bytes in");
+                    throw;
+                }
+                bytesIn += n;
+                if (n == 0) // EOF
+                    break;
+                assert (off_t(sizeof (buffer)) >= n);
+                // Handle short writes and EINTR
+                for (int j = 0; j < n;)
+                {
+                    int written;
+                    while ((written = ::write(to, buffer + j, n - j)) < 0 && errno == EINTR)
+                        LOG_TRC("EINTR writing to " << anonymizeUrl(toPath));
+                    if (written < 0)
+                    {
+                        LOG_SYS("Failed to write " << n << " bytes to " << anonymizeUrl(toPath) << " at " <<
+                                bytesIn << " bytes into " << anonymizeUrl(fromPath));
+                        throw;
+                    }
+                    j += written;
+                }
+            } while(true);
+            if (bytesIn != st.st_size)
+            {
+                LOG_WRN("Unusual: file " << anonymizeUrl(fromPath) << " changed size "
+                        "during copy from " << st.st_size << " to " << bytesIn);
+            }
+        }
+        catch (...)
+        {
+            LOG_SYS("Failed to copy from " << anonymizeUrl(fromPath) << " to " << anonymizeUrl(toPath));
+            close(from);
+            close(to);
+            unlink(toPath.c_str());
+            throw Poco::Exception("failed to copy");
+        }
+    }
+
     std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename, const std::string& dstFilenamePrefix)
     {
         const std::string srcPath = srcDir + '/' + srcFilename;
@@ -100,7 +174,7 @@ namespace FileUtil
         fileDeleter.registerForDeletion(dstPath);
 #else
         const std::string dstPath = Poco::Path(Poco::Path::temp(), dstFilename).toString();
-        Poco::File(srcPath).copyTo(dstPath);
+        copyFileTo(srcPath, dstPath);
         Poco::TemporaryFile::registerForDeletion(dstPath);
 #endif
 
diff --git a/common/FileUtil.hpp b/common/FileUtil.hpp
index a57aa5414..864188308 100644
--- a/common/FileUtil.hpp
+++ b/common/FileUtil.hpp
@@ -80,6 +80,9 @@ namespace FileUtil
         removeFile(path.toString(), recursive);
     }
 
+    /// Copy a file from @fromPath to @toPath, throws on failure.
+    void copyFileTo(const std::string &fromPath, const std::string &toPath);
+
     /// Make a temp copy of a file, and prepend it with a prefix.
     std::string getTempFilePath(const std::string& srcDir, const std::string& srcFilename,
                                 const std::string& dstFilenamePrefix);
diff --git a/test/run_unit.sh.in b/test/run_unit.sh.in
index d05e2f48f..5fb8a6936 100755
--- a/test/run_unit.sh.in
+++ b/test/run_unit.sh.in
@@ -56,16 +56,6 @@ echo "	$cmd_line"
 # drop .la suffix
 tst=`echo $tst | sed "s/\.la//"`;
 
-if test "z$tst" != "z" && test "z$CPPUNIT_TEST_NAME" != "z"; then
-    # $tst is not empty, but $CPPUNIT_TEST_NAME is set, exit early if they
-    # don't match.
-    if test "z$tst" != "z$CPPUNIT_TEST_NAME"; then
-        touch $tst_log
-        echo ":test-result: SKIP $tst (disabled by CPPUNIT_TEST_NAME)" > $test_output
-        exit 0;
-    fi
-fi
-
 export LOOL_LOGLEVEL=trace
 
 if test "z$enable_debug" != "ztrue"; then
diff --git a/wsd/Storage.cpp b/wsd/Storage.cpp
index 0be7c7c7b..8c8a8ddd8 100644
--- a/wsd/Storage.cpp
+++ b/wsd/Storage.cpp
@@ -331,8 +331,7 @@ std::string LocalStorage::loadStorageFileToLocal(const Authorization& /*auth*/,
         // Fallback to copying.
         if (!Poco::File(getRootFilePath()).exists())
         {
-            LOG_INF("Copying " << LOOLWSD::anonymizeUrl(publicFilePath) << " to " << getRootFilePathAnonym());
-            Poco::File(publicFilePath).copyTo(getRootFilePath());
+            FileUtil::copyFileTo(publicFilePath, getRootFilePath());
             _isCopy = true;
         }
     }
@@ -371,10 +370,7 @@ StorageBase::SaveResult LocalStorage::saveLocalFileToStorage(const Authorization
         LOG_TRC("Saving local file to local file storage (isCopy: " << _isCopy << ") for " << getRootFilePathAnonym());
         // Copy the file back.
         if (_isCopy && Poco::File(getRootFilePath()).exists())
-        {
-            LOG_INF("Copying " << getRootFilePathAnonym() << " to " << LOOLWSD::anonymizeUrl(getUri().getPath()));
-            Poco::File(getRootFilePath()).copyTo(getUri().getPath());
-        }
+            FileUtil::copyFileTo(getRootFilePath(), getUri().getPath());
 
         // update its fileinfo object. This is used later to check if someone else changed the
         // document while we are/were editing it
diff --git a/wsd/TraceFile.hpp b/wsd/TraceFile.hpp
index 82f5a75ce..e95fbb2e2 100644
--- a/wsd/TraceFile.hpp
+++ b/wsd/TraceFile.hpp
@@ -25,6 +25,7 @@
 #include "Protocol.hpp"
 #include "Log.hpp"
 #include "Util.hpp"
+#include "FileUtil.hpp"
 
 /// Dumps commands and notification trace.
 class TraceFileRecord
@@ -141,8 +142,7 @@ public:
                 filename += '.' + origPath.getExtension();
                 snapshot = Poco::Path(_path, filename).toString();
 
-                LOG_TRC("TraceFile: Copying local file [" << localPath << "] to snapshot [" << snapshot << "].");
-                Poco::File(localPath).copyTo(snapshot);
+                FileUtil::copyFileTo(localPath, snapshot);
                 snapshot = Poco::URI(Poco::URI("file://"), snapshot).toString();
 
                 LOG_TRC("TraceFile: Mapped URL " << url << " to " << snapshot);
commit 1c0fb25e90dda583d5a81bc7c228ad33d1243ddb
Author:     Jan Holesovsky <kendy at collabora.com>
AuthorDate: Fri Jan 17 15:21:36 2020 +0100
Commit:     Jan Holesovsky <kendy at collabora.com>
CommitDate: Tue Jan 21 12:43:17 2020 +0100

    android: When the cell cursor moves, focus the document.
    
    This particularly happens when the user has entered something into the
    formula input bar - after hitting Enter, the focus should return to the
    sheet.
    
    This is consistent with the desktop LibreOffece, where hitting Enter in
    the formula input bar returns focus to the sheet too.
    
    Change-Id: I020e008022e958f471d0cb31a8de986f576ba704
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/86984
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js
index 0d64ded2d..f031a2050 100644
--- a/loleaflet/src/layer/tile/TileLayer.js
+++ b/loleaflet/src/layer/tile/TileLayer.js
@@ -2838,6 +2838,10 @@ L.TileLayer = L.GridLayer.extend({
 			this._map.addLayer(this._cellCursorMarker);
 
 			this._addDropDownMarker();
+
+			// when the cell cursor is moving, the user is in the document,
+			// and the focus should leave the cell input bar
+			this._map.fire('editorgotfocus');
 		}
 		else if (this._cellCursorMarker) {
 			this._map.removeLayer(this._cellCursorMarker);
commit 91175c854af80ef35ee3e7a8227600e56b1cb8d6
Author:     Alexandru Vlăduţu <alexandru.vladutu at 1and1.ro>
AuthorDate: Tue Jan 21 11:01:11 2020 +0200
Commit:     Jan Holesovsky <kendy at collabora.com>
CommitDate: Tue Jan 21 11:34:12 2020 +0100

    tdf#130103: loleaflet fix save from menu for spreadsheets
    
    When editing a cell in a spreadsheet, if you don't focus on another
    element before clicking 'Save' in the menu, it won't actually save the
    last edited cell. This is different from the 'save' toolbar icon, which
    actually saves it.
    
    Change-Id: I5bb7551ce9fad28f3108bee8a7a44735e01f9d93
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/87119
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/loleaflet/src/control/Control.Menubar.js b/loleaflet/src/control/Control.Menubar.js
index 89f6328b7..d55079042 100644
--- a/loleaflet/src/control/Control.Menubar.js
+++ b/loleaflet/src/control/Control.Menubar.js
@@ -1092,7 +1092,7 @@ L.Control.Menubar = L.Control.extend({
 			if (this._map._permission !== 'readonly') {
 				this._map.fire('postMessage', {msgId: 'UI_Save'});
 				if (!this._map._disableDefaultAction['UI_Save']) {
-					this._map.save(true, true);
+					this._map.save(false, false);
 				}
 			}
 		} else if (id === 'saveas') {
commit ebaca16c4f28ae7a499c632b70b24eaaa1083439
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Mon Jan 20 16:12:47 2020 +0200
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Tue Jan 21 10:26:58 2020 +0100

    tdf#128509: Make the column and row headers tappable on touch devices
    
    After you have sleected a table on a text document in the iOS (and
    Android) app, you are supposed to be able to tap the "header"
    rectangle that is painted for each column and row, in order to select
    the whole of that column or row. But this worked only in web-based
    Online with a desktop browser, for clicking it with a mouse.
    
    Was much more complicated than expected. But now it seems to work. One
    needs to use Marker instead of Rectangle.
    
    Change-Id: I4f701c70dd4edce6a3edb6fcf9feffa7b7969a8c
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/87079
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Tor Lillqvist <tml at collabora.com>

diff --git a/loleaflet/css/loleaflet.css b/loleaflet/css/loleaflet.css
index 7d3326687..4f80a03af 100644
--- a/loleaflet/css/loleaflet.css
+++ b/loleaflet/css/loleaflet.css
@@ -91,6 +91,15 @@
 	cursor: row-resize;
 }
 
+.table-row-or-column-select-marker {
+	margin: 0px;
+	width: 24px;
+	height: 24px;
+	background-image: url('images/table-row-or-column-select-marker.svg');
+	background-size: cover;
+	background-repeat: no-repeat;
+}
+
 .table-move-marker {
 	margin-left: 0px;
 	margin-top: 0px;
diff --git a/loleaflet/images/table-row-or-column-select-marker.svg b/loleaflet/images/table-row-or-column-select-marker.svg
new file mode 100644
index 000000000..6ee9d4673
--- /dev/null
+++ b/loleaflet/images/table-row-or-column-select-marker.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="0" y="0" width="1" height="1" fill="#dddddd" />
+</svg>
diff --git a/loleaflet/src/layer/tile/TileLayer.TableOverlay.js b/loleaflet/src/layer/tile/TileLayer.TableOverlay.js
index 25e8f93e7..96c27ecb5 100644
--- a/loleaflet/src/layer/tile/TileLayer.TableOverlay.js
+++ b/loleaflet/src/layer/tile/TileLayer.TableOverlay.js
@@ -18,6 +18,11 @@ L.TileLayer.include({
 		var point = this._latLngToTwips(this._map.unproject(new L.Point(pixel, 0)));
 		return point.x;
 	},
+	_convertTwipsToPixels: function(twips) {
+		var point = this._twipsToLatLng(twips)
+		point = this._map.project(point);
+		return point;
+	},
 	hasTableSelection: function () {
 		return this._currentTableData.rows != null || this._currentTableData.columns != null;
 	},
@@ -218,10 +223,14 @@ L.TileLayer.include({
 			return;
 
 		var startX, endX, startY, endY;
-		var point1, point2;
+		var point1;
 
 		var delta1 = this._convertPixelToTwips(this._selectionHeaderDistanceFromTable);
-		var delta2 = this._convertPixelToTwips(this._selectionHeaderDistanceFromTable + this._selectionHeaderHeight);
+
+		// The 24 is the height and width of the .table-row-or-column-select-marker in loleaflet.css
+		var height = 24;
+		var width = height;
+		var selectionMarkerNominalSize = this._convertPixelToTwips(width);
 
 		for (var i = 0; i < positions.length - 1; i++) {
 			if (type === 'column') {
@@ -229,23 +238,29 @@ L.TileLayer.include({
 				endX = this._tablePositionColumnOffset + positions[i + 1];
 				startY = start;
 				endY = end;
-				point1 = this._twipsToLatLng(new L.Point(startX, startY  - delta1), this._map.getZoom());
-				point2 = this._twipsToLatLng(new L.Point(endX, startY  - delta2), this._map.getZoom());
+				point1 = this._twipsToLatLng(new L.Point(startX, startY - delta1 - selectionMarkerNominalSize),
+							     this._map.getZoom());
+				width = this._convertTwipsToPixels(new L.Point(endX - startX, 0)).x - 2;
 			}
 			else {
 				startX = start;
 				endX = end;
 				startY = this._tablePositionRowOffset + positions[i];
 				endY = this._tablePositionRowOffset + positions[i + 1];
-				point1 = this._twipsToLatLng(new L.Point(startX - delta1, startY), this._map.getZoom());
-				point2 = this._twipsToLatLng(new L.Point(startX - delta2, endY), this._map.getZoom());
+				point1 = this._twipsToLatLng(new L.Point(startX - delta1 - selectionMarkerNominalSize, startY),
+							     this._map.getZoom());
+				height = this._convertTwipsToPixels(new L.Point(0, endY - startY)).y - 2;
 			}
 
-			var bounds = new L.LatLngBounds(point1, point2);
-			var selectionRectangle = new L.Rectangle(bounds, {
-				stroke: true, weight: 1, color: '#777777',
-				fillOpacity: 1, fillColor: '#dddddd'
-			});
+			var selectionRectangle = L.marker(point1,
+				{
+					icon: L.divIcon({
+						className: 'table-row-or-column-select-marker',
+						iconSize: [width, height],
+						iconAnchor: [0, 0],
+					}),
+					draggable: true,
+				});
 
 			selectionRectangle._start = { x: startX, y: startY };
 			selectionRectangle._end = { x: endX, y: endY };
@@ -255,7 +270,10 @@ L.TileLayer.include({
 			else
 				this._tableSelectionRowMarkers.push(selectionRectangle);
 
-			selectionRectangle.on('click', this._onSelectRowColumnClick, this);
+			selectionRectangle.on('down', this._onSelectRowColumnClick, this);
+			// We don't actually want this to be draggable of course, so use a dragstart
+			// handler that freezes it.
+			selectionRectangle.on('dragstart drag dragend', this._onSelectRowColumnDrag, this);
 			this._map.addLayer(selectionRectangle);
 		}
 	},
@@ -264,6 +282,10 @@ L.TileLayer.include({
 		this._postSelectTextEvent('start', e.target._start.x + 5, e.target._start.y + 5);
 		this._postSelectTextEvent('end', e.target._end.x - 5, e.target._end.y - 5);
 	},
+	_onSelectRowColumnDrag: function(e) {
+		e.target.freezeX(true);
+		e.target.freezeY(true);
+	},
 
 	// Update dragged text selection.
 	_onTableBorderResizeMarkerDrag: function (e) {
commit 09bb16ad78f71e285b6059774ce089b9ef1d006b
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Mon Jan 20 19:33:00 2020 +0000
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Mon Jan 20 22:04:40 2020 +0100

    util: for process thread count - ignore '.' and '..' in /proc/self/tasks
    
    Change-Id: Ieec6eaac475b4e318578cfc0d93c36e2395e6f19
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/87097
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Michael Meeks <michael.meeks at collabora.com>

diff --git a/common/Util.cpp b/common/Util.cpp
index 4dc0bdadf..0b3e8cbae 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -188,8 +188,12 @@ namespace Util
             return -1;
         }
         int tasks = 0;
-        while (readdir(fdDir))
-            tasks++;
+        struct dirent *i;
+        while ((i = readdir(fdDir)))
+        {
+            if (i->d_name[0] != '.')
+                tasks++;
+        }
         closedir(fdDir);
         return tasks;
     }
commit e7f527b0700e0288e3534d67dad5ab4975bdc03f
Author:     Pranam Lashkari <lpranam at collabora.com>
AuthorDate: Fri Jan 10 02:10:39 2020 +0530
Commit:     Jan Holesovsky <kendy at collabora.com>
CommitDate: Mon Jan 20 17:54:44 2020 +0100

    Mobile wizard: Sheet tab context menu conversion
    
    Sheet tab context menu converted to mobile wizard for mobile devices
    bugfix: prevented mobile wizard to appear in readonly mode
    which allowed sheets editing in readonly mode
    
    Change-Id: I64c9437d2171b0518aa3c08f06d8d65fb3d302af
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/86507
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Jan Holesovsky <kendy at collabora.com>

diff --git a/loleaflet/src/control/Control.ContextMenu.js b/loleaflet/src/control/Control.ContextMenu.js
index 954dab877..692bd8a41 100644
--- a/loleaflet/src/control/Control.ContextMenu.js
+++ b/loleaflet/src/control/Control.ContextMenu.js
@@ -114,7 +114,7 @@ L.Control.ContextMenu = L.Control.extend({
 		}
 		if (window.mode.isMobile()) {
 			window.contextMenuWizard = true;
-			var menuData = this.getMenuStructureForMobileWizard(contextMenu, true, '');
+			var menuData = this._map.getMenuStructureForMobileWizard(contextMenu, true, '');
 			if (spellingContextMenu === true) {
 				vex.timer = setInterval(function() {
 					map.fire('mobilewizard', menuData);
@@ -257,53 +257,6 @@ L.Control.ContextMenu = L.Control.extend({
 		}
 
 		return contextMenu;
-	},
-
-	getMenuStructureForMobileWizard: function(menu, mainMenu, itemCommand) {
-		if (itemCommand.includes('sep'))
-			return null;
-
-		var itemText = ''
-		if (menu.name)
-			itemText = menu.name;
-
-		var itemType = 'submenu';
-		var executionType = 'menu';
-		if (mainMenu) {
-			itemType = 'mainmenu';
-			executionType = 'menu';
-		} else if (!menu.items) {
-			itemType = 'menuitem';
-			executionType = 'command';
-		}
-
-		var menuStructure = {
-			type : itemType,
-			enabled : true,
-			text : itemText,
-			executionType : executionType,
-			children : []
-		};
-		if (itemCommand)
-			menuStructure['command'] = itemCommand;
-		if (menu.icon)
-			menuStructure['checked'] = true;
-
-		if (mainMenu) {
-			for (var menuItem in menu) {
-				var element = this.getMenuStructureForMobileWizard(menu[menuItem], false, menuItem);
-				if (element)
-					menuStructure['children'].push(element);
-			}
-		} else if (itemType == 'submenu') {
-			for (menuItem in menu.items) {
-				element = this.getMenuStructureForMobileWizard(menu.items[menuItem], false, menuItem);
-				if (element)
-					menuStructure['children'].push(element);
-			}
-		}
-
-		return menuStructure;
 	}
 });
 
diff --git a/loleaflet/src/control/Control.JSDialogBuilder.js b/loleaflet/src/control/Control.JSDialogBuilder.js
index eaa414018..dcf9517e6 100644
--- a/loleaflet/src/control/Control.JSDialogBuilder.js
+++ b/loleaflet/src/control/Control.JSDialogBuilder.js
@@ -1453,6 +1453,8 @@ L.Control.JSDialogBuilder = L.Control.extend({
 				// before close the wizard then execute the action
 				if (data.executionType === 'action') {
 					builder.map.menubar._executeAction(undefined, data.id);
+				} else if (data.executionType === 'callback') {
+					data.callback();
 				} else if (!builder.map._clip || !builder.map._clip.filterExecCopyPaste(data.command)) {
 					// Header / footer is already inserted.
 					if ((data.command.startsWith('.uno:InsertPageHeader') ||
diff --git a/loleaflet/src/control/Control.Tabs.js b/loleaflet/src/control/Control.Tabs.js
index eac204c3b..ac4b0f40b 100644
--- a/loleaflet/src/control/Control.Tabs.js
+++ b/loleaflet/src/control/Control.Tabs.js
@@ -43,60 +43,37 @@ L.Control.Tabs = L.Control.extend({
 		var docContainer = map.options.documentContainer;
 		this._tabsCont = L.DomUtil.create('div', 'spreadsheet-tabs-container', docContainer.parentElement);
 
-		L.installContextMenu({
-			selector: '.spreadsheet-tab',
-			className: 'loleaflet-font',
-			callback: (function(key) {
-				if (key === 'insertsheetbefore') {
-					map.insertPage(this._tabForContextMenu);
-				}
-				if (key === 'insertsheetafter') {
-					map.insertPage(this._tabForContextMenu + 1);
-				}
-			}).bind(this),
-			items: {
-				'insertsheetbefore': {name: _('Insert sheet before this')},
-				'insertsheetafter': {name: _('Insert sheet after this')},
-				'deletesheet': {name: _UNO('.uno:Remove', 'spreadsheet', true),
-						callback: (function(key, options) {
-							var nPos = this._tabForContextMenu;
-							vex.dialog.confirm({
-								message: _('Are you sure you want to delete sheet, %sheet% ?').replace('%sheet%', options.$trigger.text()),
-								callback: function(data) {
-									if (data) {
-										map.deletePage(nPos);
-									}
-								}
-							});
-						}).bind(this)
-				 },
-				'renamesheet': {name: _UNO('.uno:RenameTable', 'spreadsheet', true),
-							callback: (function(key, options) {
-								var nPos = this._tabForContextMenu;
-								vex.dialog.open({
-									message: _('Enter new sheet name'),
-									input: '<input name="sheetname" type="text" value="' + options.$trigger.text() + '" required />',
-									callback: function(data) {
-										map.renamePage(data.sheetname, nPos);
-									}
-								});
-							}).bind(this)
-				} ,
-				'showsheets': {
-					name: _UNO('.uno:Show', 'spreadsheet', true),
-					callback: (function() {
-						map.showPage();
-					}).bind(this)
-				},
-				'hiddensheets': {
-					name: _UNO('.uno:Hide', 'spreadsheet', true),
-					callback: (function() {
-						map.hidePage();
-					}).bind(this)
-				}
+		this._menuItem = {
+			'insertsheetbefore': {name: _('Insert sheet before this'),
+				callback: (this._insertSheetBefore).bind(this)
 			},
-			zIndex: 1000
-		});
+			'insertsheetafter': {name: _('Insert sheet after this'),
+				callback: (this._insertSheetAfter).bind(this)
+			},
+			'deletesheet': {name: _UNO('.uno:Remove', 'spreadsheet', true),
+				callback: (this._deleteSheet).bind(this)
+			},
+			'renamesheet': {name: _UNO('.uno:RenameTable', 'spreadsheet', true),
+				callback: (this._renameSheet).bind(this)
+			} ,
+			'showsheets': {
+				name: _UNO('.uno:Show', 'spreadsheet', true),
+				callback: (this._showSheet).bind(this),
+			},
+			'hiddensheets': {
+				name: _UNO('.uno:Hide', 'spreadsheet', true),
+				callback: (this._hideSheet).bind(this)
+			}
+		};
+
+		if (!window.mode.isMobile()) {
+			L.installContextMenu({
+				selector: '.spreadsheet-tab',
+				className: 'loleaflet-font',
+				items: this._menuItem,
+				zIndex: 1000
+			});
+		}
 
 		map.on('updateparts', this._updateDisabled, this);
 	},
@@ -105,6 +82,8 @@ L.Control.Tabs = L.Control.extend({
 		var parts = e.parts;
 		var selectedPart = e.selectedPart;
 		var docType = e.docType;
+		var map = this._map;
+
 		if (docType === 'text') {
 			return;
 		}
@@ -127,20 +106,29 @@ L.Control.Tabs = L.Control.extend({
 				var ssTabScroll = L.DomUtil.create('div', 'spreadsheet-tab-scroll', this._tabsCont);
 				ssTabScroll.id = 'spreadsheet-tab-scroll';
 
+				if (window.mode.isMobile()) {
+					var menuData = map.getMenuStructureForMobileWizard(this._menuItem, true, '');
+				}
+
 				for (var i = 0; i < parts; i++) {
 					if (e.hiddenParts.indexOf(i) !== -1)
 						continue;
 					var id = 'spreadsheet-tab' + i;
 					var tab = L.DomUtil.create('button', 'spreadsheet-tab', ssTabScroll);
 					L.DomEvent.enableLongTap(tab);
-					
+
 					L.DomEvent.on(tab, 'contextmenu', function(j) {
 						return function() {
 							this._tabForContextMenu = j;
-							$('spreadsheet-tab' + j).contextMenu();
+							if (window.mode.isMobile()) {
+								window.contextMenuWizard = true;
+								if (this._map._permission != 'readonly') this._map.fire('mobilewizard', menuData);
+							} else {
+								$('spreadsheet-tab' + j).contextMenu();
+							}
 						}
 					}(i).bind(this));
-					
+
 					tab.textContent = e.partNames[i];
 					tab.id = id;
 
@@ -168,7 +156,49 @@ L.Control.Tabs = L.Control.extend({
 			this._map._docLayer._clearReferences();
 			this._map.setPart(parseInt(part), /*external:*/ false, /*calledFromSetPartHandler:*/ true);
 		}
+	},
+
+	_insertSheetBefore: function() {
+		this._map.insertPage(this._tabForContextMenu);
+	},
+
+	_insertSheetAfter: function() {
+		this._map.insertPage(this._tabForContextMenu + 1);
+	},
+
+	_deleteSheet: function() {
+		var map = this._map;
+		var nPos = this._tabForContextMenu;
+		vex.dialog.confirm({
+			message: _('Are you sure you want to delete sheet, %sheet% ?').replace('%sheet%', $('#spreadsheet-tab' + this._tabForContextMenu).text()),
+			callback: function(data) {
+				if (data) {
+					map.deletePage(nPos);
+				}
+			}
+		});
+	},
+
+	_renameSheet: function() {
+		var map = this._map;
+		var nPos = this._tabForContextMenu;
+		vex.dialog.open({
+			message: _('Enter new sheet name'),
+			input: '<input name="sheetname" type="text" value="' + $('#spreadsheet-tab' + this._tabForContextMenu).text() + '" required />',
+			callback: function(data) {
+				map.renamePage(data.sheetname, nPos);
+			}
+		});
+	},
+
+	_showSheet: function() {
+		this._map.showPage();
+	},
+
+	_hideSheet: function() {
+		this._map.hidePage();
 	}
+
 });
 
 L.control.tabs = function (options) {
diff --git a/loleaflet/src/map/Map.js b/loleaflet/src/map/Map.js
index eab0f9668..99d555b08 100644
--- a/loleaflet/src/map/Map.js
+++ b/loleaflet/src/map/Map.js
@@ -1756,6 +1756,58 @@ L.Map = L.Evented.extend({
 			this.focusLayer = null;
 		}
 	},
+
+	getMenuStructureForMobileWizard: function(menu, mainMenu, itemCommand) {
+		if (itemCommand.includes('sep'))
+			return null;
+
+		var itemText = ''
+		if (menu.name)
+			itemText = menu.name;
+
+		var itemType = 'submenu';
+		var executionType = 'menu';
+		if (mainMenu) {
+			itemType = 'mainmenu';
+			executionType = 'menu';
+		} else if (menu.callback) {
+			itemType = 'menuitem';
+			executionType = 'callback';
+		} else if (!menu.items) {
+			itemType = 'menuitem';
+			executionType = 'command';
+		}
+
+		var menuStructure = {
+			type : itemType,
+			enabled : true,
+			text : itemText,
+			executionType : executionType,
+			children : []
+		};
+		if (itemCommand)
+			menuStructure['command'] = itemCommand;
+		if (menu.icon)
+			menuStructure['checked'] = true;
+		if (menu.callback)
+			menuStructure['callback'] = menu.callback;
+
+		if (mainMenu) {
+			for (var menuItem in menu) {
+				var element = this.getMenuStructureForMobileWizard(menu[menuItem], false, menuItem);
+				if (element)
+					menuStructure['children'].push(element);
+			}
+		} else if (itemType == 'submenu') {
+			for (menuItem in menu.items) {
+				element = this.getMenuStructureForMobileWizard(menu.items[menuItem], false, menuItem);
+				if (element)
+					menuStructure['children'].push(element);
+			}
+		}
+
+		return menuStructure;
+	}
 });
 
 L.map = function (id, options) {
commit 081ce41e5042707753663a377c497d98d83f49e2
Author:     Weblate <noreply at documentfoundation.org>
AuthorDate: Mon Jan 20 10:13:45 2020 +0100
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Mon Jan 20 11:55:27 2020 +0100

    update translations
    
    LibreOffice Online/android-app (Asturian)
    Currently translated at 38.4% (38 of 99 strings)
    
    Change-Id: I8e041ba673955f00b4ff5ffa6c3813b25c670cdf
    
    update translations
    
    LibreOffice Online/android-app (Catalan)
    Currently translated at 98.0% (96 of 98 strings)
    
    Change-Id: I33985ea09845c154626cd0cb45d78e1818ac2e9b
    
    update translations
    
    LibreOffice Online/loleaflet-help (Dutch)
    Currently translated at 48.3% (201 of 416 strings)
    
    Change-Id: I4b3e98671b2ef20b0ca806d131458a004ece3a3c
    
    update translations
    
    LibreOffice Online/loleaflet-help (Basque)
    Currently translated at 90.1% (375 of 416 strings)
    
    Change-Id: I2b16c6e90b2a3344bace7653614b2a7fd6e5c802
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Basque)
    Currently translated at 100.0% (283 of 283 strings)
    
    Change-Id: I883b9548eb1efe3af7a2e40393ebf735f33a677d
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Esperanto)
    Currently translated at 63.3% (179 of 283 strings)
    
    Change-Id: I847eb27ce7f1971295e9ed274b5028e627b923b6
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Catalan)
    Currently translated at 97.9% (277 of 283 strings)
    
    Change-Id: I3be1b00a13d067390fa190da4fccc952da5076b4
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Asturian)
    Currently translated at 33.9% (96 of 283 strings)
    
    Change-Id: I8808049c8f058b62af323033725c7311bc1e2be5
    
    update translations
    
    LibreOffice Online/loleaflet-help (Catalan)
    Currently translated at 65.9% (274 of 416 strings)
    
    Change-Id: I1ae5c4d3cddd11a83d9254686182fc00d1b801d9
    
    update translations
    
    LibreOffice Online/loleaflet-help (Italian)
    Currently translated at 100.0% (416 of 416 strings)
    
    Change-Id: I6651eb476655443b236ae8e9f934828f760a4b3e
    
    update translations
    
    LibreOffice Online/loleaflet-help (French)
    Currently translated at 71.2% (296 of 416 strings)
    
    Change-Id: I68629ed044bd30c854d823caf70df954912fdc63
    
    update translations
    
    LibreOffice Online/loleaflet-help (Basque)
    Currently translated at 85.3% (355 of 416 strings)
    
    Change-Id: I624ea006ffafe977983dc823622222c903a17be2
    
    update translations
    
    LibreOffice Online/loleaflet-help (Spanish)
    Currently translated at 99.8% (415 of 416 strings)
    
    Change-Id: Ib8ba3e6397fcd396c8d01fbfba48db91bee39238
    
    update translations
    
    LibreOffice Online/loleaflet-help (Catalan)
    Currently translated at 65.4% (272 of 416 strings)
    
    Change-Id: I364c39de59a4b3a4cb705a9f0eff76aa94e247e4
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Catalan)
    Currently translated at 97.5% (276 of 283 strings)
    
    Change-Id: Ied8ff70562b4d98e181662e1e60496ef2b5bf4c7
    
    update translations
    
    LibreOffice Online/loleaflet-ui (Bulgarian)
    Currently translated at 100.0% (283 of 283 strings)
    
    Change-Id: I0f777f6dc44538153b5b7bd5a4f731e0e5110f66
    
    update translations
    
    LibreOffice Online/loleaflet-help (French)
    Currently translated at 71.2% (296 of 416 strings)
    
    Change-Id: I4b759612e69377768f5e165c4bc8daaf8f1e177c
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/86990
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Andras Timar <andras.timar at collabora.com>

diff --git a/android/app/src/main/res/values-ast/strings.xml b/android/app/src/main/res/values-ast/strings.xml
index ed5f15400..a3f158553 100644
--- a/android/app/src/main/res/values-ast/strings.xml
+++ b/android/app/src/main/res/values-ast/strings.xml
@@ -28,4 +28,14 @@
     <string name="new_presentation">Presentación nueva</string>
     <string name="new_textdocument">Documentu de testu nuevu</string>
     <string name="temp_file_saving_disabled">Esti ficheru ye namái de llectura; nun se pue guardar.</string>
+    <string name="action_overwrite">Sobroscribir</string>
+    <string name="search_label">Dir</string>
+    <string name="cancel_label">Encaboxar</string>
+    <string name="positive_ok">Aceutar</string>
+    <string name="action_cancel">Encaboxar</string>
+    <string name="negative_cancel">Encaboxar</string>
+    <string name="about_notice">Amosar avisu</string>
+    <string name="about_license">Amosar llicencia</string>
+    <string name="no_items">Nun hai elementos</string>
+    <string name="no_recent_items">Nun hai elementos recientes</string>
 </resources>
\ No newline at end of file
diff --git a/android/app/src/main/res/values-ca/strings.xml b/android/app/src/main/res/values-ca/strings.xml
index 9ec00eb61..2c7ea4532 100644
--- a/android/app/src/main/res/values-ca/strings.xml
+++ b/android/app/src/main/res/values-ca/strings.xml
@@ -95,4 +95,5 @@
     <string name="owncloud_unauthorized">No es pot iniciar una sessió al servidor al núvol. Comproveu la configuració.</string>
     <string name="owncloud_wrong_connection">No es pot connectar amb el servidor al núvol. Comproveu la configuració.</string>
     <string name="usb_connected_configure">S\'ha connectat via USB; configureu l\'aparell.</string>
+    <string name="up_description">Al directori superior</string>
 </resources>
\ No newline at end of file
diff --git a/loleaflet/po/help-ca.po b/loleaflet/po/help-ca.po
index 4e149f0a8..25b36a803 100644
--- a/loleaflet/po/help-ca.po
+++ b/loleaflet/po/help-ca.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2019-12-15 17:50+0200\n"
-"PO-Revision-Date: 2020-01-07 10:58+0000\n"
+"PO-Revision-Date: 2020-01-18 18:26+0000\n"
 "Last-Translator: Adolfo Jayme Barrientos <fito at libreoffice.org>\n"
 "Language-Team: Catalan <https://weblate.documentfoundation.org/projects/libo_online/loleaflet-help/ca/>\n"
 "Language: ca\n"
@@ -1143,7 +1143,7 @@ msgstr "Reparació del document"
 
 #: html/loleaflet-help.html%2Bdiv.p:289-5
 msgid "When multiple people edit the same document concurrently, it is possible for their changes to conflict and this can cause some confusion. The Document Repair function allows users to undo other editor’s changes to the document to a previous state."
-msgstr ""
+msgstr "Quan diverses persones editen el mateix document simultàniament, és possible que llurs modificacions entrin en conflicte i provoquin confusió. La funció Reparació del document permet als usuaris desfer les modificacions fetes per altres usuaris i restablir el document a un estat anterior."
 
 #: html/loleaflet-help.html%2Bdiv.p:290-5
 msgid "To jump back to the selected state, select it with the mouse and hit <span class=\"ui\">Jump to state</span>."
@@ -1227,7 +1227,7 @@ msgstr "Manipulació d'imatges"
 
 #: html/loleaflet-help.html%2Bdiv.p:320-5
 msgid "<span class=\"productname\">%productName</span> inserts images in the text document from your local computer or from your cloud storage. Inserted images are always embedded in the document."
-msgstr ""
+msgstr "El <span class=\"productname\">%productName</span> insereix imatges al document de text des del vostre ordinador local o a partir del magatzem al núvol. Les imatges inserides són sempre incrustades al document."
 
 #: html/loleaflet-help.html%2Bdiv.p:321-5
 msgid "<span class=\"def\">Insert image:</span> Clicking on the <span class=\"ui\">Insert image</span> icon allows you to choose an image from the cloud storage's folders and shares."
@@ -1263,7 +1263,7 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.p:331-5
 msgid "To systematically spell-check the whole document use the <span class=\"ui\">Tools</span> menu’s <span class=\"ui\">Spelling</span> option."
-msgstr ""
+msgstr "Per a comprovar sistemàticament l'ortografia de tot el document, trieu <span class=\"ui\">Eines</span> ▸ <span class=\"ui\">Ortografia</span>."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:337-5
 msgid "You edit an online spreadsheet in the same way you edit a desktop spreadsheet. Operations like entering data, selecting ranges, columns, rows or sheets are the same. Use the keyboard, menus or toolbar to command actions in the spreadsheet. Dragging cells contents to fill cells with data is also supported. Copy, cut and paste commands are available from the context menu. Following entered data with a <span class=\"kbd\">Tab</span> will move the cursor to the next cell to the right, and with an <span class=\"kbd\">Enter</span> to the cell below for easy further data entry."
@@ -1271,7 +1271,7 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.p:340-5
 msgid "Formulas are entered in the formula bar. Enter '=' and insert the formula."
-msgstr ""
+msgstr "Les fórmules s'insereixen a la barra de fórmules. Introduïu «=» i inseriu la fórmula."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:341-5
 msgid "All spreadsheets functions and mathematical rules applies."
@@ -1327,7 +1327,7 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.ol.li.p:373-11
 msgid "To remove the validity of the cell, open the dialog and set the <span class=\"ui\">Allow</span> list to “All values”."
-msgstr ""
+msgstr "Per a suprimir la validesa d'una cel·la, obriu el diàleg i definiu «Tots els valors» a la llista <span class=\"ui\">Permet</span>."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:375-5
 msgid "<span class=\"def\">Comments:</span> In a spreadsheet you can insert one comment per cell. When you select <span class=\"ui\">Insert comment</span>, a popup appears that allows you to write the content for the comment. A red dot shows on the top right corner of the cell when it has a comment. Hover the mouse on the cell to display comments."
@@ -1367,7 +1367,7 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.h4:398-5
 msgid "Handling Tables"
-msgstr ""
+msgstr "Manipulació de taules"
 
 #: html/loleaflet-help.html%2Bdiv.div.p:399-5
 msgid "Insert tables with proper icon in the toolbar. Select the initial number of rows and columns. Add rows and columns with the cell context menu. Merge cells with the <span class=\"ui\">Table</span> menu. The default paragraph style inside cells is “Table contents”."
@@ -1391,7 +1391,7 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.h4:406-5
 msgid "Other advanced features"
-msgstr ""
+msgstr "Altres funcionalitats avançades"
 
 #: html/loleaflet-help.html%2Bdiv.div.p:407-5
 msgid "<span class=\"def\">Comments:</span> Comments are inserted in the text and displayed on the right side of the screen."
@@ -1431,11 +1431,11 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.p:426-5
 msgid "Click on any slide thumbnail in the pane to switch to this slide to view or edit it."
-msgstr ""
+msgstr "Feu clic a qualsevol miniatura de diapositiva per a canviar a aquesta i visualitzar-la o editar-la."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:427-5
 msgid "Use the slide pane toolbar in the bottom to start the slideshow, add slide, duplicate or delete the current slide."
-msgstr ""
+msgstr "Feu servir la barra d'eines a la part inferior de la subfinestra de diapositives per a iniciar la presentació o afegir, duplicar o suprimir diapositives."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:430-5
 msgid "<span class=\"def\">Slide layouts:</span> <span class=\"productname\">%productName</span> Impress let you change the slide layout. Select the desired slide layout in the drop-down layout list."
@@ -1459,31 +1459,31 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.h4:439-5
 msgid "What are the documents file formats supported by <span class=\"productname\">%productName</span>?"
-msgstr ""
+msgstr "Quins són els formats de fitxer compatibles amb el <span class=\"productname\">%productName</span>?"
 
 #: html/loleaflet-help.html%2Bdiv.p:440-5
 msgid "<span class=\"productname\">%productName</span> supports both reading and writing for the following file formats:"
-msgstr ""
+msgstr "El <span class=\"productname\">%productName</span> admet la lectura i l'escriptura dels formats de fitxer següents:"
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:442-11
 msgid "Text documents: Microsoft formats DOC, DOCX, RTF. OpenDocument Format ODT"
-msgstr ""
+msgstr "Documents de text.— Formats de Microsoft DOC, DOCX i RTF. Format OpenDocument ODT."
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:443-11
 msgid "Spreadsheets: Microsoft formats XLS, XLSX, OpenDocument Format ODS"
-msgstr ""
+msgstr "Fulls de càlcul.— Formats de Microsoft XLS i XLSX. Format OpenDocument ODS."
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:444-11
 msgid "Presentations: Microsoft formats PPT, PPTX, OpenDocument Format ODP"
-msgstr ""
+msgstr "Presentacions.— Formats de Microsoft PPT i PPTX. Format OpenDocument ODP."
 
 #: html/loleaflet-help.html%2Bdiv.p:446-5
 msgid "In addition it can provide viewing for Visio, Keynote, Numbers, and Pages formats."
-msgstr ""
+msgstr "També és possible visualitzar els formats del Visio, el Keynote, el Numbers i el Pages."
 
 #: html/loleaflet-help.html%2Bdiv.h4:447-5
 msgid "How do I save a document with another name?"
-msgstr ""
+msgstr "Com pot desar un document amb un altre nom?"
 
 #: html/loleaflet-help.html%2Bdiv.ol.li.p:449-11
 msgid "Hover the mouse on the document name in the menu bar."
@@ -1808,4 +1808,4 @@ msgstr ""
 
 #: html/loleaflet-help.html%2Bdiv.div.ol.li.p:575-11
 msgid "Set the properties of the element of the object."
-msgstr ""
+msgstr "Definiu les propietats de l'element de l'objecte."
diff --git a/loleaflet/po/help-es.po b/loleaflet/po/help-es.po
index 38b0514ea..45f5b3e19 100644
--- a/loleaflet/po/help-es.po
+++ b/loleaflet/po/help-es.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2019-12-15 17:50+0200\n"
-"PO-Revision-Date: 2020-01-09 07:59+0000\n"
+"PO-Revision-Date: 2020-01-18 16:24+0000\n"
 "Last-Translator: Adolfo Jayme Barrientos <fito at libreoffice.org>\n"
 "Language-Team: Spanish <https://weblate.documentfoundation.org/projects/libo_online/loleaflet-help/es/>\n"
 "Language: es\n"
@@ -1267,7 +1267,7 @@ msgstr "Para comprobar la ortografía del documento completo, utilice el menú <
 
 #: html/loleaflet-help.html%2Bdiv.div.p:337-5
 msgid "You edit an online spreadsheet in the same way you edit a desktop spreadsheet. Operations like entering data, selecting ranges, columns, rows or sheets are the same. Use the keyboard, menus or toolbar to command actions in the spreadsheet. Dragging cells contents to fill cells with data is also supported. Copy, cut and paste commands are available from the context menu. Following entered data with a <span class=\"kbd\">Tab</span> will move the cursor to the next cell to the right, and with an <span class=\"kbd\">Enter</span> to the cell below for easy further data entry."
-msgstr "Edite una hoja de cálculo en línea de la misma forma que una hoja de trabajo del escritorio. Las operaciones de entrada de datos, la selección de intervalos, filas, columnas o hojas de cálculo son las mismas. Utilice el teclado, los menús o la barra de herramientas para activar comandos en la hoja de cálculo. Arrastrar el contenido de las celdas para llenar otras celdas también es posible. Los comandos de copiar, cortar y pegar también están disponibles en los menús contextuales. Tecla <span class=\"kbd\">Tab</span> después de entrar datos mueve el cursor a la siguiente celda a la derecha y con un <span class=\"kbd\">Enter</span> se mueve a la celda siguiente facilitando la entrada de datos."
+msgstr "Edite una hoja de cálculo en línea de la misma forma que una hoja de trabajo del escritorio. Las operaciones de entrada de datos, la selección de intervalos, filas, columnas o hojas de cálculo son las mismas. Utilice el teclado, los menús o la barra de herramientas para activar órdenes en el libro. Arrastrar el contenido de las celdas para llenar otras celdas también es posible. Las órdenes de copiar, cortar y pegar también están disponibles en los menús contextuales. La tecla <span class=\"kbd\">Tab</span> después de introducir datos mueve el cursor a la siguiente celda a la derecha y con un <span class=\"kbd\">Intro</span> se mueve a la celda inmediatamente debajo, lo que facilita la entrada de más datos."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:340-5
 msgid "Formulas are entered in the formula bar. Enter '=' and insert the formula."
@@ -1467,15 +1467,15 @@ msgstr "<span class=\"productname\">%productName</span> admite la lectura y escr
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:442-11
 msgid "Text documents: Microsoft formats DOC, DOCX, RTF. OpenDocument Format ODT"
-msgstr "Documentos de texto: formatos Microsoft DOC, DOCX, RTF. OpenDocument Format ODT"
+msgstr "Documentos de texto.— Formatos de Microsoft DOC, DOCX y RTF. Formato OpenDocument ODT."
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:443-11
 msgid "Spreadsheets: Microsoft formats XLS, XLSX, OpenDocument Format ODS"
-msgstr "Hojas de calculo: formatos Microsoft XLS, XLSX, OpenDocument Format ODS"
+msgstr "Hojas de cálculo.— Formatos de Microsoft XLS y XLSX. Formato OpenDocument ODS."
 
 #: html/loleaflet-help.html%2Bdiv.ul.li.p:444-11
 msgid "Presentations: Microsoft formats PPT, PPTX, OpenDocument Format ODP"
-msgstr "Presentaciones: formatos Microsoft PPT, PPTX, OpenDocument Format ODP"
+msgstr "Presentaciones.— Formatos de Microsoft PPT y PPTX. Formato OpenDocument ODP."
 
 #: html/loleaflet-help.html%2Bdiv.p:446-5
 msgid "In addition it can provide viewing for Visio, Keynote, Numbers, and Pages formats."
@@ -1491,7 +1491,7 @@ msgstr "Pase el ratón por encima del nombre del documento en la barra de menús
 
 #: html/loleaflet-help.html%2Bdiv.ol.li.p:450-11
 msgid "Type the new file name in the text box and press <span class=\"kbd\">Enter</span>."
-msgstr "Escriba un nuevo nombre de archivo en el cuadro de texto y pulse <span class=\"kbd\">Enter</span>."
+msgstr "Escriba un nombre de archivo nuevo en el cuadro de texto y oprima <span class=\"kbd\">Intro</span>."
 
 #: html/loleaflet-help.html%2Bdiv.p:452-5
 msgid "A copy of the document is saved with the new name in the same folder."
diff --git a/loleaflet/po/help-eu.po b/loleaflet/po/help-eu.po
index 734b6f46a..9eee06dba 100644
--- a/loleaflet/po/help-eu.po
+++ b/loleaflet/po/help-eu.po
@@ -3,7 +3,7 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2019-12-15 17:50+0200\n"
-"PO-Revision-Date: 2020-01-15 09:56+0000\n"
+"PO-Revision-Date: 2020-01-20 09:13+0000\n"
 "Last-Translator: Asier Sarasua Garmendia <asiersar at yahoo.com>\n"
 "Language-Team: Basque <https://weblate.documentfoundation.org/projects/libo_online/loleaflet-help/eu/>\n"
 "Language: eu\n"
@@ -1283,7 +1283,7 @@ msgstr "Formulen lengoaia ezagun egingo zaio kalkulu-orrien edozein erabiltzaile
 
 #: html/loleaflet-help.html%2Bdiv.div.p:346-5
 msgid "<span class=\"def\">Direct formatting:</span> You can format spreadsheets cells, columns, rows and sheets by formatting directly from the menus, toolbar or context menus. Direct formatting applies only to the current object selected. To format a cell either use the menu or hit <span class=\"kbd\">Ctrl</span> + <span class=\"kbd\">1</span>. The dialog allows complex and custom number formatting, as well as font, complex border, background, cell protection and other options."
-msgstr "<span class=\"def\">Formatu zuzena:</span> Kalkulu-orrietako gelaxken, zutabeen, errenkaden eta orrien formatua zuzenean moldatu daiteke menuak, tresna-barra edo laster-menuak erabilita. Formatu zuzena hautatutako uneko objektuari soilik aplikatuko zaio. Gelaxka bati formatua emateko, erabili menua edo sakatu < span class=\"kbd\">Ctrl</span> + <span class=\"kbd\">1</span>. Elkarrizketa-koadroak zenbakien formatu konplexu eta pertsonalizatuak ahalbidetzen ditu, bai eta letra-tipoak, ertz konplexuak, atzeko planoa, gelaxken babesa eta beste elementu batzuk aldatzea ere."
+msgstr "<span class=\"def\">Formatu zuzena:</span> Kalkulu-orrietako gelaxken, zutabeen, errenkaden eta orrien formatua zuzenean moldatu daiteke menuak, tresna-barra edo laster-menuak erabilita. Formatu zuzena hautatutako uneko objektuari soilik aplikatuko zaio. Gelaxka bati formatua emateko, erabili menua edo sakatu <span class=\"kbd\">Ctrl</span> + <span class=\"kbd\">1</span>. Elkarrizketa-koadroak zenbakien formatu konplexu eta pertsonalizatuak ahalbidetzen ditu, bai eta letra-tipoak, ertz konplexuak, atzeko planoa, gelaxken babesa eta beste elementu batzuk aldatzea ere."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:350-5
 msgid "<span class=\"def\">Sorting data:</span> You can sort a list of numbers or text ascending or descending. <span class=\"productname\">%productName</span> automatically detects cells that are headers, and adjoining columns, to extend the selection."
@@ -1323,7 +1323,7 @@ msgstr "Hautatu baliozkotasun-irizpidea <span class=\"ui\">Onartu</span> goitibe
 
 #: html/loleaflet-help.html%2Bdiv.div.ol.li.p:370-9
 msgid "Use the <span class=\"ui\">Input Help</span> and <span class=\"ui\">Error Alert</span> tabs to enhance the user interactions. Click <span class=\"ui\">OK</span> to close the dialog."
-msgstr ""
+msgstr "Erabili <span class=\"ui\">Sarreraren laguntza</span> eta <span class=\"ui\">Errore-mezua</span> fitxak erabiltzaile-elkarrekintzak hobetzeko. Egin klik <span class=\"ui\">Ados</span> aukeran elkarrizketa-koadroa ixteko."
 
 #: html/loleaflet-help.html%2Bdiv.div.ol.li.p:373-11
 msgid "To remove the validity of the cell, open the dialog and set the <span class=\"ui\">Allow</span> list to “All values”."
@@ -1335,11 +1335,11 @@ msgstr "<span class=\"def\">Iruzkinak:</span> Kalkulu-orrietan iruzkin bana sart
 
 #: html/loleaflet-help.html%2Bdiv.div.p:377-5
 msgid "<span class=\"def\">Conditional formatting:</span> <span class=\"productname\">%productName</span> adds symbols to each cell of a range based on cells conditions. Select the cell range and click the <span class=\"ui\">Conditional Formatting</span> icon on the toolbar. Select the symbol set to apply on the range."
-msgstr ""
+msgstr "<span class=\"def\">Baldintzapeko formatua:</span> <span class=\"productname\">%productName</span> aplikazioak ikurrak gehitzen dizkie barruti bateko gelaxkei, gelaxken baldintzetan oinarrituta. Hautatu gelaxka-barrutia eta egin klik tresna-barrako <span class=\"ui\">Baldintzapeko formatua</span> ikonoan. Hautatu barrutian aplikatuko den ikur multzoa."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:385-5
 msgid "<span class=\"productname\">%productName</span> edits text documents in the same way you edit a desktop document. It provides a What You See Is What You Get (WYSIWYG) layout – that conveniently lays out the document as it will be printed. Operations like typing text, cut, copy and pasting contents, selecting text, inserting, resizing, anchoring images, adding and handling tables and charts, are similar to a desktop word processor. Use the keyboard, menus and toolbars to interact with your document."
-msgstr ""
+msgstr "<span class=\"productname\">%productName</span> aplikazioarekin testu-dokumentuak editatzeko modua mahaigaineko dokumentuetan erabiltzen den bera da. Ikusten Duzuna Eskuratzen Duzu (WYSIWYG) motako diseinua du: horren arabera, dokumentuaren diseinua inprimatuta agertuko den bera da. Testua idaztea, edukiak moztu, kopiatu eta itsastea, irudiak txertatu, tamainaz aldatu eta ainguratzea, taulak eta diagramak gehitzea eta maneiatzea, eta antzeko beste eragiketa batzuk mahaigaineko testu-prozesatzaileen antzekoak dira. Erabili teklatua, menuak eta tresna-barrak dokumentuarekin lan egiteko."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:388-5
 msgid "Context menus are available on clicking the right mouse button. The commands available in the context menu are related - not extensively - to the underlying object in the document."
@@ -1359,19 +1359,19 @@ msgstr "Formatu zuzenak, aldiz, dokumentu-edukian hautatutako zatiei soilik apli
 
 #: html/loleaflet-help.html%2Bdiv.div.p:393-5
 msgid "<span class=\"def\">Direct formatting:</span> You can format text document objects by formatting directly from the menus, toolbar or context menus. Direct formatting applies only to the current object selected."
-msgstr ""
+msgstr "<span class=\"def\">Formatu zuzena:</span> Testu-dokumentuko objektuei formatua emateko modu zuzena dago menuak, tresna-barra eta laster-menuak erabilita. Formatu zuzena unean hautatutako objektuari soilik aplikatzen zaio."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:394-5
 msgid "<span class=\"def\">Style formatting:</span> <span class=\"productname\">%productName</span> support paragraph styles. You can apply an existing paragraph style to a paragraph. Choose menu <span class=\"ui\">Edit</span> → <span class=\"ui\">Edit styles</span> to change style."
-msgstr ""
+msgstr "<span class=\"def\">Estiloen bidezko formatua:</span> <span class=\"productname\">%productName</span> aplikazioak paragrafo-estiloak onartzen ditu. Lehendik dagoen paragrafo-estiloak aplika dakizkieke paragrafoei. Aukeratu <span class=\"ui\">Editatu</span> → <span class=\"ui\">Editatu estiloak</span> estiloa aldatzeko."
 
 #: html/loleaflet-help.html%2Bdiv.div.h4:398-5
 msgid "Handling Tables"
-msgstr ""
+msgstr "Taulak maneiatzea"
 
 #: html/loleaflet-help.html%2Bdiv.div.p:399-5
 msgid "Insert tables with proper icon in the toolbar. Select the initial number of rows and columns. Add rows and columns with the cell context menu. Merge cells with the <span class=\"ui\">Table</span> menu. The default paragraph style inside cells is “Table contents”."
-msgstr ""
+msgstr "Txertatu taulak tresna-barran horretarako dagoen ikonoa erabilita. Hautatu errenkaden eta zutabeen hasierako kopurua. Gehitu errenkadak eta zutabeak gelaxken laster-menua erabilita. Batu gelaxkak <span class=\"ui\">Taula</span> menuaren bidez. Gelaxken barruko paragrafo-estilo lehenetsia \"Taula-edukiak\" da."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:401-5
 msgid "<span class=\"def\">Formatting cells:</span> Click in the cell or range of cells and choose menu <span class=\"ui\">Table</span> → <span class=\"ui\">Properties</span>. Fine tune the table with the properties dialog."
@@ -1399,11 +1399,11 @@ msgstr "<span class=\"def\">Iruzkinak:</span> Iruzkinak testuan txertatzen dira
 
 #: html/loleaflet-help.html%2Bdiv.div.p:408-5
 msgid "<span class=\"def\">Formatting marks:</span> Paragraph, page and unbreakable spaces are shown as marks to assisting text alignment, editing and formatting."
-msgstr ""
+msgstr "<span class=\"def\">Formatu-markak:</span> Paragrafoak, orrialdeak eta zuriune zatiezinak marka gisa erakusten dira testuen lerrokatzean, edizioan eta formatua ematean lagungarri izan daitezen."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:409-5
 msgid "<span class=\"def\">Fields:</span> A basic set of fields is available to insert in the document."
-msgstr ""
+msgstr "<span class=\"def\">Eremuak:</span>Eremuen oinarrizko multzo bat dago erabilgarri dokumentuan txertatzeko."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:410-5
 msgid "<span class=\"def\">Alphabetical index:</span> Existing alphabetical index can be updated with new entries."
@@ -1411,23 +1411,23 @@ msgstr "<span class=\"def\">Indize alfabetikoa:</span> Lehendik dagoen indize al
 
 #: html/loleaflet-help.html%2Bdiv.div.p:411-5
 msgid "<span class=\"def\">Page header and footer:</span> Headers and footers are available for the existing page style applied in the document at the cursor position."
-msgstr ""
+msgstr "<span class=\"def\">Goiburukoa eta orri-oina:</span> Badaude goiburukoak eta orri-oinak erabilgarri dokumentuari aplikatutako orrialde-estilorako, kurtsorearen kokalekuan."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:412-5
 msgid "<span class=\"def\">Footnotes and endnotes:</span> Footnotes and endnotes are supported, being rendered as they are shown."
-msgstr ""
+msgstr "<span class=\"def\">Oin-oharrak eta amaiera-oharrak:</span> Oin-oharrak eta amaiera-oharrak onartzen dira, eta bistaratzen diren moduan errendatzen dira."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:419-5
 msgid "<span class=\"productname\">%productName</span> Impress edits presentations in a way that should be familiar to people. Operations like typing text, cut, copy and pasting contents, selecting text , inserting, resizing, anchoring images, adding and handling tables, are similar to a desktop presentation application. Use the keyboard, menus and toolbars to perform actions in your document."
-msgstr ""
+msgstr "<span class=\"productname\">%productName</span> Impress aplikazioak jende gehienarentzat ezaguna izango den moduan editatzen ditu aurkezpenak. Testua idaztea, edukiak moztu, kopiatu eta itsastea, testua hautatzea, irudiak txertatu, tamainaz aldatu eta ainguratzea eta taulak maneiatzea mahaigaineko aurkezpen-aplikazioetan bezala egiten dira. Erabili teklatua, menuak eta tresna-barrak dokumentuaren gainean ekintza desberdinak gauzatzeko."
 
 #: html/loleaflet-help.html%2Bdiv.div.p:422-5
 msgid "<span class=\"productname\">%productName</span> displays presentation slide shows, including a subset of slide transitions and object animations. Choose the slide show from the menu or click on icon in the bottom left toolbar in the slide pane."
-msgstr ""

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list