LCOV - code coverage report
Current view: top level - test/unitTest/conversation - conversationFetchSent.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 284 308 92.2 %
Date: 2024-12-21 08:56:24 Functions: 61 61 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 <git2.h>
      27             : #include <filesystem>
      28             : #include <msgpack.hpp>
      29             : 
      30             : #include "../../test_runner.h"
      31             : #include "account_const.h"
      32             : #include "archiver.h"
      33             : #include "base64.h"
      34             : #include "common.h"
      35             : #include "conversation/conversationcommon.h"
      36             : #include "fileutils.h"
      37             : #include "jami.h"
      38             : #include "manager.h"
      39             : #include <dhtnet/certstore.h>
      40             : 
      41             : using namespace std::string_literals;
      42             : using namespace std::literals::chrono_literals;
      43             : using namespace libjami::Account;
      44             : 
      45             : namespace jami {
      46             : namespace test {
      47             : 
      48             : struct UserData {
      49             :     std::string conversationId;
      50             :     bool requestReceived {false};
      51             :     bool registered {false};
      52             :     bool stopped {false};
      53             :     bool deviceAnnounced {false};
      54             :     std::vector<libjami::SwarmMessage> messages;
      55             : };
      56             : 
      57             : class ConversationFetchSentTest : public CppUnit::TestFixture
      58             : {
      59             : public:
      60           6 :     ~ConversationFetchSentTest() { libjami::fini(); }
      61           2 :     static std::string name() { return "Conversation"; }
      62             :     void setUp();
      63             :     void tearDown();
      64             :     std::string createFakeConversation(std::shared_ptr<JamiAccount> account,
      65             :                                        const std::string& fakeCert = "");
      66             : 
      67             :     std::string aliceId;
      68             :     UserData aliceData;
      69             :     std::string alice2Id;
      70             :     UserData alice2Data;
      71             :     std::string bobId;
      72             :     UserData bobData;
      73             :     std::string bob2Id;
      74             :     UserData bob2Data;
      75             :     std::string carlaId;
      76             :     UserData carlaData;
      77             : 
      78             :     std::mutex mtx;
      79             :     std::unique_lock<std::mutex> lk {mtx};
      80             :     std::condition_variable cv;
      81             : 
      82             :     void connectSignals();
      83             : 
      84             : private:
      85             :     void testSyncFetch();
      86             :     void testSyncAfterDisconnection();
      87             :     void testDisplayedOnLoad();
      88             : 
      89           2 :     CPPUNIT_TEST_SUITE(ConversationFetchSentTest);
      90           1 :     CPPUNIT_TEST(testSyncFetch);
      91           1 :     CPPUNIT_TEST(testSyncAfterDisconnection);
      92           1 :     CPPUNIT_TEST(testDisplayedOnLoad);
      93           4 :     CPPUNIT_TEST_SUITE_END();
      94             : };
      95             : 
      96             : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConversationFetchSentTest, ConversationFetchSentTest::name());
      97             : 
      98             : void
      99           3 : ConversationFetchSentTest::setUp()
     100             : {
     101             :     // Init daemon
     102           3 :     libjami::init(
     103             :         libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
     104           3 :     if (not Manager::instance().initialized)
     105           1 :         CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
     106             : 
     107           3 :     auto actors = load_actors("actors/alice-bob-carla.yml");
     108           3 :     aliceId = actors["alice"];
     109           3 :     bobId = actors["bob"];
     110           3 :     carlaId = actors["carla"];
     111             : 
     112           3 :     aliceData = {};
     113           3 :     alice2Data = {};
     114           3 :     bobData = {};
     115           3 :     bob2Data = {};
     116           3 :     carlaData = {};
     117             : 
     118           3 :     Manager::instance().sendRegister(carlaId, false);
     119           9 :     wait_for_announcement_of({aliceId, bobId});
     120           3 : }
     121             : 
     122             : void
     123           3 : ConversationFetchSentTest::connectSignals()
     124             : {
     125           3 :     std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
     126           3 :     confHandlers.insert(
     127           6 :         libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>(
     128          15 :             [&](const std::string& accountId, const std::map<std::string, std::string>&) {
     129          15 :                 if (accountId == aliceId) {
     130           2 :                     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     131           2 :                     auto details = aliceAccount->getVolatileAccountDetails();
     132           4 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     133           2 :                     if (daemonStatus == "REGISTERED") {
     134           0 :                         aliceData.registered = true;
     135           2 :                     } else if (daemonStatus == "UNREGISTERED") {
     136           2 :                         aliceData.stopped = true;
     137             :                     }
     138           4 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     139           2 :                     aliceData.deviceAnnounced = deviceAnnounced == "true";
     140          15 :                 } else if (accountId == bobId) {
     141           3 :                     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     142           3 :                     auto details = bobAccount->getVolatileAccountDetails();
     143           6 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     144           3 :                     if (daemonStatus == "REGISTERED") {
     145           1 :                         bobData.registered = true;
     146           2 :                     } else if (daemonStatus == "UNREGISTERED") {
     147           1 :                         bobData.stopped = true;
     148             :                     }
     149           6 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     150           3 :                     bobData.deviceAnnounced = deviceAnnounced == "true";
     151          13 :                 } else if (accountId == bob2Id) {
     152           8 :                     auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id);
     153           8 :                     auto details = bob2Account->getVolatileAccountDetails();
     154          16 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     155           8 :                     if (daemonStatus == "REGISTERED") {
     156           4 :                         bob2Data.registered = true;
     157           4 :                     } else if (daemonStatus == "UNREGISTERED") {
     158           2 :                         bob2Data.stopped = true;
     159             :                     }
     160          16 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     161           8 :                     bob2Data.deviceAnnounced = deviceAnnounced == "true";
     162          10 :                 } else if (accountId == carlaId) {
     163           0 :                     auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId);
     164           0 :                     auto details = carlaAccount->getVolatileAccountDetails();
     165           0 :                     auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS];
     166           0 :                     if (daemonStatus == "REGISTERED") {
     167           0 :                         carlaData.registered = true;
     168           0 :                     } else if (daemonStatus == "UNREGISTERED") {
     169           0 :                         carlaData.stopped = true;
     170             :                     }
     171           0 :                     auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED];
     172           0 :                     carlaData.deviceAnnounced = deviceAnnounced == "true";
     173           0 :                 }
     174          15 :                 cv.notify_one();
     175          15 :             }));
     176           3 :     confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmLoaded>(
     177           1 :         [&](uint32_t, const std::string& accountId,
     178             :             const std::string& /* conversationId */,
     179             :             std::vector<libjami::SwarmMessage> messages) {
     180           1 :             if (accountId == aliceId) {
     181           0 :                 aliceData.messages.insert(aliceData.messages.end(), messages.begin(), messages.end());
     182           1 :             } else if (accountId == bobId) {
     183           1 :                 bobData.messages.insert(bobData.messages.end(), messages.begin(), messages.end());
     184           0 :             } else if (accountId == bob2Id) {
     185           0 :                 bob2Data.messages.insert(bob2Data.messages.end(), messages.begin(), messages.end());
     186             :             }
     187           1 :             cv.notify_one();
     188           1 :         }));
     189           3 :     confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>(
     190           8 :         [&](const std::string& accountId, const std::string& conversationId) {
     191           8 :             if (accountId == aliceId) {
     192           3 :                 aliceData.conversationId = conversationId;
     193           5 :             } else if (accountId == alice2Id) {
     194           0 :                 alice2Data.conversationId = conversationId;
     195           5 :             } else if (accountId == bobId) {
     196           3 :                 bobData.conversationId = conversationId;
     197           2 :             } else if (accountId == bob2Id) {
     198           2 :                 bob2Data.conversationId = conversationId;
     199           0 :             } else if (accountId == carlaId) {
     200           0 :                 carlaData.conversationId = conversationId;
     201             :             }
     202           8 :             cv.notify_one();
     203           8 :         }));
     204           3 :     confHandlers.insert(
     205           6 :         libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>(
     206           5 :             [&](const std::string& accountId,
     207             :                 const std::string& /* conversationId */,
     208             :                 std::map<std::string, std::string> /*metadatas*/) {
     209           5 :                 if (accountId == aliceId) {
     210           0 :                     aliceData.requestReceived = true;
     211           5 :                 } else if (accountId == bobId) {
     212           3 :                     bobData.requestReceived = true;
     213           2 :                 } else if (accountId == bob2Id) {
     214           2 :                     bob2Data.requestReceived = true;
     215           0 :                 } else if (accountId == carlaId) {
     216           0 :                     carlaData.requestReceived = true;
     217             :                 }
     218           5 :                 cv.notify_one();
     219           5 :             }));
     220           3 :     confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>(
     221          35 :         [&](const std::string& accountId,
     222             :             const std::string& /* conversationId */,
     223             :             libjami::SwarmMessage message) {
     224          35 :             if (accountId == aliceId) {
     225          13 :                 aliceData.messages.emplace_back(message);
     226          22 :             } else if (accountId == bobId) {
     227          12 :                 bobData.messages.emplace_back(message);
     228          10 :             } else if (accountId == bob2Id) {
     229          10 :                 bob2Data.messages.emplace_back(message);
     230           0 :             } else if (accountId == carlaId) {
     231           0 :                 carlaData.messages.emplace_back(message);
     232             :             }
     233          35 :             cv.notify_one();
     234          35 :         }));
     235           3 :     confHandlers.insert(
     236           6 :         libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>(
     237          33 :             [&](const std::string& accountId,
     238             :                 const std::string& /*conversationId*/,
     239             :                 const std::string& peer,
     240             :                 const std::string& msgId,
     241             :                 int status) {
     242          33 :                 auto placeMessage = [&](auto& data) {
     243          64 :                     for (auto& dataMsg : data.messages) {
     244          64 :                         if (dataMsg.id == msgId) {
     245          33 :                             dataMsg.status[peer] = status;
     246          33 :                             return;
     247             :                         }
     248             :                     }
     249          33 :                 };
     250          33 :                 if (accountId == aliceId) {
     251           9 :                     placeMessage(aliceData);
     252          24 :                 } else if (accountId == bobId) {
     253          18 :                     placeMessage(bobData);
     254           6 :                 } else if (accountId == bob2Id) {
     255           6 :                     placeMessage(bob2Data);
     256             :                 }
     257          33 :                 cv.notify_one();
     258          33 :             }));
     259           3 :     libjami::registerSignalHandlers(confHandlers);
     260           3 : }
     261             : 
     262             : void
     263           3 : ConversationFetchSentTest::tearDown()
     264             : {
     265           6 :     auto bobArchive = std::filesystem::current_path().string() + "/bob.gz";
     266           3 :     std::remove(bobArchive.c_str());
     267           6 :     auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz";
     268           3 :     std::remove(aliceArchive.c_str());
     269           3 :     if (!alice2Id.empty()) {
     270           0 :         wait_for_removal_of(alice2Id);
     271             :     }
     272             : 
     273           3 :     if (bob2Id.empty()) {
     274           4 :         wait_for_removal_of({aliceId, bobId, carlaId});
     275             :     } else {
     276          10 :         wait_for_removal_of({aliceId, bobId, carlaId, bob2Id});
     277             :     }
     278           3 : }
     279             : 
     280             : void
     281           1 : ConversationFetchSentTest::testSyncAfterDisconnection()
     282             : {
     283           1 :     std::cout << "\nRunning test: " << __func__ << std::endl;
     284           1 :     connectSignals();
     285             : 
     286           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     287           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     288           1 :     auto bobUri = bobAccount->getUsername();
     289           1 :     auto aliceUri = aliceAccount->getUsername();
     290             : 
     291             :     // Bob creates a second device
     292           2 :     auto bobArchive = std::filesystem::current_path().string() + "/bob.gz";
     293           1 :     std::remove(bobArchive.c_str());
     294           1 :     bobAccount->exportArchive(bobArchive);
     295           2 :     std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
     296           1 :     details[ConfProperties::TYPE] = "RING";
     297           1 :     details[ConfProperties::DISPLAYNAME] = "BOB2";
     298           1 :     details[ConfProperties::ALIAS] = "BOB2";
     299           1 :     details[ConfProperties::UPNP_ENABLED] = "true";
     300           1 :     details[ConfProperties::ARCHIVE_PASSWORD] = "";
     301           1 :     details[ConfProperties::ARCHIVE_PIN] = "";
     302           1 :     details[ConfProperties::ARCHIVE_PATH] = bobArchive;
     303           1 :     bob2Id = Manager::instance().addAccount(details);
     304             : 
     305             :     // Disconnect bob2, to create a valid conv betwen Alice and Bob1
     306           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; }));
     307             : 
     308             :     // Create conversation between alice and bob
     309           1 :     aliceAccount->addContact(bobUri);
     310           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     311           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     312           1 :     CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri));
     313           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && !bob2Data.conversationId.empty(); }));
     314             : 
     315           1 :     std::this_thread::sleep_for(5s); // Wait for all join messages to be received
     316             : 
     317             :     // bob send 4 messages
     318           1 :     auto aliceMsgSize = aliceData.messages.size(), bob2MsgSize = bob2Data.messages.size(), bobMsgSize = bobData.messages.size();
     319           1 :     libjami::sendMessage(bobId, bobData.conversationId, "1"s, "");
     320           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
     321             :         return aliceData.messages.size() == aliceMsgSize + 1
     322             :                 && bobData.messages.size() == bobMsgSize + 1
     323             :                 && bob2Data.messages.size() == bob2MsgSize + 1; }));
     324           1 :     auto msgId1 = aliceData.messages.rbegin()->id;
     325          19 :     auto getMsgStatus = [&](const auto& data, const auto& id, const auto& peer) {
     326          33 :         for (const auto& msg : data.messages) {
     327          33 :             if (msg.id == id && msg.status.find(peer) != msg.status.end()) {
     328          19 :                 return static_cast<libjami::Account::MessageStates>(msg.status.at(peer));
     329             :             }
     330             :         }
     331           0 :         return libjami::Account::MessageStates::UNKNOWN;
     332             :     };
     333           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId1, aliceUri) == libjami::Account::MessageStates::SENT; }));
     334           1 :     libjami::sendMessage(bobId, bobData.conversationId, "2"s, "");
     335           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 2
     336             :                                                     && bobData.messages.size() == bobMsgSize + 2
     337             :                                                     && bob2Data.messages.size() == bob2MsgSize + 2;}));
     338           1 :     auto msgId2 = aliceData.messages.rbegin()->id;
     339             :     // Because bob2Data.status is here only on update, but msgReceived can be good directly at first
     340           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId2, aliceUri) == libjami::Account::MessageStates::SENT; }));
     341           1 :     libjami::sendMessage(bobId, bobData.conversationId, "3"s, "");
     342           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 3
     343             :                                                     && bobData.messages.size() == bobMsgSize + 3
     344             :                                                     && bob2Data.messages.size() == bob2MsgSize + 3; }));
     345           1 :     auto msgId3 = aliceData.messages.rbegin()->id;
     346           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId3, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId3, aliceUri) == libjami::Account::MessageStates::SENT; }));
     347           1 :     libjami::sendMessage(bobId, bobData.conversationId, "4"s, "");
     348           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 4
     349             :                                                     && bobData.messages.size() == bobMsgSize + 4
     350             :                                                     && bob2Data.messages.size() == bob2MsgSize + 4; }));
     351           1 :     auto msgId4 = aliceData.messages.rbegin()->id;
     352           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId4, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId4, aliceUri) == libjami::Account::MessageStates::SENT; }));
     353             : 
     354             : 
     355             :     // Bob is disabled. Bob2 will get the infos
     356           1 :     Manager::instance().sendRegister(bobId, false);
     357           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.stopped; }));
     358             : 
     359             :     // Second message is set to displayed by alice
     360           1 :     aliceAccount->setMessageDisplayed("swarm:" + aliceData.conversationId, msgId2, 3);
     361           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bob2Data, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED
     362             :                                                 && getMsgStatus(bob2Data, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED; }));
     363           1 :     CPPUNIT_ASSERT(getMsgStatus(bobData, msgId1, aliceUri) != libjami::Account::MessageStates::DISPLAYED);
     364             : 
     365             :     // Alice is disabled so she will not sync
     366           1 :     Manager::instance().sendRegister(aliceId, false);
     367           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.stopped; }));
     368             : 
     369             :     // Bob is enabled again, should sync infos with bob2
     370           1 :     Manager::instance().sendRegister(bobId, true);
     371           4 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED
     372             :                                                 && getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED; }));
     373           1 : }
     374             : 
     375             : void
     376           1 : ConversationFetchSentTest::testSyncFetch()
     377             : {
     378           1 :     std::cout << "\nRunning test: " << __func__ << std::endl;
     379           1 :     connectSignals();
     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             :     // Bob creates a second device
     387           2 :     auto bobArchive = std::filesystem::current_path().string() + "/bob.gz";
     388           1 :     std::remove(bobArchive.c_str());
     389           1 :     bobAccount->exportArchive(bobArchive);
     390           2 :     std::map<std::string, std::string> details = libjami::getAccountTemplate("RING");
     391           1 :     details[ConfProperties::TYPE] = "RING";
     392           1 :     details[ConfProperties::DISPLAYNAME] = "BOB2";
     393           1 :     details[ConfProperties::ALIAS] = "BOB2";
     394           1 :     details[ConfProperties::UPNP_ENABLED] = "true";
     395           1 :     details[ConfProperties::ARCHIVE_PASSWORD] = "";
     396           1 :     details[ConfProperties::ARCHIVE_PIN] = "";
     397           1 :     details[ConfProperties::ARCHIVE_PATH] = bobArchive;
     398           1 :     bob2Id = Manager::instance().addAccount(details);
     399             : 
     400             :     // Disconnect bob2, to create a valid conv betwen Alice and Bob1
     401           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; }));
     402             : 
     403             :     // Create conversation between alice and bob
     404           1 :     aliceAccount->addContact(bobUri);
     405           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     406           4 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     407           1 :     CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri));
     408           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && !bob2Data.conversationId.empty(); }));
     409             : 
     410           1 :     std::this_thread::sleep_for(5s); // Wait for all join messages to be received
     411             : 
     412             :     // bob send 4 messages
     413           1 :     auto aliceMsgSize = aliceData.messages.size(), bob2MsgSize = bob2Data.messages.size(), bobMsgSize = bobData.messages.size();
     414           1 :     libjami::sendMessage(bobId, bobData.conversationId, "1"s, "");
     415           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
     416             :         return aliceData.messages.size() == aliceMsgSize + 1
     417             :                 && bobData.messages.size() == bobMsgSize + 1
     418             :                 && bob2Data.messages.size() == bob2MsgSize + 1; }));
     419           1 :     auto msgId1 = aliceData.messages.rbegin()->id;
     420          26 :     auto getMsgStatus = [&](const auto& data, const auto& id, const auto& peer) {
     421          74 :         for (const auto& msg : data.messages) {
     422          70 :             if (msg.id == id && msg.status.find(peer) != msg.status.end()) {
     423          22 :                 return static_cast<libjami::Account::MessageStates>(msg.status.at(peer));
     424             :             }
     425             :         }
     426           4 :         return libjami::Account::MessageStates::UNKNOWN;
     427             :     };
     428           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId1, aliceUri) == libjami::Account::MessageStates::SENT; }));
     429           1 :     libjami::sendMessage(bobId, bobData.conversationId, "2"s, "");
     430           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 2
     431             :                                                     && bobData.messages.size() == bobMsgSize + 2
     432             :                                                     && bob2Data.messages.size() == bob2MsgSize + 2;}));
     433           1 :     auto msgId2 = aliceData.messages.rbegin()->id;
     434             :     // Because bob2Data.status is here only on update, but msgReceived can be good directly at first
     435           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId2, aliceUri) == libjami::Account::MessageStates::SENT; }));
     436           1 :     libjami::sendMessage(bobId, bobData.conversationId, "3"s, "");
     437           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 3
     438             :                                                     && bobData.messages.size() == bobMsgSize + 3
     439             :                                                     && bob2Data.messages.size() == bob2MsgSize + 3; }));
     440           1 :     auto msgId3 = aliceData.messages.rbegin()->id;
     441           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId3, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId3, aliceUri) == libjami::Account::MessageStates::SENT; }));
     442           1 :     libjami::sendMessage(bobId, bobData.conversationId, "4"s, "");
     443           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 4
     444             :                                                     && bobData.messages.size() == bobMsgSize + 4
     445             :                                                     && bob2Data.messages.size() == bob2MsgSize + 4; }));
     446           1 :     auto msgId4 = aliceData.messages.rbegin()->id;
     447           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId4, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId4, aliceUri) == libjami::Account::MessageStates::SENT; }));
     448             : 
     449             :     // Second message is set to displayed by alice
     450           1 :     aliceAccount->setMessageDisplayed("swarm:" + aliceData.conversationId, msgId2, 3);
     451           7 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED && getMsgStatus(bob2Data, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED
     452             :                                                 && getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED && getMsgStatus(bob2Data, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED; }));
     453             :     // Other messages are still set to received
     454           1 :     CPPUNIT_ASSERT(getMsgStatus(bobData, msgId3, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId3, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bobData, msgId4, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bob2Data, msgId4, aliceUri) == libjami::Account::MessageStates::SENT);
     455             : 
     456             :     // Get conversation members should show the same information
     457           1 :     auto membersInfos = libjami::getConversationMembers(bobId, bobData.conversationId);
     458           2 :     CPPUNIT_ASSERT(std::find_if(membersInfos.begin(),
     459             :                                 membersInfos.end(),
     460             :                                 [&](auto infos) {
     461             :                                     return infos["uri"] == aliceUri
     462             :                                            && infos["lastDisplayed"] == msgId2;
     463             :                                 })
     464             :                    != membersInfos.end());
     465             : 
     466             :     // Alice is disabled
     467           1 :     Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately
     468           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.stopped; }));
     469             : 
     470             :     // Bob send 2 more messages
     471           1 :     bob2MsgSize = bob2Data.messages.size();
     472           1 :     libjami::sendMessage(bobId, bobData.conversationId, "5"s, "");
     473           1 :     libjami::sendMessage(bobId, bobData.conversationId, "6"s, "");
     474           6 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.messages.size() == bob2MsgSize + 2; }));
     475           1 :     auto msgId5 = bobData.messages.rbegin()->id;
     476           1 :     auto msgId6 = (bobData.messages.rbegin()+1)->id;
     477             :     // No update
     478           3 :     CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId5, aliceUri) == libjami::Account::MessageStates::SENT && getMsgStatus(bobData, msgId6, aliceUri) == libjami::Account::MessageStates::SENT; }));
     479             :     // SwarmMessage will not get any status because nobody got the message
     480           1 :     CPPUNIT_ASSERT(getMsgStatus(bobData, msgId5, aliceUri) == libjami::Account::MessageStates::UNKNOWN);
     481           1 :     CPPUNIT_ASSERT(getMsgStatus(bobData, msgId6, aliceUri) == libjami::Account::MessageStates::UNKNOWN);
     482           1 : }
     483             : 
     484             : void
     485           1 : ConversationFetchSentTest::testDisplayedOnLoad()
     486             : {
     487           1 :     std::cout << "\nRunning test: " << __func__ << std::endl;
     488           1 :     connectSignals();
     489             : 
     490           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     491           1 :     auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
     492           1 :     auto bobUri = bobAccount->getUsername();
     493           1 :     auto aliceUri = aliceAccount->getUsername();
     494             : 
     495             :     // Create conversation between alice and bob
     496           1 :     aliceAccount->addContact(bobUri);
     497           1 :     aliceAccount->sendTrustRequest(bobUri, {});
     498           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; }));
     499           1 :     CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri));
     500           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); }));
     501             : 
     502           1 :     std::this_thread::sleep_for(5s); // Wait for all join messages to be received
     503             : 
     504             :     // bob send 2 messages
     505           1 :     auto aliceMsgSize = aliceData.messages.size(), bobMsgSize = bobData.messages.size();
     506           1 :     libjami::sendMessage(bobId, bobData.conversationId, "1"s, "");
     507           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
     508             :         return aliceData.messages.size() == aliceMsgSize + 1
     509             :                 && bobData.messages.size() == bobMsgSize + 1; }));
     510           1 :     auto msgId1 = aliceData.messages.rbegin()->id;
     511          10 :     auto getMsgStatus = [&](const auto& data, const auto& id, const auto& peer) {
     512          12 :         for (const auto& msg : data.messages) {
     513          10 :             if (msg.id == id && msg.status.find(peer) != msg.status.end()) {
     514           8 :                 return static_cast<libjami::Account::MessageStates>(msg.status.at(peer));
     515             :             }
     516             :         }
     517           2 :         return libjami::Account::MessageStates::UNKNOWN;
     518             :     };
     519           2 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::SENT; }));
     520           1 :     libjami::sendMessage(bobId, bobData.conversationId, "2"s, "");
     521           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 2
     522             :                                                     && bobData.messages.size() == bobMsgSize + 2;}));
     523           1 :     auto msgId2 = aliceData.messages.rbegin()->id;
     524             : 
     525             :     // Second message is set to displayed by alice
     526           1 :     aliceAccount->setMessageDisplayed("swarm:" + aliceData.conversationId, msgId2, 3);
     527           5 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED
     528             :                                                 && getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED; }));
     529             : 
     530           1 :     bobAccount->convModule()->loadConversations(); // Reset data
     531           1 :     bobData.messages.clear();
     532             :     // Load messages, messages should be displayed
     533           1 :     CPPUNIT_ASSERT(getMsgStatus(bobData, msgId1, aliceUri) != libjami::Account::MessageStates::DISPLAYED);
     534           1 :     libjami::loadConversation(bobId, bobData.conversationId, "", 0);
     535           3 :     CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() {
     536             :         return getMsgStatus(bobData, msgId1, aliceUri) == libjami::Account::MessageStates::DISPLAYED
     537             :                                                 && getMsgStatus(bobData, msgId2, aliceUri) == libjami::Account::MessageStates::DISPLAYED; }));
     538             : 
     539           1 : }
     540             : 
     541             : 
     542             : } // namespace test
     543             : } // namespace jami
     544             : 
     545           1 : RING_TEST_RUNNER(jami::test::ConversationFetchSentTest::name())

Generated by: LCOV version 1.14