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-04-23 08:02:50 Functions: 59 61 96.7 %

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

Generated by: LCOV version 1.14