feat(GODT-2239): bridgepp worker/overseer unit tests.

This commit is contained in:
Xavier Michelon
2023-04-17 18:43:17 +02:00
parent 3ddd88e127
commit c000ee8a3c
5 changed files with 306 additions and 3 deletions

View File

@ -0,0 +1,215 @@
// Copyright (c) 2023 Proton AG
//
// This file is part of Proton Mail Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
// clazy:excludeall=lambda-in-connect
#include "TestWorker.h"
#include <bridgepp/Worker/Overseer.h>
#include <bridgepp/Exception/Exception.h>
using namespace bridgepp;
namespace {
qint32 dummyArgc = 1; ///< A dummy int value because QCoreApplication constructor requires a reference to it.
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
Workers::Workers()
: testing::Test()
, app_(dummyArgc, nullptr) {
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void Workers::SetUp() {
Test::SetUp();
EXPECT_NO_THROW(worker_ = new TestWorker);
QObject::connect(worker_, &TestWorker::started, [&]() { results_.started = true; });
QObject::connect(worker_, &TestWorker::finished, [&]() { results_.finished = true; });
QObject::connect(worker_, &TestWorker::finished, &loop_, &QEventLoop::quit);
QObject::connect(worker_, &TestWorker::error, [&] { results_.error = true; });
QObject::connect(worker_, &TestWorker::error, &loop_, &QEventLoop::quit);
QObject::connect(worker_, &TestWorker::error, [&] { results_.error = true; });
QObject::connect(worker_, &TestWorker::error, &loop_, &QEventLoop::quit);
QObject::connect(worker_, &TestWorker::cancelled, [&] { results_.cancelled = true; });
QObject::connect(worker_, &TestWorker::cancelled, &loop_, &QEventLoop::quit);
overseer_ = std::make_unique<Overseer>(worker_, nullptr);
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void Workers::TearDown() {
EXPECT_NO_FATAL_FAILURE(overseer_.reset());
Test::TearDown();
}
//****************************************************************************************************************************************************
/// \param[in] lifetimeMs The lifetime of the worker in milliseconds.
/// \param[in] willSucceed Will the worker succeed (emit finished) or fail (emit error).
//****************************************************************************************************************************************************
TestWorker::TestWorker()
: Worker(nullptr) {
}
//****************************************************************************************************************************************************
/// \param[in] lifetimeMs The lifetime of the worker in milliseconds.
//****************************************************************************************************************************************************
void TestWorker::setLifetime(qint64 lifetimeMs) {
lifetimeMs_ = lifetimeMs;
}
//****************************************************************************************************************************************************
/// \param[in] willSucceed Will the worker succeed?
//****************************************************************************************************************************************************
void TestWorker::setWillSucceed(bool willSucceed) {
willSucceed_ = willSucceed;
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void TestWorker::run() {
emit started();
QElapsedTimer timer;
timer.start();
while (true) {
if (cancelled_.loadRelaxed()) {
emit cancelled();
return;
}
if (timer.elapsed() >= lifetimeMs_) {
break;
}
}
if (willSucceed_) {
emit finished();
} else {
emit error(QString());
}
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
void TestWorker::cancel() {
cancelled_.storeRelaxed(1);
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
TEST_F(Workers, SuccessfulWorker) {
worker_->setLifetime(10);
worker_->setWillSucceed(true);
EXPECT_NO_THROW(overseer_->startWorker(false));
EXPECT_NO_THROW(loop_.exec());
EXPECT_TRUE(results_.started);
EXPECT_TRUE(results_.finished);
EXPECT_FALSE(results_.error);
EXPECT_FALSE(results_.cancelled);
EXPECT_TRUE(overseer_->worker() != nullptr); // overseer started without autorelease.
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
TEST_F(Workers, ErrorWorker) {
worker_->setLifetime(10);
worker_->setWillSucceed(false);
EXPECT_NO_THROW(overseer_->startWorker(true));
EXPECT_NO_THROW(loop_.exec());
EXPECT_TRUE(results_.started);
EXPECT_FALSE(results_.finished);
EXPECT_TRUE(results_.error);
EXPECT_FALSE(results_.cancelled);
EXPECT_TRUE(overseer_->worker() == nullptr); // overseer started with autorelease.
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
TEST_F(Workers, CancelledWorker) {
worker_->setLifetime(10000);
worker_->setWillSucceed(true);
EXPECT_NO_THROW(overseer_->startWorker(false));
EXPECT_NO_THROW(QTimer::singleShot(10, [&]() { worker_->cancel(); }));
EXPECT_NO_THROW(loop_.exec());
EXPECT_TRUE(results_.started);
EXPECT_FALSE(results_.finished);
EXPECT_FALSE(results_.error);
EXPECT_TRUE(results_.cancelled);
}
//****************************************************************************************************************************************************
//
//****************************************************************************************************************************************************
TEST_F(Workers, Wait) {
worker_->setLifetime(10000);
worker_->setWillSucceed(true);
overseer_->startWorker(true);
bool isFinished = false;
EXPECT_NO_THROW(isFinished = overseer_->isFinished());
EXPECT_FALSE(isFinished);
EXPECT_NO_THROW(isFinished = overseer_->wait(10));
EXPECT_FALSE(isFinished);
worker_->cancel();
EXPECT_NO_THROW(isFinished = overseer_->wait(10000));
EXPECT_TRUE(isFinished);
EXPECT_NO_THROW(isFinished = overseer_->isFinished());
EXPECT_TRUE(isFinished);
}

View File

@ -0,0 +1,88 @@
// Copyright (c) 2023 Proton AG
//
// This file is part of Proton Mail Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_GUI_TEST_WORKER_H
#define BRIDGE_GUI_TEST_WORKER_H
#include <bridgepp/Worker/Overseer.h>
#include <gtest/gtest.h>
//****************************************************************************************************************************************************
/// \brief Test worker class.
///
/// This worker simply waits:
/// - For a specified amount of time and will succeed (emit finished()) or fail (emit error()) based on its parameters.
/// - to be cancelled (and will emit cancelled in that case).
//****************************************************************************************************************************************************
class TestWorker : public bridgepp::Worker {
Q_OBJECT
public: // member functions.
TestWorker(); ///< Default constructor.
TestWorker(TestWorker const &) = delete; ///< Disabled copy-constructor.
TestWorker(TestWorker &&) = delete; ///< Disabled assignment copy-constructor.
~TestWorker() override = default; ///< Destructor.
TestWorker &operator=(TestWorker const &) = delete; ///< Disabled assignment operator.
TestWorker &operator=(TestWorker &&) = delete; ///< Disabled move assignment operator.
void setLifetime(qint64 lifetimeMs); ///< Set the lifetime of the worker.
void setWillSucceed(bool willSucceed); ///< Set if the worker will succeed.
void run() override; ///< Run the worker.
void cancel(); ///< Cancel the worker.
private: // data members
qint64 lifetimeMs_ { 10 }; ///< The lifetime of the worker in milliseconds.
bool willSucceed_ { true }; ///< Will the worker succeed?
QAtomicInteger<char> cancelled_; ///< Has the worker been cancelled.
};
//****************************************************************************************************************************************************
/// \brief Fixture class for worker tests.
//****************************************************************************************************************************************************
class Workers : public testing::Test {
public: // member functions.
Workers(); ///< Default constructor.
Workers(Workers const &) = delete; ///< Disabled copy-constructor.
Workers(Workers &&) = delete; ///< Disabled assignment copy-constructor.
~Workers() = default; ///< Destructor.
Workers &operator=(Workers const &) = delete; ///< Disabled assignment operator.
Workers &operator=(Workers &&) = delete; ///< Disabled move assignment operator.
protected: // member functions.
void SetUp() override; ///< Setup the fixture.
void TearDown() override; ///< Tear down the fixture.
protected: // data type
struct Results {
bool started { false };
bool finished { false };
bool error { false };
bool cancelled { false };
}; ///< Test results data type
protected: // data members
QCoreApplication app_; ///< The Qt application required for event loop.
bridgepp::UPOverseer overseer_; ///< The overseer for the worker.
TestWorker *worker_ { nullptr }; ///< The worker.
QEventLoop loop_; ///< The event loop.
Results results_; ///< The test results.
};
#endif //BRIDGE_GUI_TEST_WORKER_H