refactor: ServerConnection: Handle the new client via signals

Use QtTests now that we can for ServerConnnecitonTests
This commit is contained in:
sithlord48
2025-11-28 16:26:29 -05:00
committed by Chris Rizzitello
parent 11fa5d636e
commit accb9d9c59
9 changed files with 156 additions and 125 deletions

View File

@ -293,8 +293,10 @@ void MainWindow::connectSlots()
connect(&m_serverConnection, &ServerConnection::configureClient, this, &MainWindow::serverConnectionConfigureClient);
connect(&m_serverConnection, &ServerConnection::clientsChanged, this, &MainWindow::serverClientsChanged);
connect(
&m_serverConnection, &ServerConnection::requestNewClientPrompt, this, &MainWindow::handleNewClientPromptRequest
);
connect(&m_serverConnection, &ServerConnection::messageShowing, this, &MainWindow::showAndActivate);
connect(&m_clientConnection, &ClientConnection::requestShowError, this, &MainWindow::showClientError);
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger, Qt::UniqueConnection);
@ -1237,3 +1239,10 @@ void MainWindow::showClientError(deskflow::client::ErrorType error, const QStrin
showAndActivate();
m_clientErrorVisible = false;
}
void MainWindow::handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth)
{
showAndActivate();
bool result = deskflow::gui::messages::showNewClientPrompt(this, clientName, usePeerAuth);
m_serverConnection.handleNewClientResult(clientName, result);
}

View File

@ -151,7 +151,7 @@ private:
void daemonIpcClientConnectionFailed();
void toggleCanRunCore(bool enableButtons);
void remoteHostChanged(const QString &newRemoteHost);
void handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth);
/**
* @brief showClientError
* @param error Error Type

View File

@ -1,12 +1,12 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ServerConnection.h"
#include "Messages.h"
#include "ServerMessage.h"
#include "common/Settings.h"
@ -15,25 +15,9 @@
namespace deskflow::gui {
//
// ServerConnection::Deps
//
bool ServerConnection::Deps::showNewClientPrompt(
QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth
) const
{
return messages::showNewClientPrompt(parent, clientName, serverRequiresPeerAuth);
}
//
// ServerConnection
//
ServerConnection::ServerConnection(QWidget *parent, IServerConfig &serverConfig, std::shared_ptr<Deps> deps)
ServerConnection::ServerConnection(QWidget *parent, IServerConfig &serverConfig)
: m_pParent(parent),
m_serverConfig(serverConfig),
m_pDeps(deps)
m_serverConfig(serverConfig)
{
}
@ -93,15 +77,17 @@ void ServerConnection::handleNewClient(const QString &clientName)
return;
}
Q_EMIT messageShowing();
m_messageShowing = true;
const bool tlsEnabled = Settings::value(Settings::Security::TlsEnabled).toBool();
const bool requireCerts = Settings::value(Settings::Security::CheckPeers).toBool();
const auto result = m_pDeps->showNewClientPrompt(m_pParent, clientName, tlsEnabled && requireCerts);
Q_EMIT requestNewClientPrompt(clientName, tlsEnabled && requireCerts);
}
void ServerConnection::handleNewClientResult(const QString &clientName, bool acceptClient)
{
m_messageShowing = false;
if (result) {
if (acceptClient) {
qDebug("accepted dialog, adding client: %s", qPrintable(clientName));
Q_EMIT configureClient(clientName);
} else {

View File

@ -1,5 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@ -19,16 +20,7 @@ class ServerConnection : public QObject
using IServerConfig = deskflow::gui::IServerConfig;
public:
struct Deps
{
virtual ~Deps() = default;
virtual bool
showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth = false) const;
};
explicit ServerConnection(
QWidget *parent, IServerConfig &serverConfig, std::shared_ptr<Deps> deps = std::make_shared<Deps>()
);
explicit ServerConnection(QWidget *parent, IServerConfig &serverConfig);
void handleLogLine(const QString &logLine);
void serverConfigDialogVisible(bool visible)
{
@ -36,9 +28,10 @@ public:
}
QStringList connectedClients() const;
void handleNewClientResult(const QString &clientName, bool acceptClient);
Q_SIGNALS:
void messageShowing();
void requestNewClientPrompt(const QString &clientName, bool peerAuthRequired);
void configureClient(const QString &clientName);
void clientsChanged(const QStringList &clients);
@ -47,7 +40,6 @@ private:
QWidget *m_pParent;
IServerConfig &m_serverConfig;
std::shared_ptr<Deps> m_pDeps;
QSet<QString> m_connectedClients;
bool m_messageShowing = false;
bool m_serverConfigDialogVisible = false;

View File

@ -14,3 +14,10 @@ create_test(
SOURCE ClientConnectionTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui"
)
create_test(
NAME ServerConnectionTests
DEPENDS gui
SOURCE ServerConnectionTests.cpp
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui"
)

View File

@ -0,0 +1,101 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ServerConnectionTests.h"
#include "gui/config/ServerConfig.h"
#include "gui/core/ServerConnection.h"
#include <common/Settings.h>
#include <QSignalSpy>
using namespace deskflow::gui;
class FullServerConfig : public ServerConfig
{
public:
bool isFull() const override
{
return true;
}
};
class ScreenExistsServerConfig : public ServerConfig
{
public:
bool screenExists(const QString &screenName) const override
{
return true;
}
};
void ServerConnectionTests::initTestCase()
{
QDir dir;
QVERIFY(dir.mkpath(m_settingsPath));
QFile oldSettings(m_settingsFile);
if (oldSettings.exists())
oldSettings.remove();
Settings::setSettingsFile(m_settingsFile);
Settings::setStateFile(m_stateFile);
}
void ServerConnectionTests::handleLogLine_newClient_shouldShowPrompt()
{
ServerConfig m_serverConfig;
ServerConnection serverConnection(nullptr, m_serverConfig);
QString clientName = "test client";
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
QVERIFY(spy.isValid());
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
QCOMPARE(spy.count(), 1);
}
void ServerConnectionTests::handleLogLine_ignoredClient_shouldNotShowPrompt()
{
ServerConfig m_serverConfig;
ServerConnection serverConnection(nullptr, m_serverConfig);
QString clientName = "test client";
serverConnection.handleNewClientResult(clientName, false);
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
QVERIFY(spy.isValid());
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
QCOMPARE(spy.count(), 0);
}
void ServerConnectionTests::handleLogLine_serverConfigFull_shouldNotShowPrompt()
{
FullServerConfig m_serverConfig;
ServerConnection serverConnection(nullptr, m_serverConfig);
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
QVERIFY(spy.isValid());
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
QCOMPARE(spy.count(), 0);
}
void ServerConnectionTests::handleLogLine_screenExists_shouldNotShowPrompt()
{
ScreenExistsServerConfig m_serverConfig;
ServerConnection serverConnection(nullptr, m_serverConfig);
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
QVERIFY(spy.isValid());
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
QCOMPARE(spy.count(), 0);
}
QTEST_MAIN(ServerConnectionTests)

View File

@ -0,0 +1,24 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include <QTest>
class ServerConnectionTests : public QObject
{
Q_OBJECT
private Q_SLOTS:
// Test are run in order top to bottom
void initTestCase();
void handleLogLine_newClient_shouldShowPrompt();
void handleLogLine_ignoredClient_shouldNotShowPrompt();
void handleLogLine_serverConfigFull_shouldNotShowPrompt();
void handleLogLine_screenExists_shouldNotShowPrompt();
private:
inline static const QString m_settingsPath = QStringLiteral("tmp/test");
inline static const QString m_settingsFile = QStringLiteral("%1/Deskflow.conf").arg(m_settingsPath);
inline static const QString m_stateFile = QStringLiteral("%1/Deskflow.state").arg(m_settingsPath);
};

View File

@ -1,79 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "gui/core/ServerConnection.h"
#include "unittests/legacytests/shared/gui/mocks/ServerConfigMock.h"
#include "gmock/gmock.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using testing::_;
using testing::NiceMock;
using namespace deskflow::gui;
class QWidget;
namespace {
struct DepsMock : public ServerConnection::Deps
{
MOCK_METHOD(
bool, showNewClientPrompt, (QWidget * parent, const QString &clientName, bool previousyAccepted),
(const, override)
);
};
} // namespace
class ServerConnectionTests : public testing::Test
{
public:
std::shared_ptr<DepsMock> m_pDeps = std::make_shared<NiceMock<DepsMock>>();
NiceMock<ServerConfigMock> m_serverConfig;
};
TEST_F(ServerConnectionTests, handleLogLine_newClient_shouldShowPrompt)
{
ServerConnection serverConnection(nullptr, m_serverConfig, m_pDeps);
QString clientName = "test client";
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, clientName, true)).Times(0);
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
}
TEST_F(ServerConnectionTests, handleLogLine_ignoredClient_shouldNotShowPrompt)
{
ServerConnection serverConnection(nullptr, m_serverConfig, m_pDeps);
ON_CALL(*m_pDeps, showNewClientPrompt(_, _, false)).WillByDefault(testing::Return(false));
serverConnection.handleLogLine(R"(unrecognised client name "stub")");
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _, false)).Times(0);
serverConnection.handleLogLine(R"(unrecognised client name "stub")");
}
TEST_F(ServerConnectionTests, handleLogLine_serverConfigFull_shouldNotShowPrompt)
{
ServerConnection serverConnection(nullptr, m_serverConfig, m_pDeps);
ON_CALL(m_serverConfig, isFull()).WillByDefault(testing::Return(true));
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _, false)).Times(0);
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
}
TEST_F(ServerConnectionTests, handleLogLine_screenExists_shouldNotShowPrompt)
{
ServerConnection serverConnection(nullptr, m_serverConfig, m_pDeps);
ON_CALL(m_serverConfig, screenExists(_)).WillByDefault(testing::Return(true));
EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _, false)).Times(0);
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
}

View File

@ -7,14 +7,12 @@
#include "arch/Arch.h"
#include "base/Log.h"
#include "common/Settings.h"
#include "unittests/legacytests/shared/ExitTimeout.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#endif
#include <filesystem>
#include <gtest/gtest.h>
using deskflow::test::ExitTimeout;
@ -23,13 +21,6 @@ const auto testDir = "tmp/test";
int main(int argc, char **argv)
{
// HACK: Unit tests should not use the filesystem.
std::filesystem::create_directories(testDir);
Settings::setSettingsFile("tmp/test/settings.ini");
Settings::setStateFile("tmp/test/Deskflow.state");
Settings::setValue(Settings::Server::ExternalConfig, true);
ExitTimeout exitTimeout(1, "Unit tests");
#if SYSAPI_WIN32