Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 : */ 17 : 18 : #include <cppunit/TestAssert.h> 19 : #include <cppunit/TestFixture.h> 20 : #include <cppunit/extensions/HelperMacros.h> 21 : 22 : #include <yaml-cpp/yaml.h> 23 : 24 : #include "common.h" 25 : 26 : /* Jami */ 27 : #include "account_const.h" 28 : #include "jami.h" 29 : #include "fileutils.h" 30 : #include "manager.h" 31 : 32 : /* Make GCC quiet about unused functions */ 33 : #pragma GCC diagnostic push 34 : #pragma GCC diagnostic ignored "-Wunused-function" 35 : 36 : void 37 265 : wait_for_announcement_of(const std::vector<std::string> accountIDs, 38 : std::chrono::seconds timeout) 39 : { 40 265 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; 41 265 : std::mutex mtx; 42 265 : std::unique_lock lk {mtx}; 43 265 : std::condition_variable cv; 44 265 : std::vector<std::atomic_bool> accountsReady(accountIDs.size()); 45 : 46 265 : size_t to_be_announced = accountIDs.size(); 47 : 48 265 : confHandlers.insert( 49 530 : libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( 50 2554 : [&, 51 265 : accountIDs = std::move(accountIDs)](const std::string& accountID, 52 : const std::map<std::string, std::string>& details) { 53 11077 : for (size_t i = 0; i < accountIDs.size(); ++i) { 54 8523 : if (accountIDs[i] != accountID) { 55 6111 : continue; 56 : } 57 : 58 2412 : if (jami::Manager::instance().getAccount(accountID)->getAccountType() == "SIP") { 59 4 : auto daemonStatus = details.at(libjami::Account::ConfProperties::Registration::STATUS); 60 2 : if (daemonStatus != "REGISTERED") { 61 0 : continue; 62 : } 63 2 : } else { 64 : try { 65 4217 : if ("true" 66 2410 : != details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED)) { 67 1807 : continue; 68 : } 69 0 : } catch (const std::out_of_range&) { 70 0 : continue; 71 0 : } 72 : } 73 : 74 605 : accountsReady[i] = true; 75 605 : cv.notify_one(); 76 : } 77 2554 : })); 78 : 79 265 : JAMI_DBG("Waiting for %zu account to be announced...", to_be_announced); 80 : 81 265 : libjami::registerSignalHandlers(confHandlers); 82 : 83 1991 : CPPUNIT_ASSERT(cv.wait_for(lk, timeout, [&] { 84 : for (const auto& rdy : accountsReady) { 85 : if (not rdy) { 86 : return false; 87 : } 88 : } 89 : 90 : return true; 91 : })); 92 : 93 265 : libjami::unregisterSignalHandlers(); 94 : 95 265 : JAMI_DBG("%zu account announced!", to_be_announced); 96 265 : } 97 : 98 : void 99 8 : wait_for_announcement_of(const std::string& accountId, 100 : std::chrono::seconds timeout) 101 : { 102 16 : wait_for_announcement_of(std::vector<std::string> {accountId}, timeout); 103 8 : } 104 : 105 : void 106 267 : wait_for_removal_of(const std::vector<std::string> accounts, 107 : std::chrono::seconds timeout) 108 : { 109 267 : JAMI_INFO("Removing %zu accounts...", accounts.size()); 110 : 111 267 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; 112 267 : std::mutex mtx; 113 267 : std::unique_lock lk {mtx}; 114 267 : std::condition_variable cv; 115 267 : std::atomic_bool accountsRemoved {false}; 116 : 117 267 : size_t current = jami::Manager::instance().getAccountList().size(); 118 : 119 : /* Prevent overflow */ 120 267 : CPPUNIT_ASSERT(current >= accounts.size()); 121 : 122 267 : size_t target = current - accounts.size(); 123 : 124 267 : confHandlers.insert( 125 534 : libjami::exportable_callback<libjami::ConfigurationSignal::AccountsChanged>([&]() { 126 784 : if (jami::Manager::instance().getAccountList().size() <= target) { 127 267 : accountsRemoved = true; 128 267 : cv.notify_one(); 129 : } 130 784 : })); 131 : 132 267 : libjami::unregisterSignalHandlers(); 133 267 : libjami::registerSignalHandlers(confHandlers); 134 : 135 1051 : for (const auto& account : accounts) { 136 784 : jami::Manager::instance().removeAccount(account, true); 137 : } 138 : 139 534 : CPPUNIT_ASSERT(cv.wait_for(lk, timeout, [&] { return accountsRemoved.load(); })); 140 : 141 267 : libjami::unregisterSignalHandlers(); 142 267 : } 143 : 144 : void 145 14 : wait_for_removal_of(const std::string& account, 146 : std::chrono::seconds timeout) 147 : { 148 28 : wait_for_removal_of(std::vector<std::string>{account}, timeout); 149 14 : } 150 : 151 : std::map<std::string, std::string> 152 258 : load_actors(const std::filesystem::path& from_yaml) 153 : { 154 258 : std::map<std::string, std::string> actors {}; 155 : 156 258 : std::ifstream file(from_yaml); 157 : 158 258 : CPPUNIT_ASSERT(file.is_open()); 159 : 160 258 : YAML::Node node = YAML::Load(file); 161 : 162 258 : CPPUNIT_ASSERT(node.IsMap()); 163 : 164 258 : auto default_account = node["default-account"]; 165 : 166 516 : std::map<std::string, std::string> default_details = libjami::getAccountTemplate(default_account["type"].as<std::string>()); 167 258 : if (default_account.IsMap()) { 168 1546 : for (const auto& kv : default_account) { 169 1288 : auto key = kv.first.as<std::string>(); 170 1288 : if (default_details.find(key) != default_details.end()) { 171 1 : default_details[key] = kv.second.as<std::string>(); 172 : } else { 173 1287 : default_details["Account." + key] = kv.second.as<std::string>(); 174 : } 175 1546 : } 176 : } 177 : 178 258 : auto accounts = node["accounts"]; 179 : 180 258 : CPPUNIT_ASSERT(accounts.IsMap()); 181 : 182 998 : for (const auto& kv : accounts) { 183 740 : auto account_name = kv.first.as<std::string>(); 184 740 : auto account = kv.second.as<YAML::Node>(); 185 740 : auto details = std::map<std::string, std::string>(default_details); 186 : 187 2236 : for (const auto& detail : account) { 188 1496 : auto key = detail.first.as<std::string>(); 189 1496 : if (details.find(key) != details.end()) { 190 0 : details[key] = detail.second.as<std::string>(); 191 : } else { 192 1496 : details["Account." + key] = detail.second.as<std::string>(); 193 : } 194 2236 : } 195 : 196 740 : actors[account_name] = jami::Manager::instance().addAccount(details); 197 998 : } 198 : 199 516 : return actors; 200 258 : } 201 : 202 : std::map<std::string, std::string> 203 97 : load_actors_and_wait_for_announcement(const std::string& from_yaml) 204 : { 205 97 : auto actors = load_actors(from_yaml); 206 : 207 97 : std::vector<std::string> wait_for; 208 : 209 97 : wait_for.reserve(actors.size()); 210 : 211 350 : for (auto it = actors.cbegin(); it != actors.cend(); ++it) { 212 253 : wait_for.emplace_back(it->second); 213 : } 214 : 215 97 : wait_for_announcement_of(wait_for); 216 : 217 194 : return actors; 218 97 : } 219 : 220 : #pragma GCC diagnostic pop