diff --git a/CMakeLists.txt b/CMakeLists.txt index da3f5d5f92e99038968e2926fa44c1a10bbb3d1a..2dfb1b4267eaea75be9202d05e4092cdded31f89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -327,6 +327,7 @@ SET( libringclient_LIB_SRCS src/bannedcontactmodel.cpp src/contactmodel.cpp src/newcallmodel.cpp + src/newdevicemodel.cpp src/conversationmodel.cpp src/database.cpp src/authority/daemon.cpp @@ -498,6 +499,7 @@ SET(libringclient_api_LIB_HDRS src/api/lrc.h src/api/newaccountmodel.h src/api/newcallmodel.h + src/api/newdevicemodel.h src/api/contactmodel.h src/api/conversationmodel.h src/api/profile.h diff --git a/src/api/account.h b/src/api/account.h index e7151d1530afad5ecc2238c3a59ef43acc91f9c7..d36abdd007916f99e193bb03c9853b730562166a 100644 --- a/src/api/account.h +++ b/src/api/account.h @@ -35,6 +35,7 @@ class NewCallModel; class ContactModel; class ConversationModel; class NewAccountModel; +class NewDeviceModel; namespace account { @@ -85,6 +86,7 @@ struct Info std::unique_ptr<lrc::api::NewCallModel> callModel; std::unique_ptr<lrc::api::ContactModel> contactModel; std::unique_ptr<lrc::api::ConversationModel> conversationModel; + std::unique_ptr<lrc::api::NewDeviceModel> deviceModel; NewAccountModel* accountModel {nullptr}; }; diff --git a/src/api/newdevicemodel.h b/src/api/newdevicemodel.h new file mode 100644 index 0000000000000000000000000000000000000000..1aac83a01d0026e1230e48a7c9cc9b471ec96e7d --- /dev/null +++ b/src/api/newdevicemodel.h @@ -0,0 +1,123 @@ +/**************************************************************************** + * Copyright (C) 2017-2018 Savoir-faire Linux * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#pragma once + +// Std +#include <memory> +#include <string> +#include <list> + +// Qt +#include <qobject.h> +#include <QObject> + +// Lrc +#include "api/account.h" +#include "typedefs.h" + +namespace lrc +{ + +class CallbacksHandler; +class NewDeviceModelPimpl; + +namespace api +{ + +namespace account { struct Info; } + +struct Device +{ + std::string id = ""; + std::string name = ""; + bool isCurrent = false; +}; + +/** + * @brief Class that manages ring devices for an account + */ +class LIB_EXPORT NewDeviceModel : public QObject { + Q_OBJECT + +public: + /** + * Used by deviceRevoked's status + */ + enum class Status { + SUCCESS = 0, + WRONG_PASSWORD = 1, + UNKNOWN_DEVICE = 2 + }; + const account::Info& owner; + + NewDeviceModel(const account::Info& owner, const CallbacksHandler& callbacksHandler); + ~NewDeviceModel(); + + /** + * Get ring devices of an account + * @return a copy of current devices + */ + std::list<Device> getAllDevices() const; + + /** + * Retrieve a device by its id + * @param id of the device + * @return the device if found else a device with a null id + */ + Device getDevice(const std::string& id) const; + + /** + * Revoke a ring device + * @param id of the device to revoke + * @param password of the account's archive + * @note will emit deviceRevoked when finished + */ + void revokeDevice(const std::string& id, const std::string& password); + + /** + * Change the name of the current device + * @param newName + * @note will emit deviceUpdated when finished + * @note ring can't change the name of another device + */ + void setCurrentDeviceName(const std::string& newName); + +Q_SIGNALS: + /** + * Link to this signal to know when a new device is added + * @param id added device + */ + void deviceAdded(const std::string& id) const; + /** + * Link to this signal to know when a device is removed + * @param id removed device + * @param Status (SUCCESS, WRONG_PASSWORD, UNKNOWN_DEVICE) + */ + void deviceRevoked(const std::string& id, const Status status) const; + /** + * Link to this signal when a device get a new name + * @param id + */ + void deviceUpdated(const std::string& id) const; + +private: + std::unique_ptr<NewDeviceModelPimpl> pimpl_; +}; + +} // namespace api +} // namespace lrc diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp index 1ed6fcef3f4b65d90f4983d0cb48eef2b6205387..88739629a043f855039c71274f0338d362ab786b 100644 --- a/src/callbackshandler.cpp +++ b/src/callbackshandler.cpp @@ -118,6 +118,16 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent) &ConfigurationManagerInterface::dataTransferEvent, this, &CallbacksHandler::slotDataTransferEvent); + + connect(&ConfigurationManager::instance(), + &ConfigurationManagerInterface::knownDevicesChanged, + this, + &CallbacksHandler::slotKnownDevicesChanged); + + connect(&ConfigurationManager::instance(), + &ConfigurationManagerInterface::deviceRevocationEnded, + this, + &CallbacksHandler::slotDeviceRevokationEnded); } CallbacksHandler::~CallbacksHandler() @@ -327,4 +337,23 @@ CallbacksHandler::slotDataTransferEvent(qulonglong dringId, uint codeStatus) } } +void +CallbacksHandler::slotKnownDevicesChanged(const QString& accountId, + const QMap<QString, QString>& devices) +{ + std::map<std::string, std::string> stdDevices; + for (auto item : devices.keys()) + stdDevices[item.toStdString()] = devices.value(item).toStdString(); + auto accountId2 = accountId.toStdString(); + emit knownDevicesChanged(accountId2, stdDevices); +} + +void +CallbacksHandler::slotDeviceRevokationEnded(const QString& accountId, + const QString& deviceId, + const int status) +{ + emit deviceRevocationEnded(accountId.toStdString(), deviceId.toStdString(), status); +} + } // namespace lrc diff --git a/src/callbackshandler.h b/src/callbackshandler.h index 8630cab8ea696813636756ff6e64de0e0b21a3d6..f9dda0de9a3bf260f9b0f49c3a379b4bfb58228c 100644 --- a/src/callbackshandler.h +++ b/src/callbackshandler.h @@ -20,6 +20,8 @@ // Std #include <memory> +#include <string> +#include <map> // Qt #include <qobject.h> @@ -171,6 +173,25 @@ Q_SIGNALS: void transferStatusTimeoutExpired(long long dringId, api::datatransfer::Info info); void transferStatusUnjoinable(long long dringId, api::datatransfer::Info info); + + /** + * Connect this signal to get when a device name changed or a device is added + * @param accountId interaction receiver. + * @param devices A map of device IDs with corresponding labels. + */ + void knownDevicesChanged(std::string& accountId, + std::map<std::string,std::string> devices); + + /** + * Emit deviceRevocationEnded + * @param accountId + * @param deviceId + * @param status SUCCESS = 0, WRONG_PASSWORD = 1, UNKNOWN_DEVICE = 2 + */ + void deviceRevocationEnded(const std::string& accountId, + const std::string& deviceId, + const int status); + private Q_SLOTS: /** * Emit newAccountMessage @@ -291,6 +312,24 @@ private Q_SLOTS: void slotDataTransferEvent(qulonglong id, uint code); + /** + * Emit knownDevicesChanged + * @param accountId + * @param devices A map of device IDs and corresponding labels + */ + void slotKnownDevicesChanged(const QString& accountId, + const QMap<QString, QString>& devices); + + /** + * Emit deviceRevocationEnded + * @param accountId + * @param deviceId + * @param status SUCCESS = 0, WRONG_PASSWORD = 1, UNKNOWN_DEVICE = 2 + */ + void slotDeviceRevokationEnded(const QString& accountId, + const QString& deviceId, + const int status); + private: const api::Lrc& parent; }; diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp index 142441530d7b9318184e1bb833fab08506a5a573..862d42499e70630a24e8ef3040e594710120c78d 100644 --- a/src/newaccountmodel.cpp +++ b/src/newaccountmodel.cpp @@ -20,12 +20,13 @@ // LRC -#include "api/lrc.h" -#include "api/newcallmodel.h" -#include "api/contactmodel.h" -#include "api/conversationmodel.h" #include "api/account.h" #include "api/behaviorcontroller.h" +#include "api/contactmodel.h" +#include "api/conversationmodel.h" +#include "api/lrc.h" +#include "api/newcallmodel.h" +#include "api/newdevicemodel.h" #include "authority/databasehelper.h" #include "callbackshandler.h" #include "database.h" @@ -219,6 +220,7 @@ NewAccountModelPimpl::addToAccounts(const std::string& accountId) owner.callModel = std::make_unique<NewCallModel>(owner, callbacksHandler); owner.contactModel = std::make_unique<ContactModel>(owner, database, callbacksHandler); owner.conversationModel = std::make_unique<ConversationModel>(owner, lrc, database, callbacksHandler, behaviorController); + owner.deviceModel = std::make_unique<NewDeviceModel>(owner, callbacksHandler); owner.accountModel = &linked; } diff --git a/src/newdevicemodel.cpp b/src/newdevicemodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc916a716a43b3c167a6b74f2e6c7ec6b1dfe08d --- /dev/null +++ b/src/newdevicemodel.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** + * Copyright (C) 2017-2018 Savoir-faire Linux * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ +#include "api/newdevicemodel.h" + +// std +#include <list> +#include <mutex> + +// LRC +#include "callbackshandler.h" +#include "dbus/configurationmanager.h" + +// Daemon +#include <account_const.h> + +// Qt +#include <QObject> + +namespace lrc +{ + + +using namespace api; + +class NewDeviceModelPimpl: public QObject +{ + Q_OBJECT +public: + NewDeviceModelPimpl(const NewDeviceModel& linked, const CallbacksHandler& callbacksHandler); + ~NewDeviceModelPimpl(); + + const CallbacksHandler& callbacksHandler; + const NewDeviceModel& linked; + + std::mutex devicesMtx_; + std::string currentDeviceId_; + std::list<Device> devices_; +public Q_SLOTS: + /** + * Listen from CallbacksHandler to get when a device name changed or a device is added + * @param accountId interaction receiver. + * @param devices A map of device IDs with corresponding labels. + */ + void slotKnownDevicesChanged(const std::string& accountId, + const std::map<std::string, std::string> devices); + + /** + * update devices_ when a device is revoked + * @param accountId + * @param deviceId + * @param status SUCCESS = 0, WRONG_PASSWORD = 1, UNKNOWN_DEVICE = 2 + */ + void slotDeviceRevocationEnded(const std::string& accountId, + const std::string& deviceId, + const int status); +}; + +NewDeviceModel::NewDeviceModel(const account::Info& owner, const CallbacksHandler& callbacksHandler) +: owner(owner) +, pimpl_(std::make_unique<NewDeviceModelPimpl>(*this, callbacksHandler)) +{ } + +NewDeviceModel::~NewDeviceModel() {} + +std::list<Device> +NewDeviceModel::getAllDevices() const +{ + return pimpl_->devices_; +} + +Device +NewDeviceModel::getDevice(const std::string& id) const +{ + std::lock_guard<std::mutex> lock(pimpl_->devicesMtx_); + auto i = std::find_if( + pimpl_->devices_.begin(), pimpl_->devices_.end(), + [id](const Device& d) { + return d.id == id; + }); + + if (i == pimpl_->devices_.end()) return {}; + + return *i; +} + +void +NewDeviceModel::revokeDevice(const std::string& id, const std::string& password) +{ + ConfigurationManager::instance().revokeDevice(owner.id.c_str(), password.c_str(), id.c_str()); +} + +void +NewDeviceModel::setCurrentDeviceName(const std::string& newName) +{ + MapStringString details = {}; + details[DRing::Account::ConfProperties::RING_DEVICE_NAME] = newName.c_str(); + ConfigurationManager::instance().setAccountDetails(owner.id.c_str(), details); +} + +NewDeviceModelPimpl::NewDeviceModelPimpl(const NewDeviceModel& linked, const CallbacksHandler& callbacksHandler) +: linked(linked) +, callbacksHandler(callbacksHandler) +, devices_({}) +{ + const MapStringString aDetails = ConfigurationManager::instance().getAccountDetails(linked.owner.id.c_str()); + currentDeviceId_ = aDetails.value(DRing::Account::ConfProperties::RING_DEVICE_ID).toStdString(); + const MapStringString accountDevices = ConfigurationManager::instance().getKnownRingDevices(linked.owner.id.c_str()); + auto it = accountDevices.begin(); + while (it != accountDevices.end()) { + { + std::lock_guard<std::mutex> lock(devicesMtx_); + auto device = Device { + /* id= */it.key().toStdString(), + /* name= */it.value().toStdString(), + /* isCurrent= */it.key().toStdString() == currentDeviceId_ + }; + if (device.isCurrent) { + devices_.emplace_front(device); + } else { + devices_.emplace_back(device); + } + } + ++it; + } + + connect(&callbacksHandler, &CallbacksHandler::knownDevicesChanged, this, + &NewDeviceModelPimpl::slotKnownDevicesChanged); + connect(&callbacksHandler, &CallbacksHandler::deviceRevocationEnded, this, + &NewDeviceModelPimpl::slotDeviceRevocationEnded); +} + +NewDeviceModelPimpl::~NewDeviceModelPimpl() +{ + disconnect(&callbacksHandler, &CallbacksHandler::knownDevicesChanged, this, + &NewDeviceModelPimpl::slotKnownDevicesChanged); + disconnect(&callbacksHandler, &CallbacksHandler::deviceRevocationEnded, this, + &NewDeviceModelPimpl::slotDeviceRevocationEnded); +} + +void +NewDeviceModelPimpl::slotKnownDevicesChanged(const std::string& accountId, + const std::map<std::string, std::string> devices) +{ + if (accountId != linked.owner.id) return; + auto devicesMap = devices; + // Update current devices + std::list<std::string> updatedDevices; + { + std::lock_guard<std::mutex> lock(devicesMtx_); + for (auto& device : devices_) { + if (devicesMap.find(device.id) != devicesMap.end()) { + if (device.name != devicesMap[device.id]) { + updatedDevices.emplace_back(device.id); + device.name = devicesMap[device.id]; + } + devicesMap.erase(device.id); + } + } + } + for (const auto& device : updatedDevices) + emit linked.deviceUpdated(device); + + // Add new devices + std::list<std::string> addedDevices; + { + std::lock_guard<std::mutex> lock(devicesMtx_); + auto it = devicesMap.begin(); + while (it != devicesMap.end()) { + devices_.emplace_back(Device { + /* id= */it->first, + /* name= */it->second, + /* isCurrent= */false + }); + addedDevices.emplace_back(it->first); + ++it; + } + } + for (const auto& device : addedDevices) + emit linked.deviceAdded(device); +} + + +void +NewDeviceModelPimpl::slotDeviceRevocationEnded(const std::string& accountId, + const std::string& deviceId, + const int status) +{ + if (accountId != linked.owner.id) return; + if (status == 0) { + std::lock_guard<std::mutex> lock(devicesMtx_); + auto it = std::find_if( + devices_.begin(), devices_.end(), + [deviceId](const Device& d) { + return d.id == deviceId; + }); + + if (it != devices_.end()) + devices_.erase(it); + } + + switch (status) { + case 0: + emit linked.deviceRevoked(deviceId, NewDeviceModel::Status::SUCCESS); + break; + case 1: + emit linked.deviceRevoked(deviceId, NewDeviceModel::Status::WRONG_PASSWORD); + break; + case 2: + emit linked.deviceRevoked(deviceId, NewDeviceModel::Status::UNKNOWN_DEVICE); + break; + default: + break; + } +} + +} // namespace lrc + +#include "newdevicemodel.moc" +#include "api/moc_newdevicemodel.cpp" diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h index 5846d5f9cdcaa47c55e3c414ab9dff366ee9b67d..3d4e0ca6c6abbf4506921810358f9627dd357491 100644 --- a/src/qtwrapper/configurationmanager_wrap.h +++ b/src/qtwrapper/configurationmanager_wrap.h @@ -566,6 +566,10 @@ public Q_SLOTS: // METHODS DRing::removeContact(accountId.toStdString(), uri.toStdString(), ban); } + void revokeDevice(const QString &accountId, const QString &password, const QString &deviceId) { + DRing::revokeDevice(accountId.toStdString(), password.toStdString(), deviceId.toStdString()); + } + void addContact(const QString &accountId, const QString &uri) { DRing::addContact(accountId.toStdString(), uri.toStdString()); } @@ -676,6 +680,7 @@ Q_SIGNALS: // SIGNALS void contactAdded(const QString &accountID, const QString &uri, bool banned); void contactRemoved(const QString &accountID, const QString &uri, bool banned); void dataTransferEvent(qulonglong transfer_id, uint code); + void deviceRevocationEnded(const QString& accountId, const QString& deviceId, int status); }; namespace org { namespace ring { namespace Ring { diff --git a/test/mocks/configurationmanager_mock.h b/test/mocks/configurationmanager_mock.h index f23d418b5a8b9fc5d924fb3e40a940fd464e2aea..76abe21be97ea2985288d871cdeecede12c5a9d6 100644 --- a/test/mocks/configurationmanager_mock.h +++ b/test/mocks/configurationmanager_mock.h @@ -53,6 +53,7 @@ private: QMap<QString, VectorMapStringString> accountToContactsMap; QStringList availableContacts_; std::mutex contactsMtx_; + QMap<QString, QMap<QString, QString>> devices; public: @@ -86,11 +87,22 @@ public: } } accountToContactsMap.insert(account, contacts); + // Init devices + MapStringString devicesForAccount; + devicesForAccount["device0"] = "pc"; + if (account.toStdString() == "ring3") + devicesForAccount["device1"] = "tel"; + devices[account] = devicesForAccount; } } ~ConfigurationManagerInterface() {} + void addNewDevice(const QString& accountId, const QString& deviceId, const QString& name) { + devices[accountId][deviceId] = name; + emit knownDevicesChanged(accountId, devices[accountId]); + } + void emitIncomingAccountMessage(const QString& accountId, const QString& from, const QMap<QString,QString>& payloads) { emit incomingAccountMessage(accountId, from, payloads); @@ -137,9 +149,7 @@ public Q_SLOTS: // METHODS MapStringString getKnownRingDevices(const QString& accountId) { - Q_UNUSED(accountId) - MapStringString temp; - return temp; + return devices[accountId]; } bool lookupName(const QString& accountId, const QString& nameServiceURL, const QString& name) @@ -174,6 +184,7 @@ public Q_SLOTS: // METHODS } else { result.insert("Account.type", "SIP"); } + result.insert("Account.deviceID", "device0"); return result; } @@ -183,6 +194,7 @@ public Q_SLOTS: // METHODS accountList << QString("ring0"); // Used in conversationmodeltester accountList << QString("ring1"); // Used in contactmodeltester accountList << QString("ring2"); // Used in newcallmodeltester + accountList << QString("ring3"); // Used in newdevicemodeltester accountList << QString("sip0"); accountList << QString("sip1"); return accountList; @@ -448,8 +460,13 @@ public Q_SLOTS: // METHODS void setAccountDetails(const QString& accountId, MapStringString details) { - Q_UNUSED(accountId) - Q_UNUSED(details) + if (accountId.toStdString() == "ring3") { + // testSetCurrentDeviceName + if (details.contains(DRing::Account::ConfProperties::RING_DEVICE_NAME)) { + devices["ring3"]["device0"] = details[DRing::Account::ConfProperties::RING_DEVICE_NAME]; + emit knownDevicesChanged(accountId, devices[accountId]); + } + } } void setAccountsOrder(const QString& order) @@ -648,6 +665,19 @@ public Q_SLOTS: // METHODS emit contactRemoved(accountId, uri, ban); } + void revokeDevice(const QString &accountId, const QString &password, const QString &deviceId) { + if (password == "") { + if (devices[accountId].contains(deviceId)) { + devices[accountId].remove(deviceId); + emit deviceRevocationEnded(accountId, deviceId, 0); + } else { + emit deviceRevocationEnded(accountId, deviceId, 2); + } + } else { + emit deviceRevocationEnded(accountId, deviceId, 1); + } + } + void addContact(const QString &accountId, const QString &uri) { if (getAccountList().indexOf(accountId) == -1) return; @@ -803,6 +833,7 @@ Q_SIGNALS: // SIGNALS void contactAdded(const QString &accountId, const QString &uri, bool banned); void contactRemoved(const QString &accountId, const QString &uri, bool banned); void dataTransferEvent(uint64_t transfer_id, uint32_t code); + void deviceRevocationEnded(const QString& accountId, const QString& deviceId, int status); }; namespace org { diff --git a/test/newdevicemodeltester.cpp b/test/newdevicemodeltester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4a585944f84fcb95f65d1e89ec2f72a6fce7d18a --- /dev/null +++ b/test/newdevicemodeltester.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2017-2018 Savoir-faire Linux Inc. + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "newdevicemodeltester.h" + +// std +#include <string> + +// Qt +#include "utils/waitforsignalhelper.h" + +// Lrc +#include <api/newaccountmodel.h> +#include <api/newdevicemodel.h> +#include <dbus/configurationmanager.h> + + +namespace ring +{ +namespace test +{ + +CPPUNIT_TEST_SUITE_REGISTRATION(NewDeviceModelTester); + +NewDeviceModelTester::NewDeviceModelTester() +: lrc_(new lrc::api::Lrc()) +, accInfo_(lrc_->getAccountModel().getAccountInfo("ring3")) +{ + +} + +void +NewDeviceModelTester::setUp() +{ + +} + +void +NewDeviceModelTester::testGetAllDevices() +{ + // See mocked ConfigurationManager::getKnownRingDevices() and getAccountDetails() + auto devices = accInfo_.deviceModel->getAllDevices(); + // Here, we should have 2 devices (device0 pc) and (device1 tel) + CPPUNIT_ASSERT_EQUAL(static_cast<int>(devices.size()), 2); + auto device0 = devices.front(); + CPPUNIT_ASSERT_EQUAL(device0.isCurrent, true); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device0")); + CPPUNIT_ASSERT_EQUAL(device0.name, std::string("pc")); + auto device1 = devices.back(); + CPPUNIT_ASSERT_EQUAL(device1.isCurrent, false); + CPPUNIT_ASSERT_EQUAL(device1.id, std::string("device1")); + CPPUNIT_ASSERT_EQUAL(device1.name, std::string("tel")); +} + +void +NewDeviceModelTester::testGetValidDevice() +{ + // device0 defined in mocked ConfigurationManager + auto device0 = accInfo_.deviceModel->getDevice("device0"); + CPPUNIT_ASSERT_EQUAL(device0.isCurrent, true); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device0")); + CPPUNIT_ASSERT_EQUAL(device0.name, std::string("pc")); +} + +void +NewDeviceModelTester::testGetInvalidDevice() +{ + // notADevice not defined in mocked ConfigurationManager + auto device0 = accInfo_.deviceModel->getDevice("notADevice"); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("")); +} + +void +NewDeviceModelTester::testNewDeviceAdded() +{ + // this will add a new device for ring3 (see mock) + ConfigurationManager::instance().addNewDevice("ring3", "device2", "tv"); + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceAdded(const std::string& id))).wait(1000); + auto device0 = accInfo_.deviceModel->getDevice("device2"); + CPPUNIT_ASSERT_EQUAL(device0.isCurrent, false); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device2")); + CPPUNIT_ASSERT_EQUAL(device0.name, std::string("tv")); + // Revoke device for other tests + // NOTE: should be removed when test will not depends from each others + // See mock + ConfigurationManager::instance().revokeDevice("ring3", "", "device2"); +} + +void +NewDeviceModelTester::testRevokeDevice() +{ + // this will add a new device for ring3 (see mock) + ConfigurationManager::instance().addNewDevice("ring3", "device2", "tv"); + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceAdded(const std::string& id))).wait(1000); + // Then revoke device + accInfo_.deviceModel->revokeDevice("device2", ""); // empty password = correct + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceRevoked(const std::string& id, + const lrc::api::NewDeviceModel::Status status))) + .wait(1000); + // Should not exists anymore + auto device2 = accInfo_.deviceModel->getDevice("device2"); + CPPUNIT_ASSERT_EQUAL(device2.id, std::string("")); +} + +void +NewDeviceModelTester::testRevokeDeviceInvalidDevice() +{ + // this will add a new device for ring3 (see mock) + ConfigurationManager::instance().addNewDevice("ring3", "device2", "tv"); + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceAdded(const std::string& id))).wait(1000); + // Then revoke device + accInfo_.deviceModel->revokeDevice("device3", ""); // empty password = correct + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceRevoked(const std::string& id, + const lrc::api::NewDeviceModel::Status status))) + .wait(1000); + // device2 still exists + auto device0 = accInfo_.deviceModel->getDevice("device2"); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device2")); + // Revoke device for other tests + // NOTE: should be removed when test will not depends from each others + // See mock + ConfigurationManager::instance().revokeDevice("ring3", "", "device2"); +} + +void +NewDeviceModelTester::testRevokeDeviceInvalidPassword() +{ + // this will add a new device for ring3 (see mock) + ConfigurationManager::instance().addNewDevice("ring3", "device2", "tv"); + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceAdded(const std::string& id))).wait(1000); + // Then revoke device + accInfo_.deviceModel->revokeDevice("device2", "notAPass"); // !empty password = incorrect + // Wait for deviceAdded + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceRevoked(const std::string& id, + const lrc::api::NewDeviceModel::Status status))) + .wait(1000); + // device2 still exists + auto device0 = accInfo_.deviceModel->getDevice("device2"); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device2")); + // Revoke device for other tests + // NOTE: should be removed when test will not depends from each others + // See mock + ConfigurationManager::instance().revokeDevice("ring3", "", "device2"); +} + +void +NewDeviceModelTester::testSetCurrentDeviceName() +{ + // Will change the name of device0 + accInfo_.deviceModel->setCurrentDeviceName("NewDeviceName"); + // Will call mocked ConfigurationManager::setAccountDetails() + // Because known devices changed, NewDeviceModel::deviceUpdated will be emitted + WaitForSignalHelper(*accInfo_.deviceModel, + SIGNAL(deviceUpdated(const std::string& id))).wait(1000); + // device0 should have a new name now. + auto device0 = accInfo_.deviceModel->getDevice("device0"); + CPPUNIT_ASSERT_EQUAL(device0.isCurrent, true); + CPPUNIT_ASSERT_EQUAL(device0.id, std::string("device0")); + CPPUNIT_ASSERT_EQUAL(device0.name, std::string("NewDeviceName")); +} + +void +NewDeviceModelTester::tearDown() +{ + accInfo_.deviceModel->setCurrentDeviceName("pc"); +} + +} // namespace test +} // namespace ring diff --git a/test/newdevicemodeltester.h b/test/newdevicemodeltester.h new file mode 100644 index 0000000000000000000000000000000000000000..be1ee76eaa6fb158992fb478ad2e8320cbd5ecae --- /dev/null +++ b/test/newdevicemodeltester.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2017-2018 Savoir-faire Linux Inc. + * + * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#pragma once + +// cppunit +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +// std +#include <memory> + +// Qt +#include <QObject> + +// lrc +#include "api/lrc.h" +#include "api/account.h" + +namespace ring +{ +namespace test +{ + +class NewDeviceModelTester : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(NewDeviceModelTester); + CPPUNIT_TEST(testGetAllDevices); + CPPUNIT_TEST(testGetValidDevice); + CPPUNIT_TEST(testGetInvalidDevice); + CPPUNIT_TEST(testNewDeviceAdded); + CPPUNIT_TEST(testRevokeDevice); + CPPUNIT_TEST(testRevokeDeviceInvalidDevice); + CPPUNIT_TEST(testRevokeDeviceInvalidPassword); + CPPUNIT_TEST(testSetCurrentDeviceName); + CPPUNIT_TEST_SUITE_END(); + +public: + NewDeviceModelTester(); + /** + * Method automatically called before each test by CppUnit + */ + void setUp(); + /** + * Retrieve all devices of an account + */ + void testGetAllDevices(); + /** + * Test getting an existing device + */ + void testGetValidDevice(); + /** + * Test getting a non existing device + */ + void testGetInvalidDevice(); + /** + * Test new device added + */ + void testNewDeviceAdded(); + /** + * Test to remove a device (valid device, valid password) + */ + void testRevokeDevice(); + /** + * Test to remove a device (invalid device, valid password) + */ + void testRevokeDeviceInvalidDevice(); + /** + * Test to remove a device (valid device, invalid password) + */ + void testRevokeDeviceInvalidPassword(); + /** + * Test to change the current device name + */ + void testSetCurrentDeviceName(); + /** + * Method automatically called after each test by CppUnit + */ + void tearDown(); + +protected: + std::unique_ptr<lrc::api::Lrc> lrc_; + const lrc::api::account::Info& accInfo_; +}; + +} // namespace test +} // namespace ring