LCOV - code coverage report
Current view: top level - test/unitTest/call - call.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 400 412 97.1 %
Date: 2024-11-15 09:04:49 Functions: 59 61 96.7 %

          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 "manager.h"
      19             : #include "jamidht/jamiaccount.h"
      20             : #include "sip/sipcall.h"
      21             : #include "sip/siptransport.h"
      22             : #include "../../test_runner.h"
      23             : #include "jami.h"
      24             : #include "account_const.h"
      25             : #include "account_schema.h"
      26             : #include "media_const.h"
      27             : #include "call_const.h"
      28             : #include "common.h"
      29             : 
      30             : #include <dhtnet/connectionmanager.h>
      31             : 
      32             : #include <cppunit/TestAssert.h>
      33             : #include <cppunit/TestFixture.h>
      34             : #include <cppunit/extensions/HelperMacros.h>
      35             : 
      36             : #include <condition_variable>
      37             : #include <filesystem>
      38             : #include <string>
      39             : 
      40             : using namespace libjami::Account;
      41             : using namespace libjami::Call::Details;
      42             : using namespace std::literals::chrono_literals;
      43             : namespace jami {
      44             : namespace test {
      45             : 
      46             : class CallTest : public CppUnit::TestFixture
      47             : {
      48             : public:
      49           9 :     CallTest()
      50           9 :     {
      51             :         // Init daemon
      52           9 :         libjami::init(
      53             :             libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
      54           9 :         if (not Manager::instance().initialized)
      55           1 :             CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
      56           9 :     }
      57          18 :     ~CallTest() { libjami::fini(); }
      58           2 :     static std::string name() { return "Call"; }
      59             :     void setUp();
      60             :     void tearDown();
      61             : 
      62             :     std::string aliceId;
      63             :     std::string bobId;
      64             :     std::string bob2Id;
      65             :     std::string carlaId;
      66             : 
      67             : private:
      68             :     void testCall();
      69             :     void testCachedCall();
      70             :     void testStopSearching();
      71             :     void testDeclineMultiDevice();
      72             :     void testTlsInfosPeerCertificate();
      73             :     void testSocketInfos();
      74             :     void testInvalidTurn();
      75             :     void testTransfer();
      76             :     void testDhtPublicInCall();
      77             : 
      78           2 :     CPPUNIT_TEST_SUITE(CallTest);
      79           1 :     CPPUNIT_TEST(testCall);
      80           1 :     CPPUNIT_TEST(testCachedCall);
      81           1 :     CPPUNIT_TEST(testStopSearching);
      82           1 :     CPPUNIT_TEST(testDeclineMultiDevice);
      83           1 :     CPPUNIT_TEST(testTlsInfosPeerCertificate);
      84           1 :     CPPUNIT_TEST(testSocketInfos);
      85           1 :     CPPUNIT_TEST(testInvalidTurn);
      86           1 :     CPPUNIT_TEST(testTransfer);
      87           1 :     CPPUNIT_TEST(testDhtPublicInCall);
      88           4 :     CPPUNIT_TEST_SUITE_END();
      89             : };
      90             : 
      91             : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CallTest, CallTest::name());
      92             : 
      93             : void
      94           9 : CallTest::setUp()
      95             : {
      96          18 :     auto actors = load_actors_and_wait_for_announcement("actors/alice-bob-carla.yml");
      97           9 :     aliceId = actors["alice"];
      98           9 :     bobId = actors["bob"];
      99           9 :     carlaId = actors["carla"];
     100           9 : }
     101             : 
     102             : void
     103           9 : CallTest::tearDown()
     104             : {
     105          18 :     auto bobArchive = std::filesystem::current_path().string() + "/bob.gz";
     106           9 :     std::remove(bobArchive.c_str());
     107             : 
     108           9 :     if (bob2Id.empty()) {
     109          32 :         wait_for_removal_of({aliceId, bobId, carlaId});
     110             :     } else {
     111           5 :         wait_for_removal_of({aliceId, bobId, carlaId, bob2Id});
     112             :     }
     113           9 : }
     114             : 
     115             : void
     116           1 : CallTest::testCall()
     117             : {
     118           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     119           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     120           1 :     auto bobUri = bobAccount->getUsername();
     121           1 :     auto aliceUri = aliceAccount->getUsername();
     122             : 
     123           1 :     std::mutex mtx;
     124           1 :     std::unique_lock lk {mtx};
     125           1 :     std::condition_variable cv;
     126           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     127           1 :     std::atomic_bool callReceived {false};
     128           1 :     std::atomic<int> callStopped {0};
     129             :     // Watch signals
     130           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     131           1 :         [&](const std::string&,
     132             :             const std::string&,
     133             :             const std::string&,
     134             :             const std::vector<std::map<std::string, std::string>>&) {
     135           1 :             callReceived = true;
     136           1 :             cv.notify_one();
     137           1 :         }));
     138           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     139           8 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     140           8 :             if (state == "OVER") {
     141           2 :                 callStopped += 1;
     142           2 :                 if (callStopped == 2)
     143           1 :                     cv.notify_one();
     144             :             }
     145           8 :         }));
     146           1 :     libjami::registerSignalHandlers(confHandlers);
     147             : 
     148           1 :     JAMI_INFO("Start call between alice and Bob");
     149           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     150             : 
     151           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callReceived.load(); }));
     152             : 
     153           1 :     JAMI_INFO("Stop call between alice and Bob");
     154           1 :     callStopped = 0;
     155           1 :     Manager::instance().hangupCall(aliceId, call);
     156           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; }));
     157           1 : }
     158             : 
     159             : void
     160           1 : CallTest::testCachedCall()
     161             : {
     162           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     163           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     164           1 :     auto bobUri = bobAccount->getUsername();
     165           1 :     auto bobDeviceId = DeviceId(std::string(bobAccount->currentDeviceId()));
     166           1 :     auto aliceUri = aliceAccount->getUsername();
     167             : 
     168             :     // Pin certificate from one to another certstore (because we do not perform any DHT operation in this test)
     169           1 :     bobAccount->certStore().pinCertificate(aliceAccount->identity().second);
     170           1 :     aliceAccount->certStore().pinCertificate(bobAccount->identity().second);
     171             : 
     172           1 :     std::mutex mtx;
     173           1 :     std::unique_lock lk {mtx};
     174           1 :     std::condition_variable cv;
     175           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     176           1 :     std::atomic_bool callReceived {false}, successfullyConnected {false};
     177           1 :     std::atomic<int> callStopped {0};
     178             :     // Watch signals
     179           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     180           1 :         [&](const std::string&,
     181             :             const std::string&,
     182             :             const std::string&,
     183             :             const std::vector<std::map<std::string, std::string>>&) {
     184           1 :             callReceived = true;
     185           1 :             cv.notify_one();
     186           1 :         }));
     187           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     188           8 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     189           8 :             if (state == "OVER") {
     190           2 :                 callStopped += 1;
     191           2 :                 if (callStopped == 2)
     192           1 :                     cv.notify_one();
     193             :             }
     194           8 :         }));
     195           1 :     libjami::registerSignalHandlers(confHandlers);
     196             : 
     197           1 :     JAMI_INFO("Connect Alice's device and Bob's device");
     198           1 :     aliceAccount->connectionManager()
     199           1 :         .connectDevice(bobDeviceId,
     200             :                        "sip",
     201           1 :                        [&cv, &successfullyConnected](std::shared_ptr<dhtnet::ChannelSocket> socket,
     202           2 :                                                      const DeviceId&) {
     203           1 :                            if (socket)
     204           1 :                                successfullyConnected = true;
     205           1 :                            cv.notify_one();
     206           1 :                        });
     207           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return successfullyConnected.load(); }));
     208             : 
     209           1 :     JAMI_INFO("Start call between alice and Bob");
     210           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     211           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callReceived.load(); }));
     212             : 
     213           1 :     callStopped = 0;
     214           1 :     JAMI_INFO("Stop call between alice and Bob");
     215           1 :     Manager::instance().hangupCall(aliceId, call);
     216           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; }));
     217           1 : }
     218             : 
     219             : void
     220           1 : CallTest::testStopSearching()
     221             : {
     222           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     223           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     224           1 :     auto bobUri = bobAccount->getUsername();
     225           1 :     auto aliceUri = aliceAccount->getUsername();
     226             : 
     227           1 :     Manager::instance().sendRegister(bobId, false);
     228             : 
     229           1 :     std::mutex mtx;
     230           1 :     std::unique_lock lk {mtx};
     231           1 :     std::condition_variable cv;
     232           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     233           1 :     std::atomic_bool callStopped {false};
     234             :     // Watch signals
     235           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     236           2 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     237           2 :             if (state == "OVER") {
     238           1 :                 callStopped = true;
     239           1 :                 cv.notify_one();
     240             :             }
     241           2 :         }));
     242           1 :     libjami::registerSignalHandlers(confHandlers);
     243             : 
     244           1 :     JAMI_INFO("Start call between alice and Bob");
     245           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     246             : 
     247             :     // Bob not there, so we should get a SEARCHING STATUS
     248           1 :     JAMI_INFO("Wait OVER state");
     249             :     // Then wait for the DHT no answer. this can take some times
     250           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&] { return callStopped.load(); }));
     251           1 : }
     252             : 
     253             : void
     254           1 : CallTest::testDeclineMultiDevice()
     255             : {
     256           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     257           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     258           1 :     auto bobUri = bobAccount->getUsername();
     259           1 :     auto aliceUri = aliceAccount->getUsername();
     260           1 :     std::mutex mtx;
     261           1 :     std::unique_lock lk {mtx};
     262           1 :     std::condition_variable cv;
     263             : 
     264             :     // Add second device for Bob
     265           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     266           2 :     auto bobArchive = std::filesystem::current_path().string() + "/bob.gz";
     267           1 :     std::remove(bobArchive.c_str());
     268           1 :     bobAccount->exportArchive(bobArchive);
     269             : 
     270           2 :     std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
     271           1 :     details[ConfProperties::TYPE] = "RING";
     272           1 :     details[ConfProperties::DISPLAYNAME] = "BOB2";
     273           1 :     details[ConfProperties::ALIAS] = "BOB2";
     274           1 :     details[ConfProperties::UPNP_ENABLED] = "true";
     275           1 :     details[ConfProperties::ARCHIVE_PASSWORD] = "";
     276           1 :     details[ConfProperties::ARCHIVE_PIN] = "";
     277           1 :     details[ConfProperties::ARCHIVE_PATH] = bobArchive;
     278             : 
     279           1 :     bob2Id = Manager::instance().addAccount(details);
     280             : 
     281           1 :     wait_for_announcement_of(bob2Id);
     282             : 
     283           1 :     std::atomic<int> callReceived {0};
     284           1 :     std::atomic<int> callStopped {0};
     285           1 :     std::string callIdBob;
     286             :     // Watch signals
     287           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     288           2 :         [&](const std::string& accountId,
     289             :             const std::string& callId,
     290             :             const std::string&,
     291             :             const std::vector<std::map<std::string, std::string>>&) {
     292           2 :             if (accountId == bobId)
     293           1 :                 callIdBob = callId;
     294           2 :             callReceived += 1;
     295           2 :             cv.notify_one();
     296           2 :         }));
     297           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     298          14 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     299          14 :             if (state == "OVER")
     300           3 :                 callStopped++;
     301          14 :             cv.notify_one();
     302          14 :         }));
     303           1 :     libjami::registerSignalHandlers(confHandlers);
     304             : 
     305           1 :     JAMI_INFO("Start call between alice and Bob");
     306           1 :     auto bobAccount2 = Manager::instance().getAccount<JamiAccount>(bob2Id);
     307             : 
     308           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     309             : 
     310          11 :     CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return callReceived == 2 && !callIdBob.empty(); }));
     311             : 
     312           1 :     JAMI_INFO("Stop call between alice and Bob");
     313           1 :     callStopped = 0;
     314           1 :     Manager::instance().refuseCall(bobId, callIdBob);
     315          11 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] {
     316             :         return callStopped.load() >= 3; /* >= because there is subcalls */
     317             :     }));
     318           1 : }
     319             : 
     320             : void
     321           1 : CallTest::testTlsInfosPeerCertificate()
     322             : {
     323           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     324           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     325           1 :     auto bobUri = bobAccount->getUsername();
     326           1 :     auto aliceUri = aliceAccount->getUsername();
     327             : 
     328           1 :     std::mutex mtx;
     329           1 :     std::unique_lock lk {mtx};
     330           1 :     std::condition_variable cv;
     331           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     332           1 :     std::atomic<int> callStopped {0};
     333           1 :     std::string bobCallId;
     334           1 :     std::string aliceCallState;
     335             :     // Watch signals
     336           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     337           1 :         [&](const std::string& accountId,
     338             :             const std::string& callId,
     339             :             const std::string&,
     340             :             const std::vector<std::map<std::string, std::string>>&) {
     341           1 :             if (accountId == bobId)
     342           1 :                 bobCallId = callId;
     343           1 :             cv.notify_one();
     344           1 :         }));
     345           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     346          11 :         [&](const std::string& accountId, const std::string&, const std::string& state, signed) {
     347          11 :             if (accountId == aliceId)
     348           5 :                 aliceCallState = state;
     349          11 :             if (state == "OVER") {
     350           2 :                 callStopped += 1;
     351           2 :                 if (callStopped == 2)
     352           1 :                     cv.notify_one();
     353             :             }
     354          11 :         }));
     355           1 :     libjami::registerSignalHandlers(confHandlers);
     356             : 
     357           1 :     JAMI_INFO("Start call between alice and Bob");
     358           1 :     auto callId = libjami::placeCallWithMedia(aliceId, bobUri, {});
     359             : 
     360           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !bobCallId.empty(); }));
     361             : 
     362           1 :     Manager::instance().answerCall(bobId, bobCallId);
     363           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceCallState == "CURRENT"; }));
     364             : 
     365           1 :     auto call = std::dynamic_pointer_cast<SIPCall>(aliceAccount->getCall(callId));
     366           1 :     auto* transport = call->getTransport();
     367           1 :     CPPUNIT_ASSERT(transport);
     368           1 :     auto cert = transport->getTlsInfos().peerCert;
     369           1 :     CPPUNIT_ASSERT(cert && cert->issuer);
     370           1 :     CPPUNIT_ASSERT(cert->issuer->getId().toString() == bobAccount->getUsername());
     371             : 
     372           1 :     JAMI_INFO("Stop call between alice and Bob");
     373           1 :     callStopped = 0;
     374           1 :     Manager::instance().hangupCall(aliceId, callId);
     375           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; }));
     376           1 : }
     377             : 
     378             : void
     379           1 : CallTest::testSocketInfos()
     380             : {
     381           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     382           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     383           1 :     auto bobUri = bobAccount->getUsername();
     384           1 :     auto aliceUri = aliceAccount->getUsername();
     385             : 
     386           1 :     std::mutex mtx;
     387           1 :     std::unique_lock lk {mtx};
     388           1 :     std::condition_variable cv;
     389           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     390           1 :     std::atomic<int> callStopped {0};
     391           1 :     std::string bobCallId;
     392           1 :     std::string aliceCallState;
     393             :     // Watch signals
     394           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     395           1 :         [&](const std::string& accountId,
     396             :             const std::string& callId,
     397             :             const std::string&,
     398             :             const std::vector<std::map<std::string, std::string>>&) {
     399           1 :             if (accountId == bobId)
     400           1 :                 bobCallId = callId;
     401           1 :             cv.notify_one();
     402           1 :         }));
     403           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     404          11 :         [&](const std::string& accountId, const std::string&, const std::string& state, signed) {
     405          11 :             if (accountId == aliceId)
     406           5 :                 aliceCallState = state;
     407          11 :             if (state == "OVER") {
     408           2 :                 callStopped += 1;
     409           2 :                 if (callStopped == 2)
     410           1 :                     cv.notify_one();
     411             :             }
     412          11 :         }));
     413           1 :     auto mediaReady = false;
     414           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::MediaNegotiationStatus>(
     415           2 :         [&](const std::string& callId,
     416             :             const std::string& event,
     417             :             const std::vector<std::map<std::string, std::string>>&) {
     418           2 :             if (event == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS) {
     419           2 :                 mediaReady = true;
     420           2 :                 cv.notify_one();
     421             :             }
     422           2 :         }));
     423           1 :     libjami::registerSignalHandlers(confHandlers);
     424             : 
     425           1 :     JAMI_INFO("Start call between alice and Bob");
     426           1 :     auto callId = libjami::placeCallWithMedia(aliceId, bobUri, {});
     427             : 
     428           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !bobCallId.empty(); }));
     429             : 
     430           1 :     Manager::instance().answerCall(bobId, bobCallId);
     431           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceCallState == "CURRENT" && mediaReady; }));
     432             : 
     433           1 :     JAMI_INFO("Detail debug");
     434           1 :     auto details = libjami::getCallDetails(aliceId, callId);
     435          21 :     for (auto i = details.begin(); i != details.end(); i++) {
     436          20 :         JAMI_INFO("%s : %s", i->first.c_str(), i->second.c_str());
     437             :     }
     438           1 :     auto call = std::dynamic_pointer_cast<SIPCall>(aliceAccount->getCall(callId));
     439           1 :     auto transport = call->getIceMedia();
     440           1 :     CPPUNIT_ASSERT(transport);
     441           1 :     CPPUNIT_ASSERT(transport->isRunning());
     442           1 :     CPPUNIT_ASSERT(transport->link().c_str() == details[libjami::Call::Details::SOCKETS]);
     443             : 
     444           1 :     JAMI_INFO("Stop call between alice and Bob");
     445           1 :     callStopped = 0;
     446           1 :     Manager::instance().hangupCall(aliceId, callId);
     447           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; }));
     448           1 : }
     449             : 
     450             : void
     451           1 : CallTest::testInvalidTurn()
     452             : {
     453           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     454           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     455           1 :     auto bobUri = bobAccount->getUsername();
     456           1 :     auto aliceUri = aliceAccount->getUsername();
     457             : 
     458           1 :     std::mutex mtx;
     459           1 :     std::unique_lock lk {mtx};
     460           1 :     std::condition_variable cv;
     461           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     462           1 :     std::atomic_bool callReceived {false};
     463           1 :     std::atomic<int> callStopped {0};
     464           1 :     bool aliceReady = false;
     465             :     // Watch signals
     466           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     467           1 :         [&](const std::string&,
     468             :             const std::string&,
     469             :             const std::string&,
     470             :             const std::vector<std::map<std::string, std::string>>&) {
     471           1 :             callReceived = true;
     472           1 :             cv.notify_one();
     473           1 :         }));
     474           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     475           8 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     476           8 :             if (state == "OVER") {
     477           2 :                 callStopped += 1;
     478           2 :                 if (callStopped == 2)
     479           1 :                     cv.notify_one();
     480             :             }
     481           8 :         }));
     482           1 :     confHandlers.insert(
     483           2 :         libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>(
     484           4 :             [&](const std::string& accountId,
     485             :                 const std::map<std::string, std::string>& details) {
     486           4 :                 if (accountId != aliceId) {
     487           0 :                     return;
     488             :                 }
     489             :                 try {
     490           8 :                     aliceReady |= accountId == aliceId
     491           8 :                                 && details.at(jami::Conf::CONFIG_ACCOUNT_REGISTRATION_STATUS) == "REGISTERED"
     492           8 :                                 && details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) == "true";
     493           0 :                 } catch (const std::out_of_range&) {}
     494           4 :                 cv.notify_one();
     495             :             }));
     496           1 :     libjami::registerSignalHandlers(confHandlers);
     497             : 
     498           1 :     std::map<std::string, std::string> details;
     499           1 :     details[ConfProperties::TURN::SERVER] = "1.1.1.1";
     500           1 :     aliceReady = false;
     501           1 :     libjami::setAccountDetails(aliceId, details);
     502           4 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceReady; }));
     503             : 
     504           1 :     JAMI_INFO("Start call between alice and Bob");
     505           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     506             : 
     507           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return callReceived.load(); }));
     508             : 
     509           1 :     JAMI_INFO("Stop call between alice and Bob");
     510           1 :     callStopped = 0;
     511           1 :     Manager::instance().hangupCall(aliceId, call);
     512           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return callStopped == 2; }));
     513           1 : }
     514             : 
     515             : void
     516           1 : CallTest::testTransfer()
     517             : {
     518             :     // Alice call Bob
     519             :     // Bob transfer to Carla
     520             : 
     521           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     522           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     523           1 :     auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId);
     524           1 :     auto carlaUri = carlaAccount->getUsername();
     525           1 :     auto bobUri = bobAccount->getUsername();
     526           1 :     auto aliceUri = aliceAccount->getUsername();
     527             : 
     528           1 :     std::mutex mtx;
     529           1 :     std::unique_lock lk {mtx};
     530           1 :     std::condition_variable cv;
     531           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     532           1 :     std::atomic_bool bobCallReceived {false};
     533           1 :     std::atomic_bool carlaCallReceived {false};
     534           1 :     std::atomic<int> bobCallStopped {0};
     535           1 :     std::atomic<int> aliceCallStopped {0};
     536           1 :     std::string bobCallId;
     537           1 :     std::string carlaCallId;
     538           1 :     std::string carlaCallPeer;
     539             :     // Watch signals
     540           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     541           2 :         [&](const std::string& accountId,
     542             :             const std::string& callId,
     543             :             const std::string& peerId,
     544             :             const std::vector<std::map<std::string, std::string>>&) {
     545           2 :             if (accountId == bobId) {
     546           1 :                 bobCallReceived = true;
     547           1 :                 bobCallId = callId;
     548           1 :             } else if (accountId == carlaId) {
     549           1 :                 carlaCallReceived = true;
     550           1 :                 carlaCallId = callId;
     551           1 :                 carlaCallPeer = peerId;
     552           1 :                 string_replace(carlaCallPeer, "@ring.dht", "");
     553             :             }
     554           2 :             cv.notify_one();
     555           2 :         }));
     556           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     557          18 :         [&](const std::string& accountId, const std::string&, const std::string& state, signed) {
     558          18 :             if (state == "OVER") {
     559           4 :                 if (accountId == bobId) {
     560           1 :                     bobCallStopped += 1;
     561           1 :                     cv.notify_one();
     562             :                 }
     563           4 :                 if (accountId == aliceId) {
     564           2 :                     aliceCallStopped += 1;
     565           2 :                     cv.notify_one();
     566             :                 }
     567             :             }
     568          18 :         }));
     569           1 :     libjami::registerSignalHandlers(confHandlers);
     570             : 
     571           1 :     JAMI_INFO("Start call between alice and Bob");
     572           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     573             : 
     574           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return bobCallReceived.load(); }));
     575             : 
     576           1 :     JAMI_INFO("Bob transfer to Carla");
     577           1 :     libjami::transfer(bobId, bobCallId, carlaUri);
     578             : 
     579           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return bobCallStopped.load(); }));
     580           4 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaCallReceived.load(); }));
     581           1 :     CPPUNIT_ASSERT(carlaCallPeer == aliceUri);
     582             : 
     583           1 :     JAMI_INFO("Stop call between alice and carla");
     584           1 :     aliceCallStopped = 0;
     585           1 :     Manager::instance().hangupCall(carlaId, carlaCallId);
     586           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceCallStopped.load(); }));
     587           1 : }
     588             : 
     589             : void
     590           1 : CallTest::testDhtPublicInCall()
     591             : {
     592           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     593           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     594           1 :     auto bobUri = bobAccount->getUsername();
     595           1 :     auto aliceUri = aliceAccount->getUsername();
     596             : 
     597           1 :     std::mutex mtx;
     598           1 :     std::unique_lock lk {mtx};
     599           1 :     std::condition_variable cv;
     600           1 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     601           1 :     std::atomic_bool callReceived {false};
     602           1 :     std::atomic<int> callStopped {0};
     603             :     // Watch signals
     604           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
     605           0 :         [&](const std::string&,
     606             :             const std::string&,
     607             :             const std::string&,
     608             :             const std::vector<std::map<std::string, std::string>>&) {
     609           0 :             callReceived = true;
     610           0 :             cv.notify_one();
     611           0 :         }));
     612           1 :     confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::StateChange>(
     613           0 :         [&](const std::string&, const std::string&, const std::string& state, signed) {
     614           0 :             if (state == "OVER") {
     615           0 :                 callStopped += 1;
     616           0 :                 if (callStopped == 2)
     617           0 :                     cv.notify_one();
     618             :             }
     619           0 :         }));
     620           1 :     libjami::registerSignalHandlers(confHandlers);
     621             : 
     622           1 :     std::map<std::string, std::string> details;
     623           1 :     details["DHT.PublicInCalls"] = "FALSE";
     624           1 :     libjami::setAccountDetails(bobId, details);
     625             : 
     626           1 :     JAMI_INFO("Start call between alice and Bob");
     627           1 :     auto call = libjami::placeCallWithMedia(aliceId, bobUri, {});
     628             : 
     629           3 :     CPPUNIT_ASSERT(!cv.wait_for(lk, 15s, [&] { return callReceived.load(); }));
     630           1 : }
     631             : 
     632             : } // namespace test
     633             : } // namespace jami
     634             : 
     635           1 : RING_TEST_RUNNER(jami::test::CallTest::name())

Generated by: LCOV version 1.14