diff --git a/test/unitTest/Makefile.am b/test/unitTest/Makefile.am index 9ca3e778e398346fd5ba51b3b572b6d5b4926cce..fe69fa2b54207d24244cfe184954a5c686f7fbb9 100644 --- a/test/unitTest/Makefile.am +++ b/test/unitTest/Makefile.am @@ -133,6 +133,12 @@ ut_audio_frame_resizer_SOURCES = media/audio/test_audio_frame_resizer.cpp common check_PROGRAMS += ut_call ut_call_SOURCES = call/call.cpp common.cpp +# +# SIPcall +# +check_PROGRAMS += ut_sipcall +ut_sipcall_SOURCES = call/sipcall.cpp common.cpp + # # recorder # diff --git a/test/unitTest/actors/alice-bob_SIP.yml b/test/unitTest/actors/alice-bob_SIP.yml new file mode 100644 index 0000000000000000000000000000000000000000..9dc629e2b7e9c02cc20c769b1a5fd4693714e839 --- /dev/null +++ b/test/unitTest/actors/alice-bob_SIP.yml @@ -0,0 +1,19 @@ +default-account: + type: SIP + upnpEnabled: "true" + SRTP.keyExchange: "none" + +accounts: + alice: + displayName: ALICE + alias: ALICE + hostname: X.X.X.X + username: YYY + password: ZZZ + + bob: + displayName: BOB + alias: BOB + hostname: X.X.X.X + username: AAA + password: BBB diff --git a/test/unitTest/call/sipcall.cpp b/test/unitTest/call/sipcall.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a971fa5328f1fda0798e10b9de0f4ad82d6e484 --- /dev/null +++ b/test/unitTest/call/sipcall.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2024 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, see <https://www.gnu.org/licenses/>. + */ + +#include "manager.h" +#include "sip/sipaccount.h" +#include "sip/sipcall.h" +#include "sip/siptransport.h" +#include "../../test_runner.h" +#include "jami.h" +#include "account_const.h" +#include "media_const.h" +#include "call_const.h" +#include "common.h" + +#include <dhtnet/connectionmanager.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <condition_variable> +#include <filesystem> +#include <string> + +using namespace libjami::Account; +using namespace libjami::Call::Details; +using namespace std::literals::chrono_literals; + +namespace jami { +namespace test { + +class SIPCallTest : public CppUnit::TestFixture +{ +public: + SIPCallTest() + { + // Init daemon + libjami::init( + libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG)); + if (not Manager::instance().initialized) + CPPUNIT_ASSERT(libjami::start("jami-sample.yml")); + } + ~SIPCallTest() { libjami::fini(); } + static std::string name() { return "Call"; } + void setUp(); + void tearDown(); + + std::string aliceId; + std::string bobId; + +private: + void testCall(); + + CPPUNIT_TEST_SUITE(SIPCallTest); + CPPUNIT_TEST(testCall); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(SIPCallTest, SIPCallTest::name()); + +void +SIPCallTest::setUp() +{ + auto actors = load_actors_and_wait_for_announcement("actors/alice-bob_SIP.yml"); + aliceId = actors["alice"]; + bobId = actors["bob"]; + std::this_thread::sleep_for(10s); +} + +void +SIPCallTest::tearDown() +{ + wait_for_removal_of({aliceId, bobId}); +} + +void +SIPCallTest::testCall() +{ + auto aliceAccount = Manager::instance().getAccount<SIPAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<SIPAccount>(bobId); + auto bobUri = bobAccount->getUsername(); + JAMI_ERROR("@@@@@@@@@22 {}", bobUri); + auto aliceUri = aliceAccount->getUsername(); + + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + std::atomic_bool callReceived {false}; + std::atomic<int> callStopped {0}; + // Watch signals + confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>( + [&](const std::string&, + const std::string&, + const std::string&, + const std::vector<std::map<std::string, std::string>>&) { + callReceived = true; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>( + [&](const std::string&, const std::string&, const std::string& state, signed) { + if (state == "OVER") { + callStopped += 1; + if (callStopped == 2) + cv.notify_one(); + } + })); + libjami::registerSignalHandlers(confHandlers); + + JAMI_INFO("Start call between alice and Bob"); + std::vector<std::map<std::string, std::string>> mediaList; + std::map<std::string, std::string> mediaAttribute + = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, + libjami::Media::MediaAttributeValue::AUDIO}, + {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR}, + {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR}, + {libjami::Media::MediaAttributeKey::SOURCE, ""}, + {libjami::Media::MediaAttributeKey::LABEL, "audio_0"}}; + mediaList.emplace_back(mediaAttribute); + + auto call = libjami::placeCallWithMedia(aliceId, bobUri, mediaList); + + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callReceived.load(); })); + + JAMI_INFO("Stop call between alice and Bob"); + callStopped = 0; + Manager::instance().hangupCall(aliceId, call); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; })); +} + +} // namespace test +} // namespace jami + +RING_TEST_RUNNER(jami::test::SIPCallTest::name()) diff --git a/test/unitTest/common.cpp b/test/unitTest/common.cpp index 181f2f3cf45e30e62f7592430ed18d50cfae494b..ab3aea681ca62dc6435b283544dc68c59bb7909a 100644 --- a/test/unitTest/common.cpp +++ b/test/unitTest/common.cpp @@ -58,13 +58,20 @@ wait_for_announcement_of(const std::vector<std::string> accountIDs, continue; } - try { - if ("true" - != details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED)) { + if (jami::Manager::instance().getAccount(accountID)->getAccountType() == "SIP") { + auto daemonStatus = details.at(libjami::Account::ConfProperties::Registration::STATUS); + if (daemonStatus != "REGISTERED") { + continue; + } + } else { + try { + if ("true" + != details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED)) { + continue; + } + } catch (const std::out_of_range&) { continue; } - } catch (const std::out_of_range&) { - continue; } accountsReady[i] = true; @@ -148,7 +155,6 @@ std::map<std::string, std::string> load_actors(const std::filesystem::path& from_yaml) { std::map<std::string, std::string> actors {}; - std::map<std::string, std::string> default_details = libjami::getAccountTemplate("RING"); std::ifstream file(from_yaml); @@ -160,9 +166,15 @@ load_actors(const std::filesystem::path& from_yaml) auto default_account = node["default-account"]; + std::map<std::string, std::string> default_details = libjami::getAccountTemplate(default_account["type"].as<std::string>()); if (default_account.IsMap()) { for (const auto& kv : default_account) { - default_details["Account." + kv.first.as<std::string>()] = kv.second.as<std::string>(); + auto key = kv.first.as<std::string>(); + if (default_details.find(key) != default_details.end()) { + default_details[key] = kv.second.as<std::string>(); + } else { + default_details["Account." + key] = kv.second.as<std::string>(); + } } } @@ -176,7 +188,12 @@ load_actors(const std::filesystem::path& from_yaml) auto details = std::map<std::string, std::string>(default_details); for (const auto& detail : account) { - details["Account." + detail.first.as<std::string>()] = detail.second.as<std::string>(); + auto key = detail.first.as<std::string>(); + if (details.find(key) != details.end()) { + details[key] = detail.second.as<std::string>(); + } else { + details["Account." + key] = detail.second.as<std::string>(); + } } actors[account_name] = jami::Manager::instance().addAccount(details);