Polish libsyncthing
* Adapt tests * Remove duplicated code * Stop Syncthing from a different thread since it blocks until Syncthing has stopped
This commit is contained in:
parent
79caeda00e
commit
61958c5046
|
@ -1 +1 @@
|
||||||
Subproject commit 51440c77d846bbca1de48d58d6fc5ad69758ca7a
|
Subproject commit afc11f78b983b6b6053776165e526b24cc945e99
|
|
@ -132,9 +132,9 @@ void setLoggingCallback(LoggingCallback &&callback)
|
||||||
* \remark
|
* \remark
|
||||||
* - Does nothing if Syncthing is already running.
|
* - Does nothing if Syncthing is already running.
|
||||||
* - Blocks the current thread as long as the instance is running.
|
* - Blocks the current thread as long as the instance is running.
|
||||||
* Use eg. std::thread(runSyncthing, options) to run it in another thread.
|
* Use e.g. std::thread(runSyncthing, options) to run it in another thread.
|
||||||
*/
|
*/
|
||||||
long long runSyncthing(const RuntimeOptions &options)
|
std::int64_t runSyncthing(const RuntimeOptions &options)
|
||||||
{
|
{
|
||||||
const RunningState runningState;
|
const RunningState runningState;
|
||||||
if (!runningState) {
|
if (!runningState) {
|
||||||
|
@ -155,16 +155,15 @@ bool isSyncthingRunning()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Stops Syncthing if it is running; otherwise does nothing.
|
* \brief Stops Syncthing if it is running; otherwise does nothing.
|
||||||
* \returns Might be called from any thread.
|
* \returns Returns the Syncthing exit code (as usual, zero means no error).
|
||||||
* \todo Make this actually work. Currently crashes happen after stopping Syncthing.
|
* \remarks
|
||||||
* \sa https://github.com/syncthing/syncthing/issues/4085
|
* - Might be called from any thread.
|
||||||
|
* - Blocks the current thread until the instance has been stopped.
|
||||||
|
* Use e.g. std::thread(stopSyncthing) to run it in another thread.
|
||||||
*/
|
*/
|
||||||
void stopSyncthing()
|
std::int64_t stopSyncthing()
|
||||||
{
|
{
|
||||||
if (!syncthingRunning.load()) {
|
return ::libst_stop_syncthing();
|
||||||
return;
|
|
||||||
}
|
|
||||||
::libst_stop_syncthing();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "./global.h"
|
#include "./global.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -30,9 +31,9 @@ using LoggingCallback = std::function<void(LogLevel, const char *message, std::s
|
||||||
|
|
||||||
void LIB_SYNCTHING_EXPORT setLoggingCallback(const LoggingCallback &callback);
|
void LIB_SYNCTHING_EXPORT setLoggingCallback(const LoggingCallback &callback);
|
||||||
void LIB_SYNCTHING_EXPORT setLoggingCallback(LoggingCallback &&callback);
|
void LIB_SYNCTHING_EXPORT setLoggingCallback(LoggingCallback &&callback);
|
||||||
long long LIB_SYNCTHING_EXPORT runSyncthing(const RuntimeOptions &options = RuntimeOptions{});
|
std::int64_t LIB_SYNCTHING_EXPORT runSyncthing(const RuntimeOptions &options = RuntimeOptions{});
|
||||||
bool LIB_SYNCTHING_EXPORT isSyncthingRunning();
|
bool LIB_SYNCTHING_EXPORT isSyncthingRunning();
|
||||||
void LIB_SYNCTHING_EXPORT stopSyncthing();
|
std::int64_t LIB_SYNCTHING_EXPORT stopSyncthing();
|
||||||
std::string LIB_SYNCTHING_EXPORT ownDeviceId();
|
std::string LIB_SYNCTHING_EXPORT ownDeviceId();
|
||||||
std::string LIB_SYNCTHING_EXPORT syncthingVersion();
|
std::string LIB_SYNCTHING_EXPORT syncthingVersion();
|
||||||
std::string LIB_SYNCTHING_EXPORT longSyncthingVersion();
|
std::string LIB_SYNCTHING_EXPORT longSyncthingVersion();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -27,16 +28,17 @@ using namespace CPPUNIT_NS;
|
||||||
*/
|
*/
|
||||||
class InterfaceTests : public TestFixture {
|
class InterfaceTests : public TestFixture {
|
||||||
CPPUNIT_TEST_SUITE(InterfaceTests);
|
CPPUNIT_TEST_SUITE(InterfaceTests);
|
||||||
CPPUNIT_TEST(testRunWidthConfig);
|
CPPUNIT_TEST(testInitialState);
|
||||||
CPPUNIT_TEST(testVersion);
|
CPPUNIT_TEST(testVersion);
|
||||||
|
CPPUNIT_TEST(testRunWidthConfig);
|
||||||
CPPUNIT_TEST_SUITE_END();
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InterfaceTests();
|
InterfaceTests();
|
||||||
|
|
||||||
void testInitialState();
|
void testInitialState();
|
||||||
void testRunWidthConfig();
|
|
||||||
void testVersion();
|
void testVersion();
|
||||||
|
void testRunWidthConfig();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
@ -82,12 +84,12 @@ string InterfaceTests::setupConfigDir()
|
||||||
if (!dir.is_directory() || dirPath == "." || dirPath == "..") {
|
if (!dir.is_directory() || dirPath == "." || dirPath == "..") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto subdirIterator = filesystem::directory_iterator(configDir % '/' + dirPath);
|
const auto subdirIterator = filesystem::directory_iterator(dirPath);
|
||||||
for (const auto &file : subdirIterator) {
|
for (const auto &file : subdirIterator) {
|
||||||
if (file.is_directory()) {
|
if (file.is_directory()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto toRemove = configDir % '/' % dirPath % '/' + file.path();
|
const auto toRemove = file.path().string();
|
||||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("removing " + toRemove, 0, remove(toRemove.data()));
|
CPPUNIT_ASSERT_EQUAL_MESSAGE("removing " + toRemove, 0, remove(toRemove.data()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +112,20 @@ void InterfaceTests::testInitialState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Tests running Syncthing.
|
* \brief Tests whether the version() functions at least return something.
|
||||||
|
*/
|
||||||
|
void InterfaceTests::testVersion()
|
||||||
|
{
|
||||||
|
const auto version(syncthingVersion());
|
||||||
|
const auto longVersion(longSyncthingVersion());
|
||||||
|
cout << "\nversion: " << version;
|
||||||
|
cout << "\nlong version: " << longVersion << endl;
|
||||||
|
CPPUNIT_ASSERT(!version.empty());
|
||||||
|
CPPUNIT_ASSERT(!longVersion.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Test helper for running Syncthing and checking log according to test configuration.
|
||||||
*/
|
*/
|
||||||
void InterfaceTests::testRun(const std::function<long long()> &runFunction)
|
void InterfaceTests::testRun(const std::function<long long()> &runFunction)
|
||||||
{
|
{
|
||||||
|
@ -135,32 +150,54 @@ void InterfaceTests::testRun(const std::function<long long()> &runFunction)
|
||||||
myIdAnnounced = true;
|
myIdAnnounced = true;
|
||||||
} else if (startsWith(msg, "Single thread SHA256 performance is")) {
|
} else if (startsWith(msg, "Single thread SHA256 performance is")) {
|
||||||
performanceAnnounced = true;
|
performanceAnnounced = true;
|
||||||
} else if (msg == "Ready to synchronize test1 (readwrite)") {
|
} else if (msg == "Ready to synchronize test1 (sendreceive)") {
|
||||||
testDir1Ready = true;
|
testDir1Ready = true;
|
||||||
} else if (msg == "Ready to synchronize test2 (readwrite)") {
|
} else if (msg == "Ready to synchronize test2 (sendreceive)") {
|
||||||
testDir2Ready = true;
|
testDir2Ready = true;
|
||||||
} else if (msg == "Device 6EIS2PN-J2IHWGS-AXS3YUL-HC5FT3K-77ZXTLL-AKQLJ4C-7SWVPUS-AZW4RQ4 is \"Test dev 1\" at [dynamic]") {
|
} else if (msg == "Device 6EIS2PN-J2IHWGS-AXS3YUL-HC5FT3K-77ZXTLL-AKQLJ4C-7SWVPUS-AZW4RQ4 is \"Test dev 1\" at [dynamic]") {
|
||||||
testDev1Ready = true;
|
testDev1Ready = true;
|
||||||
} else if (msg == "Device MMGUI6U-WUEZQCP-XZZ6VYB-LCT4TVC-ER2HAVX-QYT6X7D-S6ZSG2B-323KLQ7 is \"Test dev 2\" at [tcp://192.168.2.2:22001]") {
|
} else if (msg == "Device MMGUI6U-WUEZQCP-XZZ6VYB-LCT4TVC-ER2HAVX-QYT6X7D-S6ZSG2B-323KLQ7 is \"Test dev 2\" at [tcp://192.168.2.2:22001]") {
|
||||||
testDev2Ready = true;
|
testDev2Ready = true;
|
||||||
} else if (msg == "Shutting down") {
|
} else if (msg == "Exiting") {
|
||||||
shutDownLogged = true;
|
shutDownLogged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the message on cout (which results in duplicated messages, but allows to check whether we've got everything)
|
// print the message on cout (which results in duplicated messages, but allows to check whether we've got everything)
|
||||||
cout << "logging callback (" << static_cast<std::underlying_type<LogLevel>::type>(logLevel) << ": ";
|
cout << "logging callback (" << static_cast<std::underlying_type<LogLevel>::type>(logLevel) << "): ";
|
||||||
cout.write(message, static_cast<std::streamsize>(messageSize));
|
cout.write(message, static_cast<std::streamsize>(messageSize));
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
|
||||||
// stop Syncthing again if the found the messages we've been looking for or we've timed out
|
// stop Syncthing again if the found the messages we've been looking for or we've timed out
|
||||||
const auto timeout((DateTime::gmtNow() - startTime) > TimeSpan::fromSeconds(30));
|
const auto timeout((DateTime::gmtNow() - startTime) > TimeSpan::fromSeconds(30));
|
||||||
if (!timeout && (!myIdAnnounced || !performanceAnnounced || !testDir1Ready || !testDev1Ready || !testDev2Ready)) {
|
if (!timeout && (!myIdAnnounced || !performanceAnnounced || !testDir1Ready || !testDev1Ready || !testDev2Ready)) {
|
||||||
|
// log status
|
||||||
|
cout << "still wating for:";
|
||||||
|
if (!myIdAnnounced) {
|
||||||
|
cout << " myIdAnnounced";
|
||||||
|
}
|
||||||
|
if (!performanceAnnounced) {
|
||||||
|
cout << " performanceAnnounced";
|
||||||
|
}
|
||||||
|
if (!testDir1Ready) {
|
||||||
|
cout << " testDir1Ready";
|
||||||
|
}
|
||||||
|
if (!testDir2Ready) {
|
||||||
|
cout << " testDir2Ready";
|
||||||
|
}
|
||||||
|
if (!testDev1Ready) {
|
||||||
|
cout << " testDev1Ready";
|
||||||
|
}
|
||||||
|
if (!testDev2Ready) {
|
||||||
|
cout << " testDev2Ready";
|
||||||
|
}
|
||||||
|
cout << endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!shuttingDown) {
|
if (!shuttingDown) {
|
||||||
cerr << "stopping Syncthing again" << endl;
|
cerr << "stopping Syncthing again" << endl;
|
||||||
shuttingDown = true;
|
shuttingDown = true;
|
||||||
stopSyncthing();
|
std::thread stopThread(stopSyncthing);
|
||||||
|
stopThread.detach();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -180,22 +217,12 @@ void InterfaceTests::testRun(const std::function<long long()> &runFunction)
|
||||||
sleep(5);
|
sleep(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Tests whether Syncthing can be started (and stopped again) using the specified test config.
|
||||||
|
*/
|
||||||
void InterfaceTests::testRunWidthConfig()
|
void InterfaceTests::testRunWidthConfig()
|
||||||
{
|
{
|
||||||
RuntimeOptions options;
|
RuntimeOptions options;
|
||||||
options.configDir = setupConfigDir();
|
options.configDir = setupConfigDir();
|
||||||
testRun(bind(static_cast<long long (*)(const RuntimeOptions &)>(&runSyncthing), cref(options)));
|
testRun(bind(static_cast<std::int64_t (*)(const RuntimeOptions &)>(&runSyncthing), cref(options)));
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Tests whether the version() functions at least return something.
|
|
||||||
*/
|
|
||||||
void InterfaceTests::testVersion()
|
|
||||||
{
|
|
||||||
const auto version(syncthingVersion());
|
|
||||||
const auto longVersion(longSyncthingVersion());
|
|
||||||
cout << "\nversion: " << version;
|
|
||||||
cout << "\nlong version: " << longVersion << endl;
|
|
||||||
CPPUNIT_ASSERT(!version.empty());
|
|
||||||
CPPUNIT_ASSERT(!longVersion.empty());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,11 @@ bool SyncthingLauncher::isLibSyncthingAvailable()
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Launches a Syncthing instance using the specified \a arguments.
|
* \brief Launches a Syncthing instance using the specified \a arguments.
|
||||||
* \remarks
|
*
|
||||||
* - Does nothing if already running an instance.
|
* To use the internal library, leave \a program empty. In this case \a arguments are ignored.
|
||||||
* - To use the internal library, leave \a program empty. Otherwise it must be the path the external Syncthing executable.
|
* Otherwise \a program must be the path the external Syncthing executable.
|
||||||
|
*
|
||||||
|
* \remarks Does nothing if already running an instance.
|
||||||
*/
|
*/
|
||||||
void SyncthingLauncher::launch(const QString &program, const QStringList &arguments)
|
void SyncthingLauncher::launch(const QString &program, const QStringList &arguments)
|
||||||
{
|
{
|
||||||
|
@ -71,7 +73,7 @@ void SyncthingLauncher::launch(const QString &program, const QStringList &argume
|
||||||
}
|
}
|
||||||
|
|
||||||
// use libsyncthing
|
// use libsyncthing
|
||||||
m_future = QtConcurrent::run(this, static_cast<void (SyncthingLauncher::*)()>(&SyncthingLauncher::runLibSyncthing));
|
m_future = QtConcurrent::run(this, &SyncthingLauncher::runLibSyncthing, LibSyncthing::RuntimeOptions{});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -106,8 +108,7 @@ void SyncthingLauncher::launch(const LibSyncthing::RuntimeOptions &runtimeOption
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_manuallyStopped = false;
|
m_manuallyStopped = false;
|
||||||
m_future = QtConcurrent::run(
|
m_future = QtConcurrent::run(this, &SyncthingLauncher::runLibSyncthing, runtimeOptions);
|
||||||
this, static_cast<void (SyncthingLauncher::*)(const LibSyncthing::RuntimeOptions &)>(&SyncthingLauncher::runLibSyncthing), runtimeOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncthingLauncher::terminate()
|
void SyncthingLauncher::terminate()
|
||||||
|
@ -117,9 +118,7 @@ void SyncthingLauncher::terminate()
|
||||||
m_process.stopSyncthing();
|
m_process.stopSyncthing();
|
||||||
} else if (m_future.isRunning()) {
|
} else if (m_future.isRunning()) {
|
||||||
m_manuallyStopped = true;
|
m_manuallyStopped = true;
|
||||||
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
|
QtConcurrent::run(this, &SyncthingLauncher::stopLibSyncthing);
|
||||||
LibSyncthing::stopSyncthing();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,10 +129,7 @@ void SyncthingLauncher::kill()
|
||||||
m_process.killSyncthing();
|
m_process.killSyncthing();
|
||||||
} else if (m_future.isRunning()) {
|
} else if (m_future.isRunning()) {
|
||||||
m_manuallyStopped = true;
|
m_manuallyStopped = true;
|
||||||
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
|
QtConcurrent::run(this, &SyncthingLauncher::stopLibSyncthing);
|
||||||
// FIXME: any chance to try harder?
|
|
||||||
LibSyncthing::stopSyncthing();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,17 +202,11 @@ void SyncthingLauncher::runLibSyncthing(const LibSyncthing::RuntimeOptions &runt
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyncthingLauncher::runLibSyncthing()
|
void SyncthingLauncher::stopLibSyncthing()
|
||||||
{
|
{
|
||||||
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
|
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
|
||||||
LibSyncthing::setLoggingCallback(bind(&SyncthingLauncher::handleLoggingCallback, this, _1, _2, _3));
|
LibSyncthing::stopSyncthing();
|
||||||
emit runningChanged(true);
|
// no need to emit exited/runningChanged here; that is already done in runLibSyncthing()
|
||||||
const auto exitCode = LibSyncthing::runSyncthing();
|
|
||||||
emit exited(static_cast<int>(exitCode), exitCode == 0 ? QProcess::NormalExit : QProcess::CrashExit);
|
|
||||||
emit runningChanged(false);
|
|
||||||
#else
|
|
||||||
emit outputAvailable("libsyncthing support not enabled");
|
|
||||||
emit exited(-1, QProcess::CrashExit);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ private Q_SLOTS:
|
||||||
void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
void handleLoggingCallback(LibSyncthing::LogLevel, const char *message, std::size_t messageSize);
|
void handleLoggingCallback(LibSyncthing::LogLevel, const char *message, std::size_t messageSize);
|
||||||
void runLibSyncthing(const LibSyncthing::RuntimeOptions &runtimeOptions);
|
void runLibSyncthing(const LibSyncthing::RuntimeOptions &runtimeOptions);
|
||||||
void runLibSyncthing();
|
void stopLibSyncthing();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SyncthingProcess m_process;
|
SyncthingProcess m_process;
|
||||||
|
|
Loading…
Reference in New Issue