GODT-1553: RPC definition and mocks

WIP: updates

WIP: cache on disk and autostart.

WIP: mail, keychain and more.

WIP: updated grpc version in go mod file.

WIP: user list.

WIP: RPC service placeholder

WIP: test C++ RPC client skeleton.

Other: missing license script update.

WIP: use Qt test framework.

WIP: test for app and login calls.

WIP: test for update & cache on disk calls.

WIP: tests for mail settings calls.

WIP: all client tests.

WIP: linter fixes.

WIP: fix missing license link.

WIP: update dependency_license script for gRPC and protobuf.

WIP: removed unused file.

WIP: app & login event streaming tests.

WIP: update event stream tests.

WIP: completed event streaming tests.
This commit is contained in:
Xavier Michelon
2022-05-16 10:59:45 +02:00
committed by Jakub
parent b5321f8993
commit a4e54f063d
24 changed files with 49262 additions and 27 deletions

View File

@ -0,0 +1,25 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.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/>.
#include "RpcClient.h"
#include <QtCore>
#include <QtTest>
QTEST_MAIN(RpcClient) // This macro will generate the main() function

View File

@ -0,0 +1,66 @@
cmake_minimum_required(VERSION 3.22)
project(BridgeRpcClientTest VERSION 0.1 LANGUAGES CXX)
if (NOT DEFINED ENV{QTDIR})
message(FATAL_ERROR "QTDIR needs to be defined and point to the root of your Qt folder. (e.g. /Users/MyName/Qt/6.3/clang_64).")
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMATIC ON)
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
find_package(Qt6 COMPONENTS Core Test REQUIRED)
find_program(PROTOC_EXE protoc)
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../internal/rpc")
set(PROTO_FILE "${PROTO_DIR}/bridge_rpc.proto")
set(GRPC_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rpc")
set(PROTO_CPP_FILE "${GRPC_OUT_DIR}/bridge_rpc.pb.cc")
set(PROTO_H_FILE "${GRPC_OUT_DIR}/bridge_rpc.pb.h")
set(GRPC_CPP_FILE "${GRPC_OUT_DIR}/bridge_rpc.grpc.pb.cc")
set(GRPC_H_FILE "${GRPC_OUT_DIR}/bridge_rpc.grpc.pb.h")
add_custom_command(
OUTPUT
${PROTO_CPP_FILE}
${PROTO_H_FILE}
${GRPC_CPP_FILE}
${GRPC_H_FILE}
COMMAND
${PROTOC_EXE}
ARGS
--proto_path=${PROTO_DIR}
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
--cpp_out=${GRPC_OUT_DIR}
--grpc_out=${GRPC_OUT_DIR}
${PROTO_FILE}
DEPENDS
${PROTO_FILE}
COMMENT "Generating gPRC/Protobuf C++ code"
)
add_executable(BridgeRpcClientTest
BridgeRpcClientTest.cpp
RpcClient.cpp RpcClient.h
Exception.cpp Exception.h
${PROTO_CPP_FILE}
${PROTO_H_FILE}
${GRPC_CPP_FILE}
${GRPC_H_FILE}
)
target_link_libraries(BridgeRpcClientTest
Qt::Core Qt::Test
protobuf::libprotobuf
gRPC::grpc++ gRPC::grpc++_reflection
)

View File

@ -0,0 +1,67 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.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/>.
#include "Exception.h"
//**********************************************************************************************************************
/// \param[in] what A description of the exception
//**********************************************************************************************************************
Exception::Exception(QString what) noexcept
: std::exception()
, what_(std::move(what))
{
}
//**********************************************************************************************************************
/// \param[in] ref The Exception to copy from
//**********************************************************************************************************************
Exception::Exception(Exception const& ref) noexcept
: std::exception(ref)
, what_(ref.what_)
{
}
//**********************************************************************************************************************
/// \param[in] ref The Exception to copy from
//**********************************************************************************************************************
Exception::Exception(Exception&& ref) noexcept
: std::exception(ref)
, what_(ref.what_)
{
}
//**********************************************************************************************************************
/// \return a string describing the exception
//**********************************************************************************************************************
QString const& Exception::qwhat() const noexcept
{
return what_;
}
//**********************************************************************************************************************
/// \return A pointer to the description string of the exception.
//**********************************************************************************************************************
const char* Exception::what() const noexcept
{
return what_.toLocal8Bit().constData();
}

View File

@ -0,0 +1,44 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.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_RPC_CLIENT_TEST_EXCEPTION_H
#define BRIDGE_RPC_CLIENT_TEST_EXCEPTION_H
#include <QtCore>
#include <stdexcept>
//**********************************************************************************************************************
/// \brief Exception class
//**********************************************************************************************************************
class Exception: public std::exception
{
public: // member functions
explicit Exception(QString what = QString()) noexcept; ///< Constructor
Exception(Exception const& ref) noexcept; ///< copy constructor
Exception(Exception&& ref) noexcept; ///< copy constructor
Exception& operator=(Exception const&) = delete; ///< Disabled assignment operator
Exception& operator=(Exception&&) = delete; ///< Disabled assignment operator
~Exception() noexcept = default; ///< Destructor
QString const& qwhat() const noexcept; ///< Return the description of the exception as a QString
const char* what() const noexcept override; ///< Return the description of the exception as C style string
private: // data members
QString const what_; ///< The description of the exception
};
#endif //BRIDGE_RPC_CLIENT_TEST_EXCEPTION_H

View File

@ -0,0 +1,925 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.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/>.
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#include "RpcClient.h"
#include <QtTest>
using namespace google::protobuf;
using namespace bridgerpc;
using namespace grpc;
namespace
{
// \todo Decide where to store this certificate.
std::string cert = R"(-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJAJL2PajH8kFjMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yMjA1MTAwNjEzMzdaFw0yMjA2MDkwNjEzMzdaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKyb48XL+08YI8m4X/eeD9TQshV+vybKbU7MOG7BnH3Hv7kUH0aVP7OPnU51
eYRgUu+bkJ8qWhxD7wOLVJBcU5T1lgd+k6St83ix25P02nUc3UeU4MCxMwhjMjYu
R5F9bfSG0UlCCGAEjjmGh+CfnZkS+rgCwE/xGswFnVrynTMvrLQyN02dz/r4zJPp
yyVhTOmjdsUDs0zGDbubLf+ypR8VCXg55qYMw7Abpe+rx3BF+NCEjKlATjMeIZNx
iS0dl0OGjJZ+bfHGhnPiQxP8HxyJ0NjFNtWgblQev2sHmIq65Rry3RP1gbDAW3sk
MiIfjbnp4gGspYrmHWeWXH8g6WMCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEAO2WDYnzy9SkaS9VU2jw3nd9MEaILZsXFcVU2+52TKwRBty7b0A1x
zyxT6nT0pN0Im7DcT5/TvwFuVBJUTFs4c2gW09WUvtfuN8HVFOeX/1Pt10lMPJjR
I+wTAUQrXJHt57JE9x13gQEOW/mGUDNuoUH2cE9C1f+TrO0LaRj8dubS/gHMuV1i
aTyxu7hgbLAYq0NGD86CSOwvUvTvs6o628xvfmqqdzlpWIlQq18t2GZYFVWjrISY
LWw3OCormKSASOPrW1FXhrgwoyDXHNmZT1MHL3Rh9U5qyCwV5kDAcY956sc9lD3G
XHtSxOHLE1eDKGCUKRcYop/99inTGjJ6Xg==
-----END CERTIFICATE-----)";
Empty empty; // A protobuf empty message reused for the sake of simplicity
}
//**********************************************************************************************************************
/// \brief Help class that manage a client context. Provided context cannot be re-used, the underlying context is freed
/// and re-allocated at every call to get() (or at destruction).
//**********************************************************************************************************************
class Ctx
{
public: // member functions
Ctx()
{} ///< Default constructor.
Ctx(Ctx const &) = delete; ///< Disabled copy-constructor.
Ctx(Ctx &&) = delete; ///< Disabled assignment copy-constructor.
~Ctx() = default; ///< Destructor.
Ctx &operator=(Ctx const &) = delete; ///< Disabled assignment operator.
Ctx &operator=(Ctx &&) = delete; ///< Disabled move assignment operator.
ClientContext *get()
{
ctx_ = std::make_unique<ClientContext>();
return ctx_.get();
} ///< Release the previous context, if any and allocate a new one
private: // data members
std::unique_ptr<ClientContext> ctx_{nullptr};
};
//**********************************************************************************************************************
//
//**********************************************************************************************************************
RpcClient::RpcClient()
: QObject(nullptr)
{
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::initTestCase()
{
SslCredentialsOptions opts;
opts.pem_root_certs += cert;
channel_ = CreateChannel("localhost:9292", grpc::SslCredentials(opts));
QVERIFY2(channel_, "Channel creation failed.");
stub_ = bridgerpc::BridgeRpc::NewStub(channel_);
QVERIFY2(stub_, "Stub creation failed.");
QVERIFY2(channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(10, GPR_TIMESPAN))), "Connection to the RPC server failed.");
QVERIFY2(channel_ && stub_ && (channel_->GetState(true) == GRPC_CHANNEL_READY), "connection check failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGetCursorPos()
{
Ctx ctx;
PointResponse resp;
Status s = stub_->GetCursorPos(ctx.get(), empty, &resp);
QVERIFY2(s.ok(), "GetCursorPos failed.");
QVERIFY2(resp.x() == 100, "Invalid x value");
QVERIFY2(resp.y() == 200, "Invalid y value");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGuiReady()
{
Ctx ctx;
QVERIFY2(stub_->GuiReady(ctx.get(), empty, &empty).ok(), "GuiReady failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testQuit()
{
Ctx ctx;
QVERIFY2(stub_->Quit(ctx.get(), empty, &empty).ok(), "Quit failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testRestart()
{
Ctx ctx;
QVERIFY2(stub_->Restart(ctx.get(), empty, &empty).ok(), "Restart failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testShowOnStartup()
{
Ctx ctx;
BoolValue showOnStartup;
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showOnStartup).ok(), "ShowOnStartup failed.");
bool const newValue = !showOnStartup.value();
showOnStartup.set_value(newValue);
QVERIFY2(stub_->SetShowOnStartup(ctx.get(), showOnStartup, &empty).ok(), "SetShowOnStartup failed.");
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showOnStartup).ok(), "ShowOnStartup failed.");
QVERIFY2(showOnStartup.value() == newValue, "ShowOnStartup failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testShowSplashScreen()
{
Ctx ctx;
BoolValue showSplashScreen;
QVERIFY2(stub_->ShowSplashScreen(ctx.get(), empty, &showSplashScreen).ok(), "ShowSplashScreen failed.");
bool const newValue = !showSplashScreen.value();
showSplashScreen.set_value(newValue);
QVERIFY2(stub_->SetShowSplashScreen(ctx.get(), showSplashScreen, &empty).ok(), "SetShowSplashScreen failed.");
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showSplashScreen).ok(), "ShowSplashScreen failed.");
QVERIFY2(showSplashScreen.value() == newValue, "ShowSplashScreen failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testDockIconVisible()
{
Ctx ctx;
BoolValue dockIconVisible;
QVERIFY2(stub_->DockIconVisible(ctx.get(), empty, &dockIconVisible).ok(), "DockIconVisible failed.");
bool const newValue = !dockIconVisible.value();
dockIconVisible.set_value(newValue);
QVERIFY2(stub_->SetDockIconVisible(ctx.get(), dockIconVisible, &empty).ok(), "SetShowSplashScreen failed.");
QVERIFY2(stub_->DockIconVisible(ctx.get(), empty, &dockIconVisible).ok(), "DockIconVisible failed.");
QVERIFY2(dockIconVisible.value() == newValue, "DockIconVisible failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsFirstGuiStart()
{
Ctx ctx;
BoolValue isFirst;
QVERIFY2(stub_->IsFirstGuiStart(ctx.get(), empty, &isFirst).ok(), "IsFirstGuiStart failed.");
bool const newValue = !isFirst.value();
isFirst.set_value(newValue);
QVERIFY2(stub_->SetIsFirstGuiStart(ctx.get(), isFirst, &empty).ok(), "SetIsFirstGuiStart failed.");
QVERIFY2(stub_->IsFirstGuiStart(ctx.get(), empty, &isFirst).ok(), "IsFirstGuiStart failed.");
QVERIFY2(isFirst.value() == newValue, "IsFirstGuiStart failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsAutostartOn()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsAutostartOn(ctx.get(), empty, &isOn).ok(), "IsAutostartOn failed.");
bool const newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsAutostartOn(ctx.get(), isOn, &empty).ok(), "SetIsAutostartOn failed.");
QVERIFY2(stub_->IsAutostartOn(ctx.get(), empty, &isOn).ok(), "IsAutostartOn failed.");
QVERIFY2(isOn.value() == newValue, "IsAutostartOn failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsBetaEnabled()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsBetaEnabled(ctx.get(), empty, &isOn).ok(), "IsBetaEnabled failed.");
bool const newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsBetaEnabled(ctx.get(), isOn, &empty).ok(), "SetIsBetaEnabled failed.");
QVERIFY2(stub_->IsBetaEnabled(ctx.get(), empty, &isOn).ok(), "IsBetaEnabled failed.");
QVERIFY2(isOn.value() == newValue, "IsBetaEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGoOs()
{
Ctx ctx;
StringValue goos;
QVERIFY2(stub_->GoOs(ctx.get(), empty, &goos).ok(), "GoOs failed.");
QVERIFY2(goos.value().length() > 0, "Invalid GoOs value.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testTriggerReset()
{
Ctx ctx;
QVERIFY2(stub_->TriggerReset(ctx.get(), empty, &empty).ok(), "TriggerReset failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testVersion()
{
Ctx ctx;
StringValue version;
QVERIFY2(stub_->Version(ctx.get(), empty, &version).ok(), "Version failed.");
QVERIFY2(version.value().length() > 0, "Invalid version number.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogPath()
{
Ctx ctx;
StringValue logPath;
QVERIFY2(stub_->LogPath(ctx.get(), empty, &logPath).ok(), "LogPath failed.");
QVERIFY2(logPath.value().length() > 0, "Invalid LogPath.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLicensePath()
{
Ctx ctx;
StringValue licensePath;
QVERIFY2(stub_->LicensePath(ctx.get(), empty, &licensePath).ok(), "LicensePath failed.");
QVERIFY2(licensePath.value().length() > 0, "Invalid LicensePath.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testReleaseNotesLink()
{
Ctx ctx;
StringValue link;
QVERIFY2(stub_->ReleaseNotesLink(ctx.get(), empty, &link).ok(), "ReleaseNotesLink failed.");
QVERIFY2(link.value().length() > 0, "Invalid ReleaseNotesLink.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLandingPageLink()
{
Ctx ctx;
StringValue link;
QVERIFY2(stub_->LandingPageLink(ctx.get(), empty, &link).ok(), "LandingPageLink failed.");
QVERIFY2(link.value().length() > 0, "Invalid LandingPageLink.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testColorScheme()
{
Ctx ctx;
StringValue name;
string const schemeName = "dummyColors";
name.set_value(schemeName);
QVERIFY2(stub_->SetColorSchemeName(ctx.get(), name, &empty).ok(), "SetColorSchemeName failed.");
QVERIFY2(stub_->ColorSchemeName(ctx.get(), empty, &name).ok(), "ColorSchemeName failed.");
QVERIFY2(name.value() == schemeName, "ColorSchemeName failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testCurrentEmailClient()
{
Ctx ctx;
StringValue name;
string const clientName = "dummyClient";
name.set_value(clientName);
QVERIFY2(stub_->SetCurrentEmailClient(ctx.get(), name, &empty).ok(), "SeturrentEmailClient failed.");
QVERIFY2(stub_->CurrentEmailClient(ctx.get(), empty, &name).ok(), "CurrentEmailClient failed.");
QVERIFY2(name.value() == clientName, "CurrentEmailClient failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testReportBug()
{
Ctx ctx;
ReportBugRequest report;
report.set_description("dummy description");
report.set_address("dummy@proton.me");
report.set_emailclient("dummyClient");
report.set_includelogs(true);
QVERIFY2(stub_->ReportBug(ctx.get(), report, &empty).ok(), "ReportBug failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login(ctx.get(), login, &empty).ok(), "Login failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin2FA()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login2FA(ctx.get(), login, &empty).ok(), "Login2FA failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin2Passwords()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login2Passwords(ctx.get(), login, &empty).ok(), "Login2Passwords failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLoginAbort()
{
Ctx ctx;
LoginAbortRequest loginAbort;
loginAbort.set_username("dummyuser");
QVERIFY2(stub_->LoginAbort(ctx.get(), loginAbort, &empty).ok(), "loginAbort failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testCheckUpdate()
{
Ctx ctx;
QVERIFY2(stub_->CheckUpdate(ctx.get(), empty, &empty).ok(), "CheckUpdate failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testInstallUpdate()
{
Ctx ctx;
QVERIFY2(stub_->InstallUpdate(ctx.get(), empty, &empty).ok(), "InstallUpdate failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsAutomaticUpdateOn()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsAutomaticUpdateOn(ctx.get(), empty, &isOn).ok(), "IsAutomaticUpdateOn failed.");
bool newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsAutomaticUpdateOn(ctx.get(), isOn, &empty).ok(), "SetIsAutomaticUpdateOn failed.");
QVERIFY2(stub_->IsAutomaticUpdateOn(ctx.get(), empty, &isOn).ok(), "IsAutomaticUpdateOn failed.");
QVERIFY2(isOn.value() == newValue, "IsAutomaticUpdateOn failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsCacheOnDiskEnabled()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
bool const newValue = !isEnabled.value();
isEnabled.set_value(newValue);
QVERIFY2(stub_->SetIsCacheOnDiskEnabled(ctx.get(), isEnabled, &empty).ok(), "SetIsCacheOnDiskEnabled failed.");
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
QVERIFY2(isEnabled.value() == newValue, "IsCacheOnDiskEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testDiskCachePath()
{
Ctx ctx;
string const dummyPath = "/dummy/path";
StringValue path;
path.set_value(dummyPath);
QVERIFY2(stub_->SetDiskCachePath(ctx.get(), path, &empty).ok(), "SetDiskCachePath failed.");
QVERIFY2(stub_->DiskCachePath(ctx.get(), empty, &path).ok(), "DiskCachePath failed.");
QVERIFY2(path.value() == dummyPath, "DiskCachePath failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testChangeLocalCache()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
bool const newEnabled = !isEnabled.value();
string const dummyPath = "/another/dummy/path";
ChangeLocalCacheRequest request;
request.set_enablediskcache(newEnabled);
request.set_diskcachepath(dummyPath);
QVERIFY2(stub_->ChangeLocalCache(ctx.get(), request, &empty).ok(), "ChangeLocalCache failed.");
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
QVERIFY2(isEnabled.value() == newEnabled, "IsCacheOnDiskEnabled readback failed.");
StringValue path;
QVERIFY2(stub_->DiskCachePath(ctx.get(), empty, &path).ok(), "DiskCachePath failed.");
QVERIFY2(path.value() == dummyPath, "DiskCachePath failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsDohEnabled()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsDoHEnabled(ctx.get(), empty, &isEnabled).ok(), "IsDoHEnabled failed.");
bool const newValue = !isEnabled.value();
isEnabled.set_value(newValue);
QVERIFY2(stub_->SetIsDoHEnabled(ctx.get(), isEnabled, &empty).ok(), "SetIsDoHEnabled failed.");
QVERIFY2(stub_->IsDoHEnabled(ctx.get(), empty, &isEnabled).ok(), "IsDoHEnabled failed.");
QVERIFY2(isEnabled.value() == newValue, "IsDoHEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testUseSslForSmtp()
{
Ctx ctx;
BoolValue useSsl;
QVERIFY2(stub_->UseSslForSmtp(ctx.get(), empty, &useSsl).ok(), "UseSslForSmtp failed.");
bool const newValue = !useSsl.value();
useSsl.set_value(newValue);
QVERIFY2(stub_->SetUseSslForSmtp(ctx.get(), useSsl, &empty).ok(), "SetUseSslForSmtp failed.");
QVERIFY2(stub_->UseSslForSmtp(ctx.get(), empty, &useSsl).ok(), "UseSslForSmtp failed.");
QVERIFY2(useSsl.value() == newValue, "UseSslForSmtp failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testHostname()
{
Ctx ctx;
StringValue hostname;
QVERIFY2(stub_->Hostname(ctx.get(), empty, &hostname).ok(), "Hostname failed.");
QVERIFY2(hostname.value().length() > 0, "Hostname failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testImapPort()
{
Ctx ctx;
Int32Value port;
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
qint16 const newValue = qint16(port.value()) + 1;
port.set_value(qint32(newValue));
QVERIFY2(stub_->SetImapPort(ctx.get(), port, &empty).ok(), "SetImapPort failed.");
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
QVERIFY2(qint16(port.value()) == newValue, "ImapPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testSmtpPort()
{
Ctx ctx;
Int32Value port;
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
qint16 const newValue = qint16(port.value()) + 1;
port.set_value(qint32(newValue));
QVERIFY2(stub_->SetSmtpPort(ctx.get(), port, &empty).ok(), "SetSmtpPort failed.");
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
QVERIFY2(qint16(port.value()) == newValue, "SmtpPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testChangePorts()
{
Ctx ctx;
ChangePortsRequest request;
const qint32 imapPort = 2143, smtpPort = 2025;
request.set_imapport(imapPort);
request.set_smtpport(smtpPort);
QVERIFY2(stub_->ChangePorts(ctx.get(), request, &empty).ok(), "");
Int32Value port;
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
QVERIFY2(port.value() == imapPort, "ImapPort failed readback.");
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
QVERIFY2(port.value() == smtpPort, "SmtpPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsPortFree()
{
Ctx ctx;
Int32Value port;
port.set_value(143);
BoolValue isFree;
QVERIFY2(stub_->IsPortFree(ctx.get(), port, &isFree).ok(), "IsPortFree failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testKeychain()
{
Ctx ctx;
AvailableKeychainsResponse resp;
QVERIFY2(stub_->AvailableKeychains(ctx.get(), empty, &resp).ok(), "AvailableKeychains failed.");
QVERIFY2(resp.keychains().size() > 0, "AvailableKeychains returned an invalid result.");
string const newKeychain = resp.keychains().at(resp.keychains_size() - 1);
StringValue keychain;
keychain.set_value(newKeychain);
QVERIFY2(stub_->SetCurrentKeychain(ctx.get(), keychain, &empty).ok(), "SetCurrentKeychain failed.");
QVERIFY2(stub_->CurrentKeychain(ctx.get(), empty, &keychain).ok(), "CurrentKeychain failed.");
QVERIFY2(newKeychain == keychain.value(), "CurrentKeychain readback failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testUser()
{
Ctx ctx;
UserListResponse users;
QVERIFY2(stub_->GetUserList(ctx.get(), empty, &users).ok(), "GetUserList failed.");
QVERIFY2(users.users_size() > 0, "GetUserList returned an invalid value.");
std::string const userID = users.users(0).id();
UserSplitModeRequest splitModeRequest;
splitModeRequest.set_userid(userID);
splitModeRequest.set_active(true);
QVERIFY2(stub_->SetUserSplitMode(ctx.get(), splitModeRequest, &empty).ok(), "SetUserSplitMode failed");
ConfigureAppleMailRequest appleMailRequest;
appleMailRequest.set_userid(userID);
appleMailRequest.set_address("dummy@proton.ch");
QVERIFY2(stub_->ConfigureUserAppleMail(ctx.get(), appleMailRequest, &empty).ok(), "ConfigureUserAppleMail failed.");
StringValue stringValue;
stringValue.set_value(userID);
QVERIFY2(stub_->LogoutUser(ctx.get(), stringValue, &empty).ok(), "LogoutUser failed.");
QVERIFY2(stub_->RemoveUser(ctx.get(), stringValue, &empty).ok(), "RemoveUser failed.");
}
void checkAppEvents(ClientReader<StreamEvent>& reader)
{
QList<AppEvent::EventCase> expected = {
AppEvent::kInternetStatus,
AppEvent::kAutostartFinished,
AppEvent::kResetFinished,
AppEvent::kReportBugFinished,
AppEvent::kReportBugSuccess,
AppEvent::kReportBugError,
AppEvent::kShowMainWindow,
};
StreamEvent event;
while (reader.Read(&event)) {
QVERIFY2(event.event_case() == StreamEvent::kApp, "Received invalid event while waiting for app event.");
AppEvent const& appEvent = event.app();
AppEvent::EventCase const eventCase = appEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected app event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected app event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for app events.");
}
void checkLoginEvents(ClientReader<StreamEvent>& reader)
{
QList<LoginEvent::EventCase> expected = {
LoginEvent::kError,
LoginEvent::kTfaRequested,
LoginEvent::kTwoPasswordRequested,
LoginEvent::kFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kLogin, "Received invalid event while waiting for login event.");
LoginEvent const& loginEvent = event.login();
LoginEvent::EventCase const eventCase = loginEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected login event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected login event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for login events.");
}
void checkUpdateEvents(ClientReader<StreamEvent>& reader)
{
QList<UpdateEvent::EventCase> expected = {
UpdateEvent::kError,
UpdateEvent::kManualReady,
UpdateEvent::kManualRestartNeeded,
UpdateEvent::kForce,
UpdateEvent::kSilentRestartNeeded,
UpdateEvent::kIsLatestVersion,
UpdateEvent::kCheckFinished
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kUpdate, "Received invalid event while waiting for update event.");
UpdateEvent const& updateEvent = event.update();
UpdateEvent::EventCase const eventCase = updateEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected update event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected update event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for update events.");
}
void checkCacheEvents(ClientReader<StreamEvent>& reader)
{
QList<CacheEvent::EventCase> expected = {
CacheEvent::kError,
CacheEvent::kLocationChangedSuccess,
CacheEvent::kChangeLocalCacheFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kCache, "Received invalid event while waiting for cache event.");
CacheEvent const& cacheEvent = event.cache();
CacheEvent::EventCase const eventCase = cacheEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected cache event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected cache event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for cache events.");
}
void checkMailsSettingsEvents(ClientReader<StreamEvent>& reader)
{
QList<MailSettingsEvent::EventCase> expected = {
MailSettingsEvent::kError,
MailSettingsEvent::kUseSslForSmtpFinished,
MailSettingsEvent::kChangePortsFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kMailSettings, "Received invalid event while waiting for mail settings event.");
MailSettingsEvent const& mailSettingsEvent = event.mailsettings();
MailSettingsEvent::EventCase const eventCase = mailSettingsEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected mail settings event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected mail settings event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for mail settings events.");
}
void checkKeychainEvents(ClientReader<StreamEvent>& reader)
{
QList<KeychainEvent::EventCase> expected = {
KeychainEvent::kChangeKeychainFinished,
KeychainEvent::kHasNoKeychain,
KeychainEvent::kRebuildKeychain,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kKeychain, "Received invalid event while waiting for keychain event.");
KeychainEvent const& keychainEvent = event.keychain();
KeychainEvent::EventCase const eventCase = keychainEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected keychain event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected keychain event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for keychain events.");
}
void checkMailEvents(ClientReader<StreamEvent>& reader)
{
QList<MailEvent::EventCase> expected = {
MailEvent::kNoActiveKeyForRecipientEvent,
MailEvent::kAddressChanged,
MailEvent::kAddressChangedLogout,
MailEvent::kApiCertIssue,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kMail, "Received invalid event while waiting for mail event.");
MailEvent const& mailEvent = event.mail();
MailEvent::EventCase const eventCase = mailEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected mail event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected mail event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for mail events.");
}
void checkUserEvents(ClientReader<StreamEvent>& reader)
{
QList<UserEvent::EventCase> expected = {
UserEvent::kToggleSplitModeFinished,
UserEvent::kUserDisconnected,
UserEvent::kUserChanged,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kUser, "Received invalid event while waiting for user event.");
UserEvent const& userEvent = event.user();
UserEvent::EventCase const eventCase = userEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected user event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected user event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for user events.");
}
void RpcClient::testStream()
{
Ctx ctx;
std::unique_ptr<ClientReader<StreamEvent>> reader = stub_->GetEvents(ctx.get(), empty);
QVERIFY2(reader, "Could not instanciate event stream reader");
checkAppEvents(*reader);
checkLoginEvents(*reader);
checkUpdateEvents(*reader);
checkCacheEvents(*reader);
checkMailsSettingsEvents(*reader);
checkKeychainEvents(*reader);
checkMailEvents(*reader);
checkUserEvents(*reader);
}
#pragma clang diagnostic pop

View File

@ -0,0 +1,98 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.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_RPC_CLIENT_TEST_RPC_CLIENT_H
#define BRIDGE_RPC_CLIENT_TEST_RPC_CLIENT_H
#include "rpc/bridge_rpc.grpc.pb.h"
#include "grpc++/grpc++.h"
#include <QtCore>
//**********************************************************************************************************************
/// \brief Rpc Client class.
//**********************************************************************************************************************
class RpcClient: public QObject
{
Q_OBJECT
public: // member functions
explicit RpcClient(); ///< Default constructor.
RpcClient(RpcClient const &) = delete; ///< Disabled copy-constructor.
RpcClient(RpcClient &&) = delete; ///< Disabled assignment copy-constructor.
~RpcClient() override = default; ///< Destructor.
RpcClient &operator=(RpcClient const &) = delete; ///< Disabled assignment operator.
RpcClient &operator=(RpcClient &&) = delete; ///< Disabled move assignment operator.
private slots:
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
void initTestCase(); ///< Check if the connection with the RPC server is established.
void testGetCursorPos(); ///< Test the GetCursorPos call.
void testGuiReady(); ///< Test the GuiReady call.
void testQuit(); ///< Test the Quit call.
void testRestart(); ///< Test the Restart call.
void testShowOnStartup(); ///< Test the ShowOnStartup calls.
void testShowSplashScreen(); ///< Test the ShowSplashScreen calls.
void testDockIconVisible(); ///< Test the DockIconVisible calls.
void testIsFirstGuiStart(); ///< Test the IsFirstGuiStart calls.
void testIsAutostartOn(); ///< Test the IsAutostartOn calls.
void testIsBetaEnabled(); ///< Test the IsBetaEnabled calls.
void testGoOs(); ///< Test the GoOs call.
void testTriggerReset(); ///< Test the TriggerReset call.
void testVersion(); ///< Test the Version call.
void testLogPath(); ///< Test the LogPath call.
void testLicensePath(); ///< Test the LicensePath call.
void testReleaseNotesLink(); ///< Test the ReleastNotesLink call.
void testLandingPageLink(); ///< Test the LandingPageLink call.
void testColorScheme(); ///< Test the ColorScheme calls.
void testCurrentEmailClient(); ///< Test the CurrentEmailClient calls.
void testReportBug(); ///< Test the ReportBug call.
void testLogin(); ///< Test the Login call.
void testLogin2FA(); ///< Test the Login2FA call.
void testLogin2Passwords(); ///< Test the Login2Passwords call.
void testLoginAbort(); ///< Test the LoginAbort call.
void testCheckUpdate(); ///< Test the CheckUpdate call.
void testInstallUpdate(); ///< Test the CheckUpdate call.
void testIsAutomaticUpdateOn(); ///< Test the IsAutomaticUpdateOn calls.
void testIsCacheOnDiskEnabled(); ///< Test the IsCacheOnDiskEnabled calls.
void testDiskCachePath(); ///< Test the DiskCachePath calls.
void testChangeLocalCache(); ///< Test the ChangeLocalPath calls.
void testIsDohEnabled(); ///< Test the IsDohEnabled calls.
void testUseSslForSmtp(); ///< Test the UseSslForSmtp calls.
void testHostname(); ///< Test the Hostname call.
void testImapPort(); ///< Test the ImapPort calls.
void testSmtpPort(); ///< Test the SmtpPort calls.
void testChangePorts(); ///< Test the ChangePorts call.
void testIsPortFree(); ///< Test the IsPortFree call.
void testKeychain(); ///< Test the keychains related calls.
void testUser(); ///< Test the user related calls.
void testStream(); ///< Test the server to client stream
#pragma clang diagnostic pop
private: // data members
std::shared_ptr<grpc::Channel> channel_ { nullptr }; ///< The gRPC channel.
std::shared_ptr<bridgerpc::BridgeRpc::Stub> stub_ { nullptr }; ///< The gRPC stub (a.k.a. client).
};
#endif //BRIDGE_RPC_CLIENT_TEST_RPC_CLIENT_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff