/* * Copyright (C) 2021-2022 Savoir-faire Linux Inc. * * Author: Olivier Dion @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 #include #include #include #include "common.h" /* Jami */ #include "account_const.h" #include "jami.h" #include "fileutils.h" #include "manager.h" /* Make GCC quiet about unused functions */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" void wait_for_announcement_of(const std::vector accountIDs, std::chrono::seconds timeout) { std::map> confHandlers; std::mutex mtx; std::unique_lock lk {mtx}; std::condition_variable cv; std::vector accountsReady(accountIDs.size()); size_t to_be_announced = accountIDs.size(); confHandlers.insert( DRing::exportable_callback( [&, accountIDs = std::move(accountIDs)](const std::string& accountID, const std::map& details) { for (size_t i = 0; i < accountIDs.size(); ++i) { if (accountIDs[i] != accountID) { continue; } try { if ("true" != details.at(DRing::Account::VolatileProperties::DEVICE_ANNOUNCED)) { continue; } } catch (const std::out_of_range&) { continue; } accountsReady[i] = true; cv.notify_one(); } })); JAMI_DBG("Waiting for %zu account to be announced...", to_be_announced); DRing::registerSignalHandlers(confHandlers); CPPUNIT_ASSERT(cv.wait_for(lk, timeout, [&] { for (const auto& rdy : accountsReady) { if (not rdy) { return false; } } return true; })); DRing::unregisterSignalHandlers(); JAMI_DBG("%zu account announced!", to_be_announced); } void wait_for_announcement_of(const std::string& accountId, std::chrono::seconds timeout) { wait_for_announcement_of(std::vector {accountId}, timeout); } void wait_for_removal_of(const std::vector accounts, std::chrono::seconds timeout) { JAMI_INFO("Removing %zu accounts...", accounts.size()); std::map> confHandlers; std::mutex mtx; std::unique_lock lk {mtx}; std::condition_variable cv; std::atomic_bool accountsRemoved {false}; size_t current = jami::Manager::instance().getAccountList().size(); /* Prevent overflow */ CPPUNIT_ASSERT(current >= accounts.size()); size_t target = current - accounts.size(); confHandlers.insert( DRing::exportable_callback([&]() { if (jami::Manager::instance().getAccountList().size() <= target) { accountsRemoved = true; cv.notify_one(); } })); DRing::unregisterSignalHandlers(); DRing::registerSignalHandlers(confHandlers); for (const auto& account : accounts) { jami::Manager::instance().removeAccount(account, true); } CPPUNIT_ASSERT(cv.wait_for(lk, timeout, [&] { return accountsRemoved.load(); })); DRing::unregisterSignalHandlers(); } void wait_for_removal_of(const std::string& account, std::chrono::seconds timeout) { wait_for_removal_of(std::vector{account}, timeout); } std::map load_actors(const std::string& from_yaml) { std::map actors {}; std::map default_details = DRing::getAccountTemplate("RING"); std::ifstream file = jami::fileutils::ifstream(from_yaml); CPPUNIT_ASSERT(file.is_open()); YAML::Node node = YAML::Load(file); CPPUNIT_ASSERT(node.IsMap()); auto default_account = node["default-account"]; if (default_account.IsMap()) { for (const auto& kv : default_account) { default_details["Account." + kv.first.as()] = kv.second.as(); } } auto accounts = node["accounts"]; CPPUNIT_ASSERT(accounts.IsMap()); for (const auto& kv : accounts) { auto account_name = kv.first.as(); auto account = kv.second.as(); auto details = std::map(default_details); for (const auto& detail : account) { details["Account." + detail.first.as()] = detail.second.as(); } actors[account_name] = jami::Manager::instance().addAccount(details); } return actors; } std::map load_actors_and_wait_for_announcement(const std::string& from_yaml) { auto actors = load_actors(from_yaml); std::vector wait_for; wait_for.reserve(actors.size()); for (auto it = actors.cbegin(); it != actors.cend(); ++it) { wait_for.emplace_back(it->second); } wait_for_announcement_of(wait_for); return actors; } #pragma GCC diagnostic pop