LCOV - code coverage report
Current view: top level - test/unitTest/conversation - typers.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 138 149 92.6 %
Date: 2024-12-21 08:56:24 Functions: 34 34 100.0 %

          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 <condition_variable>
      23             : #include <string>
      24             : #include <fstream>
      25             : #include <streambuf>
      26             : #include <filesystem>
      27             : #include <msgpack.hpp>
      28             : 
      29             : #include "../../test_runner.h"
      30             : #include "account_const.h"
      31             : #include "archiver.h"
      32             : #include "base64.h"
      33             : #include "common.h"
      34             : #include "conversation/conversationcommon.h"
      35             : #include "fileutils.h"
      36             : #include "jami.h"
      37             : #include "manager.h"
      38             : #include <dhtnet/certstore.h>
      39             : 
      40             : using namespace std::string_literals;
      41             : using namespace std::literals::chrono_literals;
      42             : using namespace libjami::Account;
      43             : 
      44             : namespace jami {
      45             : namespace test {
      46             : 
      47             : struct UserData {
      48             :     std::string conversationId;
      49             :     bool registered {false};
      50             :     bool stopped {false};
      51             :     bool requestReceived {false};
      52             :     bool deviceAnnounced {false};
      53             :     std::map<std::string, int> composing;
      54             : };
      55             : 
      56             : class TypersTest : public CppUnit::TestFixture
      57             : {
      58             : public:
      59           8 :     ~TypersTest() { libjami::fini(); }
      60           2 :     static std::string name() { return "Typers"; }
      61             :     void setUp();
      62             :     void tearDown();
      63             : 
      64             :     std::string aliceId;
      65             :     UserData aliceData;
      66             :     std::string bobId;
      67             :     UserData bobData;
      68             : 
      69             :     std::mutex mtx;
      70             :     std::unique_lock<std::mutex> lk {mtx};
      71             :     std::condition_variable cv;
      72             : 
      73             :     void connectSignals();
      74             : 
      75             :     void testSetIsComposing();
      76             :     void testTimeout();
      77             :     void testTypingRemovedOnMemberRemoved();
      78             :     void testAccountConfig();
      79             : 
      80             : private:
      81           2 :     CPPUNIT_TEST_SUITE(TypersTest);
      82           1 :     CPPUNIT_TEST(testSetIsComposing);
      83           1 :     CPPUNIT_TEST(testTimeout);
      84           1 :     CPPUNIT_TEST(testTypingRemovedOnMemberRemoved);
      85           1 :     CPPUNIT_TEST(testAccountConfig);
      86           4 :     CPPUNIT_TEST_SUITE_END();
      87             : };
      88             : 
      89             : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(TypersTest, TypersTest::name());
      90             : 
      91             : void
      92           4 : TypersTest::setUp()
      93             : {
      94             :     // Init daemon
      95           4 :     libjami::init(
      96             :         libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
      97           4 :     if (not Manager::instance().initialized)
      98           1 :         CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
      99             : 
     100           4 :     auto actors = load_actors("actors/alice-bob.yml");
     101           4 :     aliceId = actors["alice"];
     102           4 :     bobId = actors["bob"];
     103           4 :     aliceData = {};
     104           4 :     bobData = {};
     105             : 
     106          12 :     wait_for_announcement_of({aliceId, bobId});
     107           4 : }
     108             : void
     109           4 : TypersTest::connectSignals()
     110             : {
     111           4 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     112           4 :     confHandlers.insert(
     113           8 :         libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>(
     114           4 :             [&](const std::string& accountId, const std::map<std::string, std::string>&) {
     115           4 :                 if (accountId == aliceId) {
     116           4 :                     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     117           4 :                     auto details = aliceAccount->getVolatileAccountDetails();
     118           8 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     119           4 :                     if (daemonStatus == "REGISTERED") {
     120           2 :                         aliceData.registered = true;
     121           2 :                     } else if (daemonStatus == "UNREGISTERED") {
     122           1 :                         aliceData.stopped = true;
     123             :                     }
     124           8 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     125           4 :                     aliceData.deviceAnnounced = deviceAnnounced == "true";
     126           4 :                 } else if (accountId == bobId) {
     127           0 :                     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     128           0 :                     auto details = bobAccount->getVolatileAccountDetails();
     129           0 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     130           0 :                     if (daemonStatus == "REGISTERED") {
     131           0 :                         bobData.registered = true;
     132           0 :                     } else if (daemonStatus == "UNREGISTERED") {
     133           0 :                         bobData.stopped = true;
     134             :                     }
     135           0 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     136           0 :                     bobData.deviceAnnounced = deviceAnnounced == "true";
     137           0 :                 }
     138           4 :                 cv.notify_one();
     139           4 :             }));
     140           4 :     confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>(
     141           8 :         [&](const std::string& accountId, const std::string& conversationId) {
     142           8 :             if (accountId == aliceId) {
     143           4 :                 aliceData.conversationId = conversationId;
     144           4 :             } else if (accountId == bobId) {
     145           4 :                 bobData.conversationId = conversationId;
     146             :             }
     147           8 :             cv.notify_one();
     148           8 :         }));
     149           4 :     confHandlers.insert(
     150           8 :         libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>(
     151           4 :             [&](const std::string& accountId,
     152             :                 const std::string& /* conversationId */,
     153             :                 std::map<std::string, std::string> /*metadatas*/) {
     154           4 :                 if (accountId == aliceId) {
     155           0 :                     aliceData.requestReceived = true;
     156           4 :                 } else if (accountId == bobId) {
     157           4 :                     bobData.requestReceived = true;
     158             :                 }
     159           4 :                 cv.notify_one();
     160           4 :             }));
     161           4 :     confHandlers.insert(
     162           8 :         libjami::exportable_callback<libjami::ConfigurationSignal::ComposingStatusChanged>(
     163           6 :             [&](const std::string& accountId,
     164             :                 const std::string& /* conversationId */,
     165             :                 const std::string& contactUri,
     166             :                 int status) {
     167           6 :                 if (accountId == aliceId) {
     168           2 :                     aliceData.composing[contactUri] = status;
     169           4 :                 } else if (accountId == bobId) {
     170           4 :                     bobData.composing[contactUri] = status;
     171             :                 }
     172           6 :                 cv.notify_one();
     173           6 :             }));
     174             : 
     175           4 :     libjami::registerSignalHandlers(confHandlers);
     176           4 : }
     177             : 
     178             : void
     179           4 : TypersTest::tearDown()
     180             : {
     181          12 :     wait_for_removal_of({aliceId, bobId});
     182           4 : }
     183             : 
     184             : void
     185           1 : TypersTest::testSetIsComposing()
     186             : {
     187           1 :     connectSignals();
     188           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     189           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     190           1 :     auto aliceUri = aliceAccount->getUsername();
     191           1 :     auto bobUri = bobAccount->getUsername();
     192             : 
     193           1 :     aliceAccount->addContact(bobUri);
     194           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     195           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     196             : 
     197           1 :     CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 1);
     198           1 :     libjami::acceptConversationRequest(bobId, aliceData.conversationId);
     199           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); }));
     200           1 :     std::this_thread::sleep_for(5s); // Wait a bit to ensure that everything is updated
     201             : 
     202           1 :     libjami::setIsComposing(aliceId, "swarm:" + aliceData.conversationId, true);
     203           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() {
     204             :         return bobData.composing[aliceUri]; }));
     205             : 
     206           1 :     libjami::setIsComposing(aliceId, "swarm:" + aliceData.conversationId, false);
     207           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 12s, [&]() { return !bobData.composing[aliceUri]; }));
     208           1 : }
     209             : 
     210             : void
     211           1 : TypersTest::testTimeout()
     212             : {
     213           1 :     connectSignals();
     214           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     215           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     216           1 :     auto aliceUri = aliceAccount->getUsername();
     217           1 :     auto bobUri = bobAccount->getUsername();
     218             : 
     219           1 :     aliceAccount->addContact(bobUri);
     220           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     221           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     222             : 
     223           1 :     CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 1);
     224           1 :     libjami::acceptConversationRequest(bobId, aliceData.conversationId);
     225           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); }));
     226           1 :     std::this_thread::sleep_for(5s); // Wait a bit to ensure that everything is updated
     227             : 
     228           1 :     libjami::setIsComposing(aliceId, "swarm:" + aliceData.conversationId, true);
     229           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return bobData.composing[aliceUri]; }));
     230             : 
     231             :     // After 12s, it should be false
     232           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 12s, [&]() { return !bobData.composing[aliceUri]; }));
     233           1 : }
     234             : 
     235             : void
     236           1 : TypersTest::testTypingRemovedOnMemberRemoved()
     237             : {
     238           1 :     connectSignals();
     239             : 
     240           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     241           1 :     auto bobUri = bobAccount->getUsername();
     242             : 
     243           1 :     auto convId = libjami::startConversation(aliceId);
     244             : 
     245           1 :     libjami::addConversationMember(aliceId, convId, bobUri);
     246           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     247             : 
     248           1 :     libjami::acceptConversationRequest(bobId, aliceData.conversationId);
     249           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); }));
     250             : 
     251           1 :     std::this_thread::sleep_for(5s); // Wait a bit to ensure that everything is updated
     252             : 
     253           1 :     libjami::setIsComposing(bobId, "swarm:" + bobData.conversationId, true);
     254           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return aliceData.composing[bobUri]; }));
     255             : 
     256           1 :     libjami::removeConversationMember(aliceId, convId, bobUri);
     257           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !aliceData.composing[bobUri]; }));
     258           1 : }
     259             : 
     260             : void
     261           1 : TypersTest::testAccountConfig()
     262             : {
     263           1 :     connectSignals();
     264           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     265           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     266           1 :     auto aliceUri = aliceAccount->getUsername();
     267           1 :     auto bobUri = bobAccount->getUsername();
     268             : 
     269           1 :     std::map<std::string, std::string> details;
     270           1 :     details[ConfProperties::SENDCOMPOSING] = "false";
     271           1 :     libjami::setAccountDetails(aliceId, details);
     272           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.registered; }));
     273             : 
     274           1 :     aliceAccount->addContact(bobUri);
     275           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     276           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     277             : 
     278           1 :     CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 1);
     279           1 :     libjami::acceptConversationRequest(bobId, aliceData.conversationId);
     280           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); }));
     281           1 :     std::this_thread::sleep_for(5s); // Wait a bit to ensure that everything is updated
     282             : 
     283             :     // Should not receive composing status
     284           1 :     libjami::setIsComposing(aliceId, "swarm:" + aliceData.conversationId, true);
     285           3 :     CPPUNIT_ASSERT(!cv.wait_for(lk, 5s, [&]() {
     286             :         return bobData.composing[aliceUri]
     287             :         ; }));
     288           1 : }
     289             : 
     290             : 
     291             : } // namespace test
     292             : } // namespace jami
     293             : 
     294           1 : RING_TEST_RUNNER(jami::test::TypersTest::name())

Generated by: LCOV version 1.14