diff --git a/CMakeLists.txt b/CMakeLists.txt index f536e45a943d4d8e53777fc3ec6f5e1a9a26ae1e..d980f58567add76c5e38ae53e56419598fc8d38c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) project(jami-core - VERSION 13.11.0 + VERSION 14.0.0 LANGUAGES C CXX) set(PACKAGE_NAME "Jami Daemon") set (CMAKE_CXX_STANDARD 17) diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml index c1643d2d843e416c52cee89f392b246f71daf87f..e7f7aa8973d630232868bec4f72a153874e68072 100644 --- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml +++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml @@ -1848,9 +1848,21 @@ <arg type="u" name="id" direction="out"/> </method> - <method name="loadConversationUntil" tp:name-for-bindings="loadConversationUntil"> - <tp:added version="10.0.0"/> - <tp:docstring> + <method name="loadConversation" tp:name-for-bindings="loadConversation"> + <tp:added version="14.0.0"/> + <tp:docstring> + Load messages from a conversation + </tp:docstring> + <arg type="s" name="accountId" direction="in"/> + <arg type="s" name="conversationId" direction="in"/> + <arg type="s" name="fromMessage" direction="in"/> + <arg type="u" name="n" direction="in"/> + <arg type="u" name="id" direction="out"/> + </method> + + <method name="loadConversationUntil" tp:name-for-bindings="loadConversationUntil"> + <tp:added version="10.0.0"/> + <tp:docstring> Load messages from a conversation </tp:docstring> <arg type="s" name="accountId" direction="in"/> @@ -1873,6 +1885,15 @@ <arg type="u" name="count" direction="out"/> </method> + <method name="clearCache" tp:name-for-bindings="clearCache"> + <tp:added version="14.0.0"/> + <tp:docstring> + Clear interactions loaded from daemon. Used by dbus to reload interactions + </tp:docstring> + <arg type="s" name="accountId" direction="in"/> + <arg type="s" name="conversationId" direction="in"/> + </method> + <method name="searchConversation" tp:name-for-bindings="searchConversation"> <tp:added version="13.4.0"/> <tp:docstring> @@ -1992,9 +2013,37 @@ </arg> </signal> - <signal name="messagesFound" tp:name-for-bindings="messagesFound"> - <tp:added version="10.0.0"/> - <tp:docstring> + <signal name="swarmLoaded" tp:name-for-bindings="swarmLoaded"> + <tp:added version="14.0.0"/> + <tp:docstring> + Notify clients when a conversation is loaded + </tp:docstring> + <arg type="u" name="id"> + <tp:docstring> + Id of the related loadConversationMessages's request + </tp:docstring> + </arg> + <arg type="s" name="account_id"> + <tp:docstring> + Account id related + </tp:docstring> + </arg> + <arg type="s" name="conversation_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="VectorSwarmMessage"/> + <arg type="a(sssa{ss}aa{ss}aa{ss})" name="messages"> + <tp:docstring> + Messages of the conversation + </tp:docstring> + </arg> + </signal> + + <signal name="messagesFound" tp:name-for-bindings="messagesFound"> + <tp:added version="10.0.0"/> + <tp:docstring> Notify clients when messages matching a regex are found </tp:docstring> <arg type="u" name="id"> @@ -2043,9 +2092,111 @@ </arg> </signal> - <signal name="conversationProfileUpdated" tp:name-for-bindings="conversationProfileUpdated"> - <tp:added version="13.4.0"/> - <tp:docstring> + <signal name="swarmMessageReceived" tp:name-for-bindings="swarmMessageReceived"> + <tp:added version="14.0.0"/> + <tp:docstring> + Notify clients when a conversation receives a new message + </tp:docstring> + <arg type="s" name="account_id"> + <tp:docstring> + Account id related + </tp:docstring> + </arg> + <arg type="s" name="conversation_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="SwarmMessage"/> + <arg type="(sssa{ss}aa{ss}aa{ss})" name="message"> + <tp:docstring> + The new message + </tp:docstring> + </arg> + </signal> + + <signal name="swarmMessageUpdated" tp:name-for-bindings="swarmMessageUpdated"> + <tp:added version="14.0.0"/> + <tp:docstring> + Notify clients when a conversation receives a new message + </tp:docstring> + <arg type="s" name="account_id"> + <tp:docstring> + Account id related + </tp:docstring> + </arg> + <arg type="s" name="conversation_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="SwarmMessage"/> + <arg type="(sssa{ss}aa{ss}aa{ss})" name="message"> + <tp:docstring> + The new message + </tp:docstring> + </arg> + </signal> + + <signal name="reactionAdded" tp:name-for-bindings="reactionAdded"> + <tp:added version="14.0.0"/> + <tp:docstring> + Notify clients when a conversation receives a new message + </tp:docstring> + <arg type="s" name="account_id"> + <tp:docstring> + Account id related + </tp:docstring> + </arg> + <arg type="s" name="conversation_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <arg type="s" name="message_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.Out3" value="MapStringString"/> + <arg type="a{ss}" name="reaction"> + <tp:docstring> + The new message + </tp:docstring> + </arg> + </signal> + + <signal name="reactionRemoved" tp:name-for-bindings="reactionRemoved"> + <tp:added version="14.0.0"/> + <tp:docstring> + Notify clients when a conversation receives a new message + </tp:docstring> + <arg type="s" name="account_id"> + <tp:docstring> + Account id related + </tp:docstring> + </arg> + <arg type="s" name="conversation_id"> + <tp:docstring> + Conversation id + </tp:docstring> + </arg> + <arg type="s" name="message_id"> + <tp:docstring> + Message's id + </tp:docstring> + </arg> + <arg type="s" name="reaction_id"> + <tp:docstring> + Reaction's id + </tp:docstring> + </arg> + </signal> + + + <signal name="conversationProfileUpdated" tp:name-for-bindings="conversationProfileUpdated"> + <tp:added version="13.4.0"/> + <tp:docstring> Notify clients when a conversation got its profile changed. </tp:docstring> <arg type="s" name="account_id"> diff --git a/bin/dbus/dbusconfigurationmanager.hpp b/bin/dbus/dbusconfigurationmanager.hpp index 8fddb461bfe834857a7e38674312fc7b75929c06..638d08fad8a7d69c6afe4b74a7d747d61e6c43b5 100644 --- a/bin/dbus/dbusconfigurationmanager.hpp +++ b/bin/dbus/dbusconfigurationmanager.hpp @@ -29,6 +29,7 @@ class DBusConfigurationManager : public sdbus::AdaptorInterfaces<cx::ring::Ring::ConfigurationManager_adaptor> { public: + using DBusSwarmMessage = sdbus::Struct<std::string, std::string, std::string, std::map<std::string, std::string>, std::vector<std::map<std::string, std::string>>, std::vector<std::map<std::string, std::string>>>; DBusConfigurationManager(sdbus::IConnection& connection) : AdaptorInterfaces(connection, "/cx/ring/Ring/ConfigurationManager") { @@ -931,6 +932,15 @@ public: return libjami::loadConversationMessages(accountId, conversationId, fromMessage, n); } + uint32_t + loadConversation(const std::string& accountId, + const std::string& conversationId, + const std::string& fromMessage, + const uint32_t& n) + { + return libjami::loadConversation(accountId, conversationId, fromMessage, n); + } + uint32_t loadConversationUntil(const std::string& accountId, const std::string& conversationId, @@ -950,6 +960,13 @@ public: return libjami::countInteractions(accountId, conversationId, toId, fromId, authorUri); } + void + clearCache(const std::string& accountId, + const std::string& conversationId) + { + return libjami::clearCache(accountId, conversationId); + } + uint32_t searchConversation(const std::string& accountId, const std::string& conversationId, @@ -1122,10 +1139,30 @@ private: const std::map<std::string, SharedCallback> convEvHandlers = { exportable_serialized_callback<ConversationSignal::ConversationLoaded>( std::bind(&DBusConfigurationManager::emitConversationLoaded, this, _1, _2, _3, _4)), + exportable_serialized_callback<ConversationSignal::SwarmLoaded>([this](const uint32_t& id, const std::string& account_id, const std::string& conversation_id, const std::vector<libjami::SwarmMessage>& messages) { + std::vector<DBusSwarmMessage> msgList; + for (const auto& message: messages) { + DBusSwarmMessage msg {message.id, message.type, message.linearizedParent, message.body, message.reactions, message.editions}; + msgList.push_back(msg); + } + DBusConfigurationManager::emitSwarmLoaded(id, account_id, conversation_id, msgList); + }), exportable_serialized_callback<ConversationSignal::MessagesFound>( std::bind(&DBusConfigurationManager::emitMessagesFound, this, _1, _2, _3, _4)), exportable_serialized_callback<ConversationSignal::MessageReceived>( std::bind(&DBusConfigurationManager::emitMessageReceived, this, _1, _2, _3)), + exportable_serialized_callback<ConversationSignal::SwarmMessageReceived>([this](const std::string& account_id, const std::string& conversation_id, const libjami::SwarmMessage& message) { + DBusSwarmMessage msg {message.id, message.type, message.linearizedParent, message.body, message.reactions, message.editions}; + DBusConfigurationManager::emitSwarmMessageReceived(account_id, conversation_id, msg); + }), + exportable_serialized_callback<ConversationSignal::SwarmMessageUpdated>([this](const std::string& account_id, const std::string& conversation_id, const libjami::SwarmMessage& message) { + DBusSwarmMessage msg {message.id, message.type, message.linearizedParent, message.body, message.reactions, message.editions}; + DBusConfigurationManager::emitSwarmMessageUpdated(account_id, conversation_id, msg); + }), + exportable_serialized_callback<ConversationSignal::ReactionAdded>( + std::bind(&DBusConfigurationManager::emitReactionAdded, this, _1, _2, _3, _4)), + exportable_serialized_callback<ConversationSignal::ReactionRemoved>( + std::bind(&DBusConfigurationManager::emitReactionRemoved, this, _1, _2, _3, _4)), exportable_serialized_callback<ConversationSignal::ConversationProfileUpdated>( std::bind(&DBusConfigurationManager::emitConversationProfileUpdated, this, _1, _2, _3)), exportable_serialized_callback<ConversationSignal::ConversationRequestReceived>( diff --git a/bin/jni/conversation.i b/bin/jni/conversation.i index 30c10efdee0ae93dcb6c89e42bfc9d187aa3601d..fdecb07e2ed4b20922d1bc4c68a454a3a41e9ba4 100644 --- a/bin/jni/conversation.i +++ b/bin/jni/conversation.i @@ -26,8 +26,13 @@ class ConversationCallback { public: virtual ~ConversationCallback(){} virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} + virtual void swarmLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<libjami::SwarmMessage> /*messages*/){} virtual void messagesFound(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){} + virtual void swarmMessageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void swarmMessageUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void reactionAdded(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, std::map<std::string, std::string> /*reaction*/){} + virtual void reactionRemoved(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, const std::string& /* reactionId */){} virtual void conversationProfileUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*profile*/){} virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){} virtual void conversationRequestDeclined(const std::string& /*accountId*/, const std::string& /* conversationId */){} @@ -43,6 +48,16 @@ public: namespace libjami { +struct SwarmMessage +{ + std::string id; + std::string type; + std::string linearizedParent; + std::map<std::string, std::string> body; + std::vector<std::map<std::string, std::string>> reactions; + std::vector<std::map<std::string, std::string>> editions; +}; + // Conversation management std::string startConversation(const std::string& accountId); void acceptConversationRequest(const std::string& accountId, const std::string& conversationId); @@ -64,8 +79,10 @@ namespace libjami { // Message send/load void sendMessage(const std::string& accountId, const std::string& conversationId, const std::string& message, const std::string& replyTo, const int32_t& flag); uint32_t loadConversationMessages(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n); + uint32_t loadConversation(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n); uint32_t loadConversationUntil(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, const std::string& toMessage); uint32_t countInteractions(const std::string& accountId, const std::string& conversationId, const std::string& toId, const std::string& fromId, const std::string& authorUri); + void clearCache(const std::string& accountId, const std::string& conversationId); uint32_t searchConversation(const std::string& accountId, const std::string& conversationId, const std::string& author, @@ -82,8 +99,13 @@ class ConversationCallback { public: virtual ~ConversationCallback(){} virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} + virtual void swarmLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<libjami::SwarmMessage> /*messages*/){} virtual void messagesFound(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){} + virtual void swarmMessageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void swarmMessageUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void reactionAdded(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, std::map<std::string, std::string> /*messageId*/){} + virtual void reactionRemoved(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, const std::string& /* reactionId */){} virtual void conversationProfileUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*profile*/){} virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){} virtual void conversationRequestDeclined(const std::string& /*accountId*/, const std::string& /* conversationId */){} diff --git a/bin/jni/jni_interface.i b/bin/jni/jni_interface.i index 6b549324d90339f51c3469e762e59c63ced7bd50..9e54cda7589e851da117ee7c5201694ef00a2da2 100644 --- a/bin/jni/jni_interface.i +++ b/bin/jni/jni_interface.i @@ -325,8 +325,13 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM const std::map<std::string, SharedCallback> conversationHandlers = { exportable_callback<ConversationSignal::ConversationLoaded>(bind(&ConversationCallback::conversationLoaded, convM, _1, _2, _3, _4)), + exportable_callback<ConversationSignal::SwarmLoaded>(bind(&ConversationCallback::swarmLoaded, convM, _1, _2, _3, _4)), exportable_callback<ConversationSignal::MessagesFound>(bind(&ConversationCallback::messagesFound, convM, _1, _2, _3, _4)), exportable_callback<ConversationSignal::MessageReceived>(bind(&ConversationCallback::messageReceived, convM, _1, _2, _3)), + exportable_callback<ConversationSignal::SwarmMessageReceived>(bind(&ConversationCallback::swarmMessageReceived, convM, _1, _2, _3)), + exportable_callback<ConversationSignal::SwarmMessageUpdated>(bind(&ConversationCallback::swarmMessageUpdated, convM, _1, _2, _3)), + exportable_callback<ConversationSignal::ReactionAdded>(bind(&ConversationCallback::reactionAdded, convM, _1, _2, _3, _4)), + exportable_callback<ConversationSignal::ReactionRemoved>(bind(&ConversationCallback::reactionRemoved, convM, _1, _2, _3, _4)), exportable_callback<ConversationSignal::ConversationProfileUpdated>(bind(&ConversationCallback::conversationProfileUpdated, convM, _1, _2, _3)), exportable_callback<ConversationSignal::ConversationRequestReceived>(bind(&ConversationCallback::conversationRequestReceived, convM, _1, _2, _3)), exportable_callback<ConversationSignal::ConversationRequestDeclined>(bind(&ConversationCallback::conversationRequestDeclined, convM, _1, _2)), diff --git a/bin/nodejs/callback.h b/bin/nodejs/callback.h index 7b2a4d69b2a75e1c79522a45a1d5428ed012f041..154d6d77d66fc332fb36879c00cfb551dfcf80c4 100644 --- a/bin/nodejs/callback.h +++ b/bin/nodejs/callback.h @@ -31,8 +31,10 @@ Persistent<Function> incomingMessageCb; Persistent<Function> incomingCallCb; Persistent<Function> incomingCallWithMediaCb; Persistent<Function> conversationLoadedCb; +Persistent<Function> swarmLoadedCb; Persistent<Function> messagesFoundCb; Persistent<Function> messageReceivedCb; +Persistent<Function> swarmMessageReceivedCb; Persistent<Function> conversationProfileUpdatedCb; Persistent<Function> conversationRequestReceivedCb; Persistent<Function> conversationRequestDeclinedCb; @@ -99,10 +101,14 @@ getPresistentCb(std::string_view signal) return &incomingCallWithMediaCb; else if (signal == "ConversationLoaded") return &conversationLoadedCb; + else if (signal == "SwarmLoaded") + return &swarmLoadedCb; else if (signal == "MessagesFound") return &messagesFoundCb; else if (signal == "MessageReceived") return &messageReceivedCb; + else if (signal == "SwarmMessageReceived") + return &swarmMessageReceivedCb; else if (signal == "ConversationProfileUpdated") return &conversationProfileUpdatedCb; else if (signal == "ConversationReady") diff --git a/bin/nodejs/conversation.i b/bin/nodejs/conversation.i index 803fcd3b229d9f2ca8373b270be20f8878fb131a..6673a8c4e34a1e405c22959c4cea4dfc980be4ab 100644 --- a/bin/nodejs/conversation.i +++ b/bin/nodejs/conversation.i @@ -26,8 +26,13 @@ class ConversationCallback { public: virtual ~ConversationCallback(){} virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} + virtual void swarmLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<libjami::SwarmMessage> /*messages*/){} virtual void messagesFound(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){} + virtual void swarmMessageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void swarmMessageUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void reactionAdded(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, std::map<std::string, std::string> /*reaction*/){} + virtual void reactionRemoved(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, const std::string& /* reactionId */){} virtual void conversationProfileUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*profile*/){} virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){} virtual void conversationRequestDeclined(const std::string& /*accountId*/, const std::string& /* conversationId */){} @@ -43,6 +48,16 @@ public: namespace libjami { +struct SwarmMessage +{ + std::string id; + std::string type; + std::string linearizedParent; + std::map<std::string, std::string> body; + std::vector<std::map<std::string, std::string>> reactions; + std::vector<std::map<std::string, std::string>> editions; +}; + // Conversation management std::string startConversation(const std::string& accountId); void acceptConversationRequest(const std::string& accountId, const std::string& conversationId); @@ -64,7 +79,9 @@ namespace libjami { // Message send/load void sendMessage(const std::string& accountId, const std::string& conversationId, const std::string& message, const std::string& replyTo, const int32_t& flag); uint32_t loadConversationMessages(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n); + uint32_t loadConversation(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n); uint32_t loadConversationUntil(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, const std::string& toMessage); + void clearCache(const std::string& accountId, const std::string& conversationId); uint32_t countInteractions(const std::string& accountId, const std::string& conversationId, const std::string& toId, const std::string& fromId, const std::string& authorUri); uint32_t searchConversation(const std::string& accountId, const std::string& conversationId, @@ -83,8 +100,13 @@ class ConversationCallback { public: virtual ~ConversationCallback(){} virtual void conversationLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} + virtual void swarmLoaded(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<libjami::SwarmMessage> /*messages*/){} virtual void messagesFound(uint32_t /* id */, const std::string& /*accountId*/, const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/){} virtual void messageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/){} + virtual void swarmMessageReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void swarmMessageUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, const libjami::SwarmMessage& /*message*/){} + virtual void reactionAdded(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, std::map<std::string, std::string> /*reaction*/){} + virtual void reactionRemoved(const std::string& /*accountId*/, const std::string& /* conversationId */, const std::string& /* messageId */, const std::string& /* reactionId */){} virtual void conversationProfileUpdated(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*profile*/){} virtual void conversationRequestReceived(const std::string& /*accountId*/, const std::string& /* conversationId */, std::map<std::string, std::string> /*metadatas*/){} virtual void conversationRequestDeclined(const std::string& /*accountId*/, const std::string& /* conversationId */){} diff --git a/bin/nodejs/nodejs_interface.i b/bin/nodejs/nodejs_interface.i index 13a3d911cfa140966bcaecd21513bf965aeceead..42a73c39eaecc8acce7ef88367eb035e7ce9dd45 100644 --- a/bin/nodejs/nodejs_interface.i +++ b/bin/nodejs/nodejs_interface.i @@ -150,8 +150,13 @@ void init(const SWIGV8_VALUE& funcMap){ const std::map<std::string, SharedCallback> conversationHandlers = { exportable_callback<ConversationSignal::ConversationLoaded>(bind(&conversationLoaded, _1, _2, _3, _4)), + exportable_callback<ConversationSignal::SwarmLoaded>(bind(&swarmLoaded, _1, _2, _3, _4)), exportable_callback<ConversationSignal::MessagesFound>(bind(&messagesFound, _1, _2, _3, _4)), exportable_callback<ConversationSignal::MessageReceived>(bind(&messageReceived, _1, _2, _3)), + exportable_callback<ConversationSignal::SwarmMessageReceived>(bind(&swarmMessageReceived, _1, _2, _3)), + exportable_callback<ConversationSignal::SwarmMessageUpdated>(bind(&swarmMessageUpdated, _1, _2, _3)), + exportable_callback<ConversationSignal::ReactionAdded>(bind(&reactionAdded, _1, _2, _3, _4)), + exportable_callback<ConversationSignal::ReactionRemoved>(bind(&reactionRemoved, _1, _2, _3, _4)), exportable_callback<ConversationSignal::ConversationProfileUpdated>(bind(&conversationProfileUpdated, _1, _2, _3)), exportable_callback<ConversationSignal::ConversationRequestReceived>(bind(&conversationRequestReceived, _1, _2, _3)), exportable_callback<ConversationSignal::ConversationRequestDeclined>(bind(&conversationRequestDeclined, _1, _2)), diff --git a/configure.ac b/configure.ac index f94bf70f779775da81a8f2d8d327b5012dbeef31..5c7467037ee207374a9c8b3826243a01699b98b0 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Jami - configure.ac dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([Jami Daemon],[13.11.0],[jami@gnu.org],[jami]) +AC_INIT([Jami Daemon],[14.0.0],[jami@gnu.org],[jami]) dnl Clear the implicit flags that default to '-g -O2', otherwise they dnl take precedence over the values we set via the diff --git a/meson.build b/meson.build index 73c16b77456bf43885c5c9ea7da960964a61dcca..97ae791a12169ad7488f29df30379dbb5a390e42 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('jami-daemon', ['c', 'cpp'], - version: '13.11.0', + version: '14.0.0', license: 'GPL3+', default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'], meson_version:'>= 0.56' diff --git a/src/client/conversation_interface.cpp b/src/client/conversation_interface.cpp index 661832b96f6d53e832c7649446b60d3f47b95043..0fb86ab66a6668a016509d0312aee4d61a96d231 100644 --- a/src/client/conversation_interface.cpp +++ b/src/client/conversation_interface.cpp @@ -195,6 +195,18 @@ loadConversationMessages(const std::string& accountId, return 0; } +uint32_t +loadConversation(const std::string& accountId, + const std::string& conversationId, + const std::string& fromMessage, + size_t n) +{ + if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) + if (auto convModule = acc->convModule()) + return convModule->loadConversation(conversationId, fromMessage, n); + return 0; +} + uint32_t loadConversationUntil(const std::string& accountId, const std::string& conversationId, @@ -220,6 +232,14 @@ countInteractions(const std::string& accountId, return 0; } +void +clearCache(const std::string& accountId, const std::string& conversationId) +{ + if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) + if (auto convModule = acc->convModule()) + convModule->clearCache(conversationId); +} + uint32_t searchConversation(const std::string& accountId, const std::string& conversationId, diff --git a/src/client/ring_signal.cpp b/src/client/ring_signal.cpp index 5576d32b3d439765536be15d728d45bbd6195a42..9d86696ca93fa65fc94173dd86b96910c25085b3 100644 --- a/src/client/ring_signal.cpp +++ b/src/client/ring_signal.cpp @@ -129,8 +129,13 @@ getSignalHandlers() /* Conversation */ exported_callback<libjami::ConversationSignal::ConversationLoaded>(), + exported_callback<libjami::ConversationSignal::SwarmLoaded>(), exported_callback<libjami::ConversationSignal::MessagesFound>(), exported_callback<libjami::ConversationSignal::MessageReceived>(), + exported_callback<libjami::ConversationSignal::SwarmMessageReceived>(), + exported_callback<libjami::ConversationSignal::SwarmMessageUpdated>(), + exported_callback<libjami::ConversationSignal::ReactionAdded>(), + exported_callback<libjami::ConversationSignal::ReactionRemoved>(), exported_callback<libjami::ConversationSignal::ConversationProfileUpdated>(), exported_callback<libjami::ConversationSignal::ConversationRequestReceived>(), exported_callback<libjami::ConversationSignal::ConversationRequestDeclined>(), diff --git a/src/jami/conversation_interface.h b/src/jami/conversation_interface.h index aed802231ec25c12b49755691f1c27476962bb1a..26d932c775a89fb6ab7676ccf572d0934c374bb9 100644 --- a/src/jami/conversation_interface.h +++ b/src/jami/conversation_interface.h @@ -26,11 +26,28 @@ #include <vector> #include <map> #include <string> +#include <list> #include "jami.h" namespace libjami { +struct SwarmMessage +{ + std::string id; + std::string type; + std::string linearizedParent; + std::map<std::string, std::string> body; + std::vector<std::map<std::string, std::string>> reactions; + std::vector<std::map<std::string, std::string>> editions; + + void fromMapStringString(const std::map<std::string, std::string>& commit) { + id = commit.at("id"); + type = commit.at("type"); + body = commit; // TODO erase type/id? + } +}; + // Conversation management LIBJAMI_PUBLIC std::string startConversation(const std::string& accountId); LIBJAMI_PUBLIC void acceptConversationRequest(const std::string& accountId, @@ -79,6 +96,10 @@ LIBJAMI_PUBLIC uint32_t loadConversationMessages(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, size_t n); +LIBJAMI_PUBLIC uint32_t loadConversation(const std::string& accountId, + const std::string& conversationId, + const std::string& fromMessage, + size_t n); LIBJAMI_PUBLIC uint32_t loadConversationUntil(const std::string& accountId, const std::string& conversationId, const std::string& fromMessage, @@ -88,6 +109,7 @@ LIBJAMI_PUBLIC uint32_t countInteractions(const std::string& accountId, const std::string& toId, const std::string& fromId, const std::string& authorUri); +LIBJAMI_PUBLIC void clearCache(const std::string& accountId, const std::string& conversationId); LIBJAMI_PUBLIC uint32_t searchConversation(const std::string& accountId, const std::string& conversationId, const std::string& author, @@ -110,6 +132,14 @@ struct LIBJAMI_PUBLIC ConversationSignal const std::string& /* conversationId */, std::vector<std::map<std::string, std::string>> /*messages*/); }; + struct LIBJAMI_PUBLIC SwarmLoaded + { + constexpr static const char* name = "SwarmLoaded"; + using cb_type = void(uint32_t /* id */, + const std::string& /*accountId*/, + const std::string& /* conversationId */, + std::vector<SwarmMessage> /*messages*/); + }; struct LIBJAMI_PUBLIC MessagesFound { constexpr static const char* name = "MessagesFound"; @@ -125,6 +155,36 @@ struct LIBJAMI_PUBLIC ConversationSignal const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/); }; + struct LIBJAMI_PUBLIC SwarmMessageReceived + { + constexpr static const char* name = "SwarmMessageReceived"; + using cb_type = void(const std::string& /*accountId*/, + const std::string& /* conversationId */, + const SwarmMessage& /*message*/); + }; + struct LIBJAMI_PUBLIC SwarmMessageUpdated + { + constexpr static const char* name = "SwarmMessageUpdated"; + using cb_type = void(const std::string& /*accountId*/, + const std::string& /* conversationId */, + const SwarmMessage& /*message*/); + }; + struct LIBJAMI_PUBLIC ReactionAdded + { + constexpr static const char* name = "ReactionAdded"; + using cb_type = void(const std::string& /*accountId*/, + const std::string& /* conversationId */, + const std::string& /* messageId */, + std::map<std::string, std::string> /*reaction*/); + }; + struct LIBJAMI_PUBLIC ReactionRemoved + { + constexpr static const char* name = "ReactionRemoved"; + using cb_type = void(const std::string& /*accountId*/, + const std::string& /* conversationId */, + const std::string& /* messageId */, + const std::string& /* reactionId */); + }; struct LIBJAMI_PUBLIC ConversationProfileUpdated { constexpr static const char* name = "ConversationProfileUpdated"; diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index 629c115d8367301321d88e7043710e49d8690349..0d72a0e5be0c8893f58539840521ce9f23fea18d 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -29,12 +29,14 @@ #include <string_view> #include <opendht/thread_pool.h> #include <tuple> +#include <optional> #include "swarm/swarm_manager.h" #ifdef ENABLE_PLUGIN #include "manager.h" #include "plugin/jamipluginmanager.h" #include "plugin/streamdata.h" #endif +#include "jami/conversation_interface.h" namespace jami { @@ -119,6 +121,16 @@ ConversationRequest::toMap() const return result; } +using MessageList = std::list<std::shared_ptr<libjami::SwarmMessage>>; + +struct History +{ + MessageList messageList {}; + std::map<std::string, std::shared_ptr<libjami::SwarmMessage>> quickAccess {}; + std::map<std::string, std::list<std::shared_ptr<libjami::SwarmMessage>>> pendingEditions {}; + std::map<std::string, std::list<std::map<std::string, std::string>>> pendingReactions {}; +}; + class Conversation::Impl { public: @@ -369,6 +381,7 @@ public: auto convId = repository_->id(); auto ok = !commits.empty(); auto lastId = ok ? commits.rbegin()->at(ConversationMapKeys::ID) : ""; + addToHistory(commits, true); if (ok) { bool announceMember = false; for (const auto& c : commits) { @@ -602,6 +615,7 @@ public: std::weak_ptr<JamiAccount> account_; std::atomic_bool isRemoving_ {false}; std::vector<std::map<std::string, std::string>> loadMessages(const LogOptions& options); + std::vector<libjami::SwarmMessage> loadMessages2(const LogOptions& options, History* optHistory = nullptr); void pull(); std::vector<std::map<std::string, std::string>> mergeHistory(const std::string& uri); @@ -642,6 +656,24 @@ public: std::unique_ptr<asio::steady_timer> fallbackTimer_; bool isMobile {false}; + + /** + * Loaded history represents the linearized history to show for clients + */ + mutable History loadedHistory_ {}; + std::vector<libjami::SwarmMessage> addToHistory(const std::vector<std::map<std::string, std::string>>& commits, + bool messageReceived = false, + History* history = nullptr) const; + // While loading the history, we need to avoid: + // - reloading history (can just be ignored) + // - adding new commits (should wait for history to be loaded) + bool isLoadingHistory_ {false}; + mutable std::mutex historyMtx_ {}; + mutable std::condition_variable historyCv_ {}; + + void handleReaction(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit) const; + void handleEdition(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit, bool messageReceived) const; + bool handleMessage(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit, bool messageReceived) const; }; bool @@ -738,9 +770,280 @@ Conversation::Impl::loadMessages(const LogOptions& options) { if (!repository_) return {}; - std::vector<ConversationCommit> convCommits; - convCommits = repository_->log(options); - return repository_->convCommitToMap(convCommits); + std::vector<ConversationCommit> commits; + auto startLogging = options.from == ""; + auto breakLogging = false; + repository_->log([&](const auto& id, const auto& author, const auto& commit) { + if (!commits.empty()) { + // Set linearized parent + commits.rbegin()->linearized_parent = id; + } + if (options.skipMerge && git_commit_parentcount(commit.get()) > 1) { + return CallbackResult::Skip; + } + if ((options.nbOfCommits != 0 + && commits.size() == options.nbOfCommits)) + return CallbackResult::Break; // Stop logging + if (breakLogging) + return CallbackResult::Break; // Stop logging + if (id == options.to) { + if (options.includeTo) + breakLogging = true; // For the next commit + else + return CallbackResult::Break; // Stop logging + } + + if (!startLogging && options.from != "" && options.from == id) + startLogging = true; + if (!startLogging) + return CallbackResult::Skip; // Start logging after this one + + if (options.fastLog) { + if (options.authorUri != "") { + if (options.authorUri == repository_->uriFromDevice(author.email)) { + return CallbackResult::Break; // Found author, stop + } + } + // Used to only count commit + commits.emplace(commits.end(), ConversationCommit {}); + return CallbackResult::Skip; + } + + return CallbackResult::Ok; // Continue + }, + [&](auto&& cc) { + commits.emplace(commits.end(), std::forward<decltype(cc)>(cc)); + }, + [](auto, auto, auto) { return false; }, + options.from, + options.logIfNotFound); + return repository_->convCommitToMap(commits); +} + +std::vector<libjami::SwarmMessage> +Conversation::Impl::loadMessages2(const LogOptions& options, History* optHistory) +{ + { + std::lock_guard<std::mutex> lock(historyMtx_); + if (!repository_ || (!optHistory && isLoadingHistory_)) + return {}; + if (!optHistory) + isLoadingHistory_ = true; + } + + auto startLogging = options.from == ""; + auto breakLogging = false; + auto currentHistorySize = loadedHistory_.messageList.size(); + std::vector<std::string> replies; + std::vector<libjami::SwarmMessage> ret; + repository_->log([&](const auto& id, const auto& author, const auto& commit) { + if (options.skipMerge && git_commit_parentcount(commit.get()) > 1) { + return CallbackResult::Skip; + } + if (replies.empty()) { // This avoid load until + // NOTE: in the future, we may want to add "Reply-Body" in commit to avoid to load until this commit + if ((options.nbOfCommits != 0 + && (loadedHistory_.messageList.size() - currentHistorySize) == options.nbOfCommits)) + return CallbackResult::Break; // Stop logging + if (breakLogging) + return CallbackResult::Break; // Stop logging + if (id == options.to) { + if (options.includeTo) + breakLogging = true; // For the next commit + else + return CallbackResult::Break; // Stop logging + } + } + + if (!startLogging && options.from != "" && options.from == id) + startLogging = true; + if (!startLogging) + return CallbackResult::Skip; // Start logging after this one + + if (options.fastLog) { + if (options.authorUri != "") { + if (options.authorUri == repository_->uriFromDevice(author.email)) { + return CallbackResult::Break; // Found author, stop + } + } + } + + return CallbackResult::Ok; // Continue + }, + [&](auto&& cc) { + std::map<std::string, std::string> map = *repository_->convCommitToMap(cc); + if (map.find("reply-to") != map.end()) { + replies.emplace_back(map.at("reply-to")); + } + auto it = std::find(replies.begin(), replies.end(), map.at("id")); + if (it != replies.end()) { + replies.erase(it); + } + auto added = addToHistory({map}, false, optHistory); + ret.insert(ret.end(), added.begin(), added.end()); + }, + [](auto, auto, auto) { return false; }, + options.from, + options.logIfNotFound); + + if (!optHistory) { + std::lock_guard<std::mutex> lock(historyMtx_); + isLoadingHistory_ = false; + historyCv_.notify_all(); + } + + return ret; +} + +void +Conversation::Impl::handleReaction(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit) const +{ + auto it = history.quickAccess.find(sharedCommit->body.at("react-to")); + auto peditIt = history.pendingEditions.find(sharedCommit->id); + if (peditIt != history.pendingEditions.end()) { + auto oldBody = sharedCommit->body; + sharedCommit->body["body"] = peditIt->second.front()->body["body"]; + if (sharedCommit->body.at("body").empty()) + return; + history.pendingEditions.erase(peditIt); + } + if (it != history.quickAccess.end()) { + it->second->reactions.emplace_back(sharedCommit->body); + emitSignal<libjami::ConversationSignal::ReactionAdded>(accountId_, repository_->id(), it->second->id, sharedCommit->body); + } else { + history.pendingReactions[sharedCommit->body.at("react-to")].emplace_back(sharedCommit->body); + } +} + +void +Conversation::Impl::handleEdition(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit, bool messageReceived) const +{ + auto editId = sharedCommit->body.at("edit"); + auto it = history.quickAccess.find(editId); + if (it != history.quickAccess.end()) { + auto baseCommit = it->second; + if (baseCommit) { + auto itReact = baseCommit->body.find("react-to"); + auto body = sharedCommit->body.at("body"); + // Edit reaction + if (itReact != baseCommit->body.end()) { + baseCommit->body["body"] = body; // Replace body if pending + it = history.quickAccess.find(itReact->second); + auto itPending = history.pendingReactions.find(itReact->second); + if (it != history.quickAccess.end()) { + baseCommit = it->second; // Base commit + auto itPreviousReact = std::find_if(baseCommit->reactions.begin(), baseCommit->reactions.end(), [&](const auto& reaction) { + return reaction.at("id") == editId; + }); + if (itPreviousReact != baseCommit->reactions.end()) { + (*itPreviousReact)["body"] = body; + if (body.empty()) { + baseCommit->reactions.erase(itPreviousReact); + emitSignal<libjami::ConversationSignal::ReactionRemoved>(accountId_, repository_->id(), baseCommit->id, editId); + } + } + } else if (itPending != history.pendingReactions.end()) { + // Else edit if pending + auto itReaction = std::find_if(itPending->second.begin(), itPending->second.end(), [&](const auto& reaction) { + return reaction.at("id") == editId; + }); + if (itReaction != itPending->second.end()) { + (*itReaction)["body"] = body; + if (body.empty()) + itPending->second.erase(itReaction); + } + } else { + // Add to pending edtions + messageReceived? history.pendingEditions[editId].emplace_front(sharedCommit) + : history.pendingEditions[editId].emplace_back(sharedCommit); + } + } else { + // Normal message + it->second->editions.emplace(it->second->editions.begin(), it->second->body); + it->second->body["body"] = sharedCommit->body["body"]; + emitSignal<libjami::ConversationSignal::SwarmMessageUpdated>(accountId_, repository_->id(), *it->second); + } + } + } else { + messageReceived? history.pendingEditions[editId].emplace_front(sharedCommit) + : history.pendingEditions[editId].emplace_back(sharedCommit); + } +} + +bool +Conversation::Impl::handleMessage(History& history, const std::shared_ptr<libjami::SwarmMessage>& sharedCommit, bool messageReceived) const +{ + if (messageReceived) { + // For a received message, we place it at the beginning of the list + if (!history.messageList.empty()) + sharedCommit->linearizedParent = (*history.messageList.begin())->id; + history.messageList.emplace_front(sharedCommit); + } else { + // For a loaded message, we load from newest to oldest + // So we change the parent of the last message. + if (!history.messageList.empty()) + (*history.messageList.rbegin())->linearizedParent = sharedCommit->id; + history.messageList.emplace_back(sharedCommit); + } + // Handle pending reactions/editions + auto reactIt = history.pendingReactions.find(sharedCommit->id); + if (reactIt != history.pendingReactions.end()) { + for (const auto& commitBody: reactIt->second) + sharedCommit->reactions.emplace_back(commitBody); + history.pendingReactions.erase(reactIt); + } + auto peditIt = history.pendingEditions.find(sharedCommit->id); + if (peditIt != history.pendingEditions.end()) { + auto oldBody = sharedCommit->body; + sharedCommit->body["body"] = peditIt->second.front()->body["body"]; + peditIt->second.pop_front(); + for (const auto& commit: peditIt->second) { + sharedCommit->editions.emplace_back(commit->body); + } + sharedCommit->editions.emplace_back(oldBody); + history.pendingEditions.erase(peditIt); + } + // Announce to client + if (messageReceived) + emitSignal<libjami::ConversationSignal::SwarmMessageReceived>(accountId_, repository_->id(), *sharedCommit); + return !messageReceived; +} + +std::vector<libjami::SwarmMessage> +Conversation::Impl::addToHistory(const std::vector<std::map<std::string, std::string>>& commits, bool messageReceived, History* optHistory) const +{ + if (messageReceived && (!optHistory && isLoadingHistory_)) { + std::unique_lock<std::mutex> lk(historyMtx_); + historyCv_.wait(lk, [&] { return !isLoadingHistory_; }); + } + std::vector<libjami::SwarmMessage> messages; + auto addCommit = [&](const auto& commit) { + auto* history = optHistory ? optHistory : &loadedHistory_; + auto commitId = commit.at("id"); + if (history->quickAccess.find(commitId) != history->quickAccess.end()) + return; // Already present + auto typeIt = commit.find("type"); + auto reactToIt = commit.find("react-to"); + auto editIt = commit.find("edit"); + // Nothing to show for the client, skip + if (typeIt != commit.end() && typeIt->second == "merge") + return; + + auto sharedCommit = std::make_shared<libjami::SwarmMessage>(); + sharedCommit->fromMapStringString(commit); + history->quickAccess[commitId] = sharedCommit; + + if (reactToIt != commit.end() && !reactToIt->second.empty()) { + handleReaction(*history, sharedCommit); + } else if (editIt != commit.end() && !editIt->second.empty()) { + handleEdition(*history, sharedCommit, messageReceived); + } else if (handleMessage(*history, sharedCommit, messageReceived)) { + messages.emplace_back(*sharedCommit); + } + }; + std::for_each(commits.begin(), commits.end(), addCommit); + + return messages; } Conversation::Conversation(const std::shared_ptr<JamiAccount>& account, @@ -1178,7 +1481,7 @@ Conversation::getCommit(const std::string& commitId) const } void -Conversation::loadMessages(const OnLoadMessages& cb, const LogOptions& options) +Conversation::loadMessages(OnLoadMessages cb, const LogOptions& options) { if (!cb) return; @@ -1189,6 +1492,27 @@ Conversation::loadMessages(const OnLoadMessages& cb, const LogOptions& options) }); } +void +Conversation::loadMessages2(const OnLoadMessages2& cb, const LogOptions& options) +{ + if (!cb) + return; + dht::ThreadPool::io().run([w = weak(), cb = std::move(cb), options] { + if (auto sthis = w.lock()) { + cb(sthis->pimpl_->loadMessages2(options)); + } + }); +} + +void +Conversation::clearCache() +{ + pimpl_->loadedHistory_.messageList.clear(); + pimpl_->loadedHistory_.quickAccess.clear(); + pimpl_->loadedHistory_.pendingEditions.clear(); + pimpl_->loadedHistory_.pendingReactions.clear(); +} + std::string Conversation::lastCommitId() const { @@ -1976,14 +2300,15 @@ Conversation::countInteractions(const std::string& toId, const std::string& fromId, const std::string& authorUri) const { - // Log but without content to avoid costly convertions. LogOptions options; options.to = toId; options.from = fromId; options.authorUri = authorUri; options.logIfNotFound = false; options.fastLog = true; - return pimpl_->repository_->log(options).size(); + History history; + auto res = pimpl_->loadMessages2(options, &history); + return res.size(); } void @@ -1998,7 +2323,74 @@ Conversation::search(uint32_t req, auto acc = sthis->pimpl_->account_.lock(); if (!acc) return; - auto commits = sthis->pimpl_->repository_->search(filter); + + History history; + std::vector<std::map<std::string, std::string>> commits {}; + // std::regex_constants::ECMAScript is the default flag. + auto re = std::regex(filter.regexSearch, + filter.caseSensitive ? std::regex_constants::ECMAScript + : std::regex_constants::icase); + sthis->pimpl_->repository_->log([&](const auto& id, const auto& author, auto& commit) { + if (!filter.author.empty() && filter.author != sthis->uriFromDevice(author.email)) { + // Filter author + return CallbackResult::Skip; + } + auto commitTime = git_commit_time(commit.get()); + if (filter.before && filter.before < commitTime) { + // Only get commits before this date + return CallbackResult::Skip; + } + if (filter.after && filter.after > commitTime) { + // Only get commits before this date + if (git_commit_parentcount(commit.get()) <= 1) + return CallbackResult::Break; + else + return CallbackResult::Skip; // Because we are sorting it with + // GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME + } + + return CallbackResult::Ok; // Continue + }, + [&](auto&& cc) { + sthis->pimpl_->addToHistory({*sthis->pimpl_->repository_->convCommitToMap(cc)}, false, &history); + }, + [&](auto id, auto, auto) { + if (id == filter.lastId) + return true; + return false; + }, + "", + false); + // Search on generated history + for (auto& message : history.messageList) { + auto contentType = message->type; + auto isSearchable = contentType == "text/plain" + || contentType == "application/data-transfer+json"; + if (filter.type.empty() && !isSearchable) { + // Not searchable, at least for now + continue; + } else if (contentType == filter.type || filter.type.empty()) { + if (isSearchable) { + // If it's a text match the body, else the display name + auto body = contentType == "text/plain" ? message->body.at("body") + : message->body.at("displayName"); + std::smatch body_match; + if (std::regex_search(body, body_match, re)) { + auto commit = message->body; + commit["id"] = message->id; + commit["type"] = message->type; + commits.emplace_back(commit); + } + } else { + // Matching type, just add it to the results + commits.emplace_back(message->body); + } + + if (filter.maxResult != 0 && commits.size() == filter.maxResult) + break; + } + } + if (commits.size() > 0) emitSignal<libjami::ConversationSignal::MessagesFound>(req, acc->getAccountID(), diff --git a/src/jamidht/conversation.h b/src/jamidht/conversation.h index 3d883ad5c8481c9896689c298301babc3568c4a6..55c4b44c75f06deeeb1828da7b310a6cb05f9bfb 100644 --- a/src/jamidht/conversation.h +++ b/src/jamidht/conversation.h @@ -22,6 +22,7 @@ #include "jamidht/conversationrepository.h" #include "conversationrepository.h" #include "swarm/swarm_protocol.h" +#include "jami/conversation_interface.h" #include <json/json.h> #include <msgpack.hpp> @@ -134,6 +135,8 @@ enum class ConversationMode; using OnPullCb = std::function<void(bool fetchOk)>; using OnLoadMessages = std::function<void(std::vector<std::map<std::string, std::string>>&& messages)>; +using OnLoadMessages2 + = std::function<void(std::vector<libjami::SwarmMessage>&& messages)>; using OnCommitCb = std::function<void(const std::string&)>; using OnDoneCb = std::function<void(bool, const std::string&)>; using OnMultiDoneCb = std::function<void(const std::vector<std::string>&)>; @@ -296,7 +299,17 @@ public: * @param cb The callback when loaded * @param options The log options */ - void loadMessages(const OnLoadMessages& cb, const LogOptions& options); + void loadMessages(OnLoadMessages cb, const LogOptions& options); + /** + * Get a range of messages + * @param cb The callback when loaded + * @param options The log options + */ + void loadMessages2(const OnLoadMessages2& cb, const LogOptions& options); + /** + * Clear all cached messages + */ + void clearCache(); /** * Retrieve one commit * @param commitId @@ -474,7 +487,6 @@ public: * @return displayed */ std::map<std::string, std::string> displayed() const; - /** * Retrieve how many interactions there is from HEAD to interactionId * @param toId "" for getting the whole history @@ -485,7 +497,6 @@ public: uint32_t countInteractions(const std::string& toId, const std::string& fromId = "", const std::string& authorUri = "") const; - /** * Search in the conversation via a filter * @param req Id of the request diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp index 5372378c191e09721a3d366115e1f4083c3f6dc5..e2712371cff37d0e5fdc25229b8f31883df46c4a 100644 --- a/src/jamidht/conversation_module.cpp +++ b/src/jamidht/conversation_module.cpp @@ -2009,6 +2009,44 @@ ConversationModule::loadConversationMessages(const std::string& conversationId, return 0; } +void +ConversationModule::clearCache(const std::string& conversationId) +{ + if (auto conv = pimpl_->getConversation(conversationId)) { + std::lock_guard<std::mutex> lk(conv->mtx); + if (conv->conversation) { + conv->conversation->clearCache(); + } + } +} + +uint32_t +ConversationModule::loadConversation(const std::string& conversationId, + const std::string& fromMessage, + size_t n) +{ + auto acc = pimpl_->account_.lock(); + if (auto conv = pimpl_->getConversation(conversationId)) { + std::lock_guard<std::mutex> lk(conv->mtx); + if (conv->conversation) { + const uint32_t id = std::uniform_int_distribution<uint32_t> {}(acc->rand); + LogOptions options; + options.from = fromMessage; + options.nbOfCommits = n; + conv->conversation->loadMessages2( + [accountId = pimpl_->accountId_, conversationId, id](auto&& messages) { + emitSignal<libjami::ConversationSignal::SwarmLoaded>(id, + accountId, + conversationId, + messages); + }, + options); + return id; + } + } + return 0; +} + uint32_t ConversationModule::loadConversationUntil(const std::string& conversationId, const std::string& fromMessage, diff --git a/src/jamidht/conversation_module.h b/src/jamidht/conversation_module.h index 0feaad89639e661d0c0367b267844da3082dcf80..f7e3cba9415b3a8b31d731132e0f6c342df38cf1 100644 --- a/src/jamidht/conversation_module.h +++ b/src/jamidht/conversation_module.h @@ -226,9 +226,17 @@ public: uint32_t loadConversationMessages(const std::string& conversationId, const std::string& fromMessage = "", size_t n = 0); + uint32_t loadConversation(const std::string& conversationId, + const std::string& fromMessage = "", + size_t n = 0); uint32_t loadConversationUntil(const std::string& conversationId, const std::string& fromMessage, const std::string& to); + /** + * Clear loaded interactions + * @param conversationId + */ + void clearCache(const std::string& conversationId); // File transfer /** diff --git a/src/jamidht/conversationrepository.cpp b/src/jamidht/conversationrepository.cpp index 88129602968ca91912227cd7b5db78468db0c772..f05b7bc2ed745766a2f1747a7790e902384947fb 100644 --- a/src/jamidht/conversationrepository.cpp +++ b/src/jamidht/conversationrepository.cpp @@ -54,13 +54,6 @@ as_view(const GitObject& blob) return as_view(reinterpret_cast<git_blob*>(blob.get())); } -enum class CallbackResult { Skip, Break, Ok }; - -using PreConditionCb - = std::function<CallbackResult(const std::string&, const GitAuthor&, const GitCommit&)>; -using PostConditionCb - = std::function<bool(const std::string&, const GitAuthor&, ConversationCommit&)>; - class ConversationRepository::Impl { public: @@ -158,7 +151,6 @@ public: const std::string& from = "", bool logIfNotFound = true) const; std::vector<ConversationCommit> log(const LogOptions& options) const; - std::vector<std::map<std::string, std::string>> search(const Filter& filter) const; GitObject fileAtTree(const std::string& path, const GitTree& tree) const; GitObject memberCertificate(std::string_view memberUri, const GitTree& tree) const; @@ -2184,74 +2176,6 @@ ConversationRepository::Impl::log(const LogOptions& options) const return commits; } -std::vector<std::map<std::string, std::string>> -ConversationRepository::Impl::search(const Filter& filter) const -{ - std::vector<std::map<std::string, std::string>> commits {}; - // std::regex_constants::ECMAScript is the default flag. - auto re = std::regex(filter.regexSearch, - filter.caseSensitive ? std::regex_constants::ECMAScript - : std::regex_constants::icase); - forEachCommit( - [&](const auto& id, const auto& author, auto& commit) { - if (!commits.empty()) { - // Set linearized parent - commits.rbegin()->at("linearizedParent") = id; - } - - if (!filter.author.empty() && filter.author != uriFromDevice(author.email)) { - // Filter author - return CallbackResult::Skip; - } - auto commitTime = git_commit_time(commit.get()); - if (filter.before && filter.before < commitTime) { - // Only get commits before this date - return CallbackResult::Skip; - } - if (filter.after && filter.after > commitTime) { - // Only get commits before this date - if (git_commit_parentcount(commit.get()) <= 1) - return CallbackResult::Break; - else - return CallbackResult::Skip; // Because we are sorting it with - // GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME - } - - return CallbackResult::Ok; // Continue - }, - [&](auto&& cc) { - auto content = convCommitToMap(cc); - auto contentType = content ? content->at("type") : ""; - auto isSearchable = contentType == "text/plain" - || contentType == "application/data-transfer+json"; - if (filter.type.empty() && !isSearchable) { - // Not searchable, at least for now - return; - } else if (contentType == filter.type || filter.type.empty()) { - if (isSearchable) { - // If it's a text match the body, else the display name - auto body = contentType == "text/plain" ? content->at("body") - : content->at("displayName"); - std::smatch body_match; - if (std::regex_search(body, body_match, re)) { - commits.emplace(commits.end(), std::move(*content)); - } - } else { - // Matching type, just add it to the results - commits.emplace(commits.end(), std::move(*content)); - } - } - }, - [&](auto id, auto, auto) { - if (filter.maxResult != 0 && commits.size() == filter.maxResult) - return true; - if (id == filter.lastId) - return true; - return false; - }); - return commits; -} - GitObject ConversationRepository::Impl::fileAtTree(const std::string& path, const GitTree& tree) const { @@ -3123,10 +3047,14 @@ ConversationRepository::log(const LogOptions& options) const return pimpl_->log(options); } -std::vector<std::map<std::string, std::string>> -ConversationRepository::search(const Filter& filter) const +void +ConversationRepository::log(PreConditionCb&& preCondition, + std::function<void(ConversationCommit&&)>&& emplaceCb, + PostConditionCb&& postCondition, + const std::string& from, + bool logIfNotFound) const { - return pimpl_->search(filter); + pimpl_->forEachCommit(std::move(preCondition), std::move(emplaceCb), std::move(postCondition), from, logIfNotFound); } std::optional<ConversationCommit> diff --git a/src/jamidht/conversationrepository.h b/src/jamidht/conversationrepository.h index 60e585286e4922ae1ee6d701fc561c45fb9ed840..de96ebd8dcb3e8fee78893220f55f4cbdb7cec1c 100644 --- a/src/jamidht/conversationrepository.h +++ b/src/jamidht/conversationrepository.h @@ -127,6 +127,13 @@ struct ConversationMember } }; +enum class CallbackResult { Skip, Break, Ok }; + +using PreConditionCb + = std::function<CallbackResult(const std::string&, const GitAuthor&, const GitCommit&)>; +using PostConditionCb + = std::function<bool(const std::string&, const GitAuthor&, ConversationCommit&)>; + /** * This class gives access to the git repository that represents the conversation */ @@ -219,16 +226,14 @@ public: * @return a list of commits */ std::vector<ConversationCommit> log(const LogOptions& options = {}) const; + void log(PreConditionCb&& preCondition, + std::function<void(ConversationCommit&&)>&& emplaceCb, + PostConditionCb&& postCondition, + const std::string& from = "", + bool logIfNotFound = true) const; std::optional<ConversationCommit> getCommit(const std::string& commitId, bool logIfNotFound = true) const; - /** - * Search in the conversation via a filter - * @param filter Parameters for the search - * @return matching commits - */ - std::vector<std::map<std::string, std::string>> search(const Filter& filter) const; - /** * Get parent via topological + date sort in branch main of a commit * @param commitId id to choice diff --git a/test/unitTest/conversation/call.cpp b/test/unitTest/conversation/call.cpp index c25b2ce299dcfd9b89781494497dacdd0c33a441..dd92c8fe85a6a09d788b1df55580b0021c780896 100644 --- a/test/unitTest/conversation/call.cpp +++ b/test/unitTest/conversation/call.cpp @@ -46,7 +46,7 @@ struct ConvData bool conferenceRemoved {false}; std::string hostState {}; std::string state {}; - std::vector<std::map<std::string, std::string>> messages {}; + std::vector<libjami::SwarmMessage> messages {}; }; class ConversationCallTest : public CppUnit::TestFixture @@ -157,10 +157,10 @@ ConversationCallTest::connectSignals() carlaData_.id = conversationId; cv.notify_one(); })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>( [&](const std::string& accountId, const std::string& conversationId, - std::map<std::string, std::string> message) { + const libjami::SwarmMessage& message) { if (accountId == aliceId && aliceData_.id == conversationId) aliceData_.messages.emplace_back(message); if (accountId == bobId && bobData_.id == conversationId) @@ -295,7 +295,7 @@ ConversationCallTest::testActiveCalls() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); // should get message cv.wait_for(lk, 30s, [&]() { return !aliceData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0]["type"] == "application/call-history+json"); + CPPUNIT_ASSERT(aliceData_.messages[0].type == "application/call-history+json"); // get active calls = 1 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 1); @@ -306,7 +306,7 @@ ConversationCallTest::testActiveCalls() // should get message cv.wait_for(lk, 30s, [&]() { return !aliceData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); @@ -352,18 +352,18 @@ ConversationCallTest::testActiveCalls3Peers() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_) && lastCommitIsCall(carlaData_); }); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), confId); aliceData_.conferenceChanged = false; @@ -392,9 +392,9 @@ ConversationCallTest::testActiveCalls3Peers() return !aliceData_.messages.empty() && !bobData_.messages.empty() && !carlaData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); - CPPUNIT_ASSERT(bobData_.messages[0].find("duration") != bobData_.messages[0].end()); - CPPUNIT_ASSERT(carlaData_.messages[0].find("duration") != carlaData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); + CPPUNIT_ASSERT(bobData_.messages[0].body.find("duration") != bobData_.messages[0].body.end()); + CPPUNIT_ASSERT(carlaData_.messages[0].body.find("duration") != carlaData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); @@ -440,7 +440,7 @@ ConversationCallTest::testRejoinCall() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { @@ -448,11 +448,11 @@ ConversationCallTest::testRejoinCall() && lastCommitIsCall(carlaData_); }); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), confId); aliceData_.conferenceChanged = false; @@ -500,9 +500,9 @@ ConversationCallTest::testRejoinCall() return !aliceData_.messages.empty() && !bobData_.messages.empty() && !carlaData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); - CPPUNIT_ASSERT(bobData_.messages[0].find("duration") != bobData_.messages[0].end()); - CPPUNIT_ASSERT(carlaData_.messages[0].find("duration") != carlaData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); + CPPUNIT_ASSERT(bobData_.messages[0].body.find("duration") != bobData_.messages[0].body.end()); + CPPUNIT_ASSERT(carlaData_.messages[0].body.find("duration") != carlaData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); @@ -536,7 +536,7 @@ ConversationCallTest::testParticipantHangupConfNotRemoved() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { @@ -545,9 +545,9 @@ ConversationCallTest::testParticipantHangupConfNotRemoved() auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), - bobData_.messages.rbegin()->at("confId")); + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), + bobData_.messages.rbegin()->body.at("confId")); aliceData_.conferenceChanged = false; auto bobCallId = libjami::placeCallWithMedia(bobId, destination, {}); @@ -600,19 +600,19 @@ ConversationCallTest::testJoinFinishedCall() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_) && lastCommitIsCall(carlaData_); }); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), - bobData_.messages.rbegin()->at("confId")); + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), + bobData_.messages.rbegin()->body.at("confId")); // hangup aliceData_.messages.clear(); bobData_.messages.clear(); @@ -635,7 +635,7 @@ ConversationCallTest::testJoinFinishedCall() return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_) && lastCommitIsCall(carlaData_) && bobData_.hostState == "CURRENT"; }); - confId = bobData_.messages.rbegin()->at("confId"); + confId = bobData_.messages.rbegin()->body.at("confId"); CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 1); // hangup aliceData_.messages.clear(); @@ -647,9 +647,9 @@ ConversationCallTest::testJoinFinishedCall() return !aliceData_.messages.empty() && !bobData_.messages.empty() && !carlaData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); - CPPUNIT_ASSERT(bobData_.messages[0].find("duration") != bobData_.messages[0].end()); - CPPUNIT_ASSERT(carlaData_.messages[0].find("duration") != carlaData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); + CPPUNIT_ASSERT(bobData_.messages[0].body.find("duration") != bobData_.messages[0].body.end()); + CPPUNIT_ASSERT(carlaData_.messages[0].body.find("duration") != carlaData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); } @@ -697,7 +697,7 @@ ConversationCallTest::testJoinFinishedCallForbidden() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { @@ -705,12 +705,12 @@ ConversationCallTest::testJoinFinishedCallForbidden() && lastCommitIsCall(carlaData_); }); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), - bobData_.messages.rbegin()->at("confId")); + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), + bobData_.messages.rbegin()->body.at("confId")); // hangup aliceData_.messages.clear(); @@ -738,7 +738,7 @@ ConversationCallTest::testJoinFinishedCallForbidden() && lastCommitIsCall(carlaData_) && bobData_.hostState == "CURRENT"; }); - confId = bobData_.messages.rbegin()->at("confId"); + confId = bobData_.messages.rbegin()->body.at("confId"); CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 1); @@ -753,9 +753,9 @@ ConversationCallTest::testJoinFinishedCallForbidden() return !aliceData_.messages.empty() && !bobData_.messages.empty() && !carlaData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); - CPPUNIT_ASSERT(bobData_.messages[0].find("duration") != bobData_.messages[0].end()); - CPPUNIT_ASSERT(carlaData_.messages[0].find("duration") != carlaData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); + CPPUNIT_ASSERT(bobData_.messages[0].body.find("duration") != bobData_.messages[0].body.end()); + CPPUNIT_ASSERT(carlaData_.messages[0].body.find("duration") != carlaData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); @@ -787,7 +787,7 @@ ConversationCallTest::testUsePreference() bobData_.messages.clear(); auto lastCommitIsProfile = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/update-profile"; + && data.messages.rbegin()->body.at("type") == "application/update-profile"; }; libjami::updateConversationInfos(aliceId, aliceData_.id, @@ -806,13 +806,13 @@ ConversationCallTest::testUsePreference() auto callId = libjami::placeCallWithMedia(bobId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_); }); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); // Alice should be the host CPPUNIT_ASSERT(aliceAccount->getConference(confId)); @@ -837,12 +837,12 @@ ConversationCallTest::testJoinWhileActiveCall() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_); })); - auto confId = aliceData_.messages.rbegin()->at("confId"); + auto confId = aliceData_.messages.rbegin()->body.at("confId"); libjami::addConversationMember(aliceId, aliceData_.id, bobUri); CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return bobData_.requestReceived; })); @@ -887,7 +887,7 @@ ConversationCallTest::testCallSelfIfDefaultHost() bobData_.messages.clear(); auto lastCommitIsProfile = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/update-profile"; + && data.messages.rbegin()->body.at("type") == "application/update-profile"; }; libjami::updateConversationInfos(aliceId, aliceData_.id, @@ -906,13 +906,13 @@ ConversationCallTest::testCallSelfIfDefaultHost() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, {}); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->body.at("type") == "application/call-history+json"; }; // should get message CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_); })); - auto confId = aliceData_.messages.rbegin()->at("confId"); + auto confId = aliceData_.messages.rbegin()->body.at("confId"); // Alice should be the host CPPUNIT_ASSERT(aliceAccount->getConference(confId)); Manager::instance().hangupConference(aliceId, confId); @@ -945,7 +945,7 @@ ConversationCallTest::testNeedsHost() bobData_.messages.clear(); auto lastCommitIsProfile = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/update-profile"; + && data.messages.rbegin()->body.at("type") == "application/update-profile"; }; libjami::updateConversationInfos(aliceId, aliceData_.id, @@ -996,7 +996,7 @@ ConversationCallTest::testAudioOnly() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, mediaList); // should get message cv.wait_for(lk, 30s, [&]() { return !aliceData_.messages.empty() && !pInfos_.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0]["type"] == "application/call-history+json"); + CPPUNIT_ASSERT(aliceData_.messages[0].type == "application/call-history+json"); CPPUNIT_ASSERT(pInfos_.size() == 1); CPPUNIT_ASSERT(pInfos_[0]["videoMuted"] == "true"); @@ -1006,7 +1006,7 @@ ConversationCallTest::testAudioOnly() // should get message cv.wait_for(lk, 30s, [&]() { return !aliceData_.messages.empty(); }); - CPPUNIT_ASSERT(aliceData_.messages[0].find("duration") != aliceData_.messages[0].end()); + CPPUNIT_ASSERT(aliceData_.messages[0].body.find("duration") != aliceData_.messages[0].body.end()); // get active calls = 0 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, aliceData_.id).size() == 0); @@ -1052,13 +1052,13 @@ ConversationCallTest::testJoinAfterMuteHost() auto callId = libjami::placeCallWithMedia(aliceId, "swarm:" + aliceData_.id, mediaList); auto lastCommitIsCall = [&](const auto& data) { return !data.messages.empty() - && data.messages.rbegin()->at("type") == "application/call-history+json"; + && data.messages.rbegin()->type == "application/call-history+json"; }; // should get message CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return lastCommitIsCall(aliceData_) && lastCommitIsCall(bobData_) && !pInfos_.empty(); })); - auto confId = bobData_.messages.rbegin()->at("confId"); + auto confId = bobData_.messages.rbegin()->body.at("confId"); // Mute host auto call = std::dynamic_pointer_cast<SIPCall>(aliceAccount->getCall(callId)); @@ -1071,8 +1071,8 @@ ConversationCallTest::testJoinAfterMuteHost() // Bob join, alice must stay muted auto destination = fmt::format("rdv:{}/{}/{}/{}", bobData_.id, - bobData_.messages.rbegin()->at("uri"), - bobData_.messages.rbegin()->at("device"), + bobData_.messages.rbegin()->body.at("uri"), + bobData_.messages.rbegin()->body.at("device"), confId); aliceData_.conferenceChanged = false; diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp index a092886c7c04dc1277bb1cd0362bbd810b38dd5f..4fbf617afd7c047338199269922d3fef28ee6428 100644 --- a/test/unitTest/conversation/conversation.cpp +++ b/test/unitTest/conversation/conversation.cpp @@ -56,6 +56,29 @@ struct ConvInfoTest namespace jami { namespace test { +struct UserData { + std::string conversationId; + bool removed {false}; + bool requestReceived {false}; + bool errorDetected {false}; + bool registered {false}; + bool stopped {false}; + bool deviceAnnounced {false}; + bool composing {false}; + bool sending {false}; + bool sent {false}; + bool searchFinished {false}; + std::string profilePath; + std::string payloadTrustRequest; + std::map<std::string, std::string> profile; + std::vector<libjami::SwarmMessage> messages; + std::vector<libjami::SwarmMessage> messagesUpdated; + std::vector<std::map<std::string, std::string>> reactions; + std::vector<std::map<std::string, std::string>> messagesFound; + std::vector<std::string> reactionRemoved; + std::map<std::string, std::string> preferences; +}; + class ConversationTest : public CppUnit::TestFixture { public: @@ -67,15 +90,22 @@ public: const std::string& fakeCert = ""); std::string aliceId; + UserData aliceData; std::string alice2Id; + UserData alice2Data; std::string bobId; + UserData bobData; std::string bob2Id; + UserData bob2Data; std::string carlaId; + UserData carlaData; std::mutex mtx; std::unique_lock<std::mutex> lk {mtx}; std::condition_variable cv; + void connectSignals(); + private: void testCreateConversation(); void testCreateConversationInvalidDisplayName(); @@ -200,10 +230,266 @@ ConversationTest::setUp() bobId = actors["bob"]; carlaId = actors["carla"]; + aliceData = {}; + alice2Data = {}; + bobData = {}; + bob2Data = {}; + carlaData = {}; + Manager::instance().sendRegister(carlaId, false); wait_for_announcement_of({aliceId, bobId}); } +void +ConversationTest::connectSignals() +{ + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string& accountId, const std::map<std::string, std::string>&) { + if (accountId == aliceId) { + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto details = aliceAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + aliceData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + aliceData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + aliceData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bobId) { + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto details = bobAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bobData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bobData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bobData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bob2Id) { + auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); + auto details = bob2Account->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bob2Data.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bob2Data.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bob2Data.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == carlaId) { + auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); + auto details = carlaAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + carlaData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + carlaData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + carlaData.deviceAnnounced = deviceAnnounced == "true"; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == aliceId) { + aliceData.conversationId = conversationId; + } else if (accountId == alice2Id) { + alice2Data.conversationId = conversationId; + } else if (accountId == bobId) { + bobData.conversationId = conversationId; + } else if (accountId == bob2Id) { + bob2Data.conversationId = conversationId; + } else if (accountId == carlaId) { + carlaData.conversationId = conversationId; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( + [&](const std::string& account_id, + const std::string& /*from*/, + const std::string& /*conversationId*/, + const std::vector<uint8_t>& payload, + time_t /*received*/) { + auto payloadStr = std::string(payload.data(), payload.data() + payload.size()); + if (account_id == aliceId) + aliceData.payloadTrustRequest = payloadStr; + else if (account_id == bobId) + bobData.payloadTrustRequest = payloadStr; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + std::map<std::string, std::string> /*metadatas*/) { + if (accountId == aliceId) { + aliceData.requestReceived = true; + } else if (accountId == bobId) { + bobData.requestReceived = true; + } else if (accountId == bob2Id) { + bob2Data.requestReceived = true; + } else if (accountId == carlaId) { + carlaData.requestReceived = true; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messages.emplace_back(message); + } else if (accountId == bobId) { + bobData.messages.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messages.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageUpdated>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messagesUpdated.emplace_back(message); + } else if (accountId == bobId) { + bobData.messagesUpdated.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messagesUpdated.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ReactionAdded>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + const std::string& /* messageId */, + std::map<std::string, std::string> reaction) { + if (accountId == aliceId) { + aliceData.reactions.emplace_back(reaction); + } else if (accountId == bobId) { + bobData.reactions.emplace_back(reaction); + } else if (accountId == carlaId) { + carlaData.reactions.emplace_back(reaction); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ReactionRemoved>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + const std::string& /* messageId */, + const std::string& reactionId) { + if (accountId == aliceId) { + aliceData.reactionRemoved.emplace_back(reactionId); + } else if (accountId == bobId) { + bobData.reactionRemoved.emplace_back(reactionId); + } else if (accountId == carlaId) { + carlaData.reactionRemoved.emplace_back(reactionId); + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + int /*code*/, + const std::string& /* what */) { + if (accountId == aliceId) + aliceData.errorDetected = true; + else if (accountId == bobId) + bobData.errorDetected = true; + else if (accountId == carlaId) + carlaData.errorDetected = true; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::ComposingStatusChanged>( + [&](const std::string& accountId, + const std::string& /*conversationId*/, + const std::string& /*peer*/, + bool state) { + if (accountId == bobId) { + bobData.composing = state; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( + [&](const std::string& accountId, + const std::string& /*conversationId*/, + const std::string& /*peer*/, + const std::string& /*msgId*/, + int status) { + if (accountId == aliceId) { + if (status == 2) + aliceData.sending = true; + if (status == 3) + aliceData.sent = true; + } else if (accountId == bobId) { + if (status == 2) + bobData.sending = true; + if (status == 3) + bobData.sent = true; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationProfileUpdated>( + [&](const auto& accountId, const auto& /* conversationId */, const auto& profile) { + if (accountId == aliceId) { + aliceData.profile = profile; + } else if (accountId == bobId) { + bobData.profile = profile; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( + [&](const std::string& accountId, const std::string&) { + if (accountId == aliceId) + aliceData.removed = true; + else if (accountId == bobId) + bobData.removed = true; + else if (accountId == bob2Id) + bob2Data.removed = true; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ProfileReceived>( + [&](const std::string& accountId, const std::string& peerId, const std::string& path) { + if (accountId == bobId) + bobData.profilePath = path; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationPreferencesUpdated>( + [&](const std::string& accountId, + const std::string& conversationId, + std::map<std::string, std::string> preferences) { + if (accountId == bobId) + bobData.preferences = preferences; + else if (accountId == bob2Id) + bob2Data.preferences = preferences; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessagesFound>( + [&](uint32_t, + const std::string& accountId, + const std::string& conversationId, + std::vector<std::map<std::string, std::string>> msg) { + if (accountId == aliceId) { + aliceData.messagesFound.insert(aliceData.messagesFound.end(), msg.begin(), msg.end()); + aliceData.searchFinished = conversationId.empty(); + } + cv.notify_one(); + })); + libjami::registerSignalHandlers(confHandlers); +} + void ConversationTest::tearDown() { @@ -226,31 +512,20 @@ void ConversationTest::testCreateConversation() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto aliceDeviceId = aliceAccount->currentDeviceId(); auto uri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - // Start conversation auto convId = libjami::startConversation(aliceId); - cv.wait_for(lk, 30s, [&]() { return conversationReady; }); - CPPUNIT_ASSERT(conversationReady); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); ConversationRepository repo(aliceAccount, convId); CPPUNIT_ASSERT(repo.mode() == ConversationMode::INVITES_ONLY); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files @@ -341,24 +616,14 @@ void ConversationTest::testGetConversationsAfterRm() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto uri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - // Start conversation auto convId = libjami::startConversation(aliceId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); auto conversations = libjami::getConversations(aliceId); CPPUNIT_ASSERT(conversations.size() == 1); @@ -371,24 +636,11 @@ void ConversationTest::testRemoveInvalidConversation() { std::cout << "\nRunning test: " << __func__ << std::endl; - - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto uri = aliceAccount->getUsername(); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + connectSignals(); // Start conversation auto convId = libjami::startConversation(aliceId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); auto conversations = libjami::getConversations(aliceId); CPPUNIT_ASSERT(conversations.size() == 1); @@ -401,203 +653,86 @@ void ConversationTest::testSendMessage() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; }); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == 2; }); + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - cv.wait_for(lk, 30s, [&]() { return messageBobReceived == 1; }); + cv.wait_for(lk, 30s, [&]() { return bobData.messages.size() == bobMsgSize + 1; }); } void ConversationTest::testSendMessageWithBadDisplayName() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - bool aliceRegistered = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = aliceAccount->getVolatileAccountDetails(); - auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "REGISTERED") { - aliceRegistered = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - std::map<std::string, std::string> details; details[ConfProperties::DISPLAYNAME] = "<o>"; libjami::setAccountDetails(aliceId, details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceRegistered; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.registered; })); auto convId = libjami::startConversation(aliceId); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == 2; })); + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - cv.wait_for(lk, 30s, [&]() { return messageBobReceived == 1; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.messages.size() == bobMsgSize + 1; })); } void ConversationTest::testReplaceWithBadCertificate() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - auto requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - auto conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - auto errorDetected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; }); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == 2; }); // Replace alice's certificate with a bad one. - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations" / convId; + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; auto aliceDevicePath = repoPath / "devices" / fmt::format("{}.crt", aliceAccount->currentDeviceId()); auto bobDevicePath = repoPath / "devices" / fmt::format("{}.crt", bobAccount->currentDeviceId()); std::filesystem::copy(bobDevicePath, @@ -613,50 +748,33 @@ ConversationTest::testReplaceWithBadCertificate() wbuilder["commentStyle"] = "None"; wbuilder["indentation"] = ""; auto message = Json::writeString(wbuilder, root); - messageBobReceived = 0; commitInRepo(repoPath, aliceAccount, message); // now we need to sync! + bobData.errorDetected = false; libjami::sendMessage(aliceId, convId, "trigger sync!"s, ""); // We should detect the incorrect commit! - cv.wait_for(lk, 30s, [&]() { return errorDetected; }); + cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; }); } void ConversationTest::testSendMessageTriggerMessageReceived() { std::cout << "\nRunning test: " << __func__ << std::endl; - - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageReceived = 0; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - messageReceived += 1; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& /* accountId */, const std::string& /* conversationId */) { - conversationReady = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + connectSignals(); auto convId = libjami::startConversation(aliceId); - cv.wait_for(lk, 30s, [&] { return conversationReady; }); + cv.wait_for(lk, 30s, [&] { return !aliceData.conversationId.empty(); }); + auto msgSize = aliceData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - cv.wait_for(lk, 30s, [&] { return messageReceived == 1; }); - CPPUNIT_ASSERT(messageReceived == 1); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceData.messages.size() == msgSize + 1; })); } void ConversationTest::testMergeTwoDifferentHeads() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); @@ -666,33 +784,15 @@ ConversationTest::testMergeTwoDifferentHeads() carlaAccount->trackBuddyPresence(aliceUri, true); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, carlaGotMessage = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == carlaId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /* message */) { - if (accountId == carlaId && conversationId == convId) { - carlaGotMessage = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto msgSize = aliceData.messages.size(); aliceAccount->convModule()->addConversationMember(convId, carlaUri, false); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == msgSize + 1; })); // Cp conversations & convInfo - auto repoPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations"; + auto repoPathAlice = fileutils::get_data_dir() / aliceId / "conversations"; auto repoPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "conversations"; std::filesystem::copy(repoPathAlice, repoPathCarla, std::filesystem::copy_options::recursive); - auto ciPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto ciPathAlice = fileutils::get_data_dir() / aliceId / "convInfo"; auto ciPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "convInfo"; @@ -710,9 +810,7 @@ ConversationTest::testMergeTwoDifferentHeads() // Start Carla, should merge and all messages should be there Manager::instance().sendRegister(carlaId, true); - carlaGotMessage = false; - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaGotMessage; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return !carlaData.messages.empty(); })); } void @@ -797,7 +895,7 @@ ConversationTest::testSendMessageToMultipleParticipants() })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); repoPath = fileutils::get_data_dir() / carlaAccount->getAccountID() @@ -815,288 +913,124 @@ void ConversationTest::testPingPongMessages() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) - messageBobReceived += 1; - if (accountId == aliceId) - messageAliceReceived += 1; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - messageAliceReceived = 0; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 60s, [&]() { return conversationReady && messageAliceReceived == 1; })); + cv.wait_for(lk, 60s, [&]() { return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); - messageBobReceived = 0; - messageAliceReceived = 0; + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "ping"s, ""); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return messageBobReceived == 1 && messageAliceReceived == 1; + return bobMsgSize + 1 == bobData.messages.size() && aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::sendMessage(bobId, convId, "pong"s, ""); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return messageBobReceived == 2 && messageAliceReceived == 2; + return bobMsgSize + 2 == bobData.messages.size() && aliceMsgSize + 2 == aliceData.messages.size(); })); libjami::sendMessage(bobId, convId, "ping"s, ""); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return messageBobReceived == 3 && messageAliceReceived == 3; + return bobMsgSize + 3 == bobData.messages.size() && aliceMsgSize + 3 == aliceData.messages.size(); })); libjami::sendMessage(aliceId, convId, "pong"s, ""); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return messageBobReceived == 4 && messageAliceReceived == 4; + return bobMsgSize + 4 == bobData.messages.size() && aliceMsgSize + 4 == aliceData.messages.size(); })); - libjami::unregisterSignalHandlers(); } void ConversationTest::testIsComposing() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - aliceComposing = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::ComposingStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - bool state) { - if (accountId == bobId && conversationId == convId && peer == aliceUri) { - aliceComposing = state; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); aliceAccount->setIsComposing("swarm:" + convId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceComposing; })); - + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.composing; })); aliceAccount->setIsComposing("swarm:" + convId, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceComposing; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.composing; })); } void ConversationTest::testMessageStatus() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - cv.notify_one(); - } - })); - bool sending = false, sent = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - const std::string& msgId, - int status) { - if (accountId == aliceId && convId == conversationId) { - if (status == 2) - sending = true; - if (status == 3) - sent = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); - sending = false; - sent = false; + aliceData.sending = false; + aliceData.sent = false; libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return sending && sent; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.sending && aliceData.sent; })); } void ConversationTest::testSetMessageDisplayed() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - msgDisplayed = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - cv.notify_one(); - } - })); - std::string aliceLastMsg; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - const std::string& msgId, - int status) { - if (conversationId == convId && peer == aliceUri && status == 3) { - if (accountId == bobId && msgId == conversationId) - msgDisplayed = true; - else if (accountId == aliceId) - aliceLastMsg = msgId; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - aliceLastMsg = ""; + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && !aliceLastMsg.empty(); })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); // Last displayed messages should not be set yet auto membersInfos = libjami::getConversationMembers(bobId, convId); @@ -1112,12 +1046,12 @@ ConversationTest::testSetMessageDisplayed() [&](auto infos) { // Last read for alice is when bob is added to the members return infos["uri"] == aliceUri - && infos["lastDisplayed"] == aliceLastMsg; + && infos["lastDisplayed"] == aliceData.messages[0].id; }) != membersInfos.end()); - + bobData.sent = false; aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return msgDisplayed; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.sent; })); // Now, the last displayed message should be updated in member's infos (both sides) membersInfos = libjami::getConversationMembers(bobId, convId); @@ -1136,170 +1070,65 @@ ConversationTest::testSetMessageDisplayed() && infos["lastDisplayed"] == convId; }) != membersInfos.end()); - - libjami::unregisterSignalHandlers(); } void ConversationTest::testSetMessageDisplayedTwice() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - msgDisplayed = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - cv.notify_one(); - } - })); - std::string aliceLastMsg; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - const std::string& msgId, - int status) { - if (conversationId == convId && peer == aliceUri && status == 3) { - if (accountId == bobId && msgId == conversationId) - msgDisplayed = true; - else if (accountId == aliceId) - aliceLastMsg = msgId; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - aliceLastMsg = ""; + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && !aliceLastMsg.empty(); })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); + bobData.sent = false; aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return msgDisplayed; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.sent; })); - msgDisplayed = false; + bobData.sent = false; aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return msgDisplayed; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return bobData.sent; })); } void ConversationTest::testSetMessageDisplayedPreference() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - msgDisplayed = false, aliceRegistered = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - std::string aliceLastMsg; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - const std::string& msgId, - int status) { - if (conversationId == convId && peer == aliceUri && status == 3) { - if (accountId == bobId && msgId == conversationId) - msgDisplayed = true; - else if (accountId == aliceId) - aliceLastMsg = msgId; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = aliceAccount->getVolatileAccountDetails(); - auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "REGISTERED") { - aliceRegistered = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); auto details = aliceAccount->getAccountDetails(); CPPUNIT_ASSERT(details[ConfProperties::SENDREADRECEIPT] == "true"); details[ConfProperties::SENDREADRECEIPT] = "false"; libjami::setAccountDetails(aliceId, details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceRegistered; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.registered; })); - aliceLastMsg = ""; + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return requestReceived && memberMessageGenerated && !aliceLastMsg.empty(); - })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size(); })); + libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); // Last displayed messages should not be set yet auto membersInfos = libjami::getConversationMembers(aliceId, convId); @@ -1308,13 +1137,13 @@ ConversationTest::testSetMessageDisplayedPreference() [&](auto infos) { // Last read for alice is when bob is added to the members return infos["uri"] == aliceUri - && infos["lastDisplayed"] == aliceLastMsg; + && infos["lastDisplayed"] == aliceData.messages[0].id; }) != membersInfos.end()); aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); // Bob should not receive anything here, as sendMessageDisplayed is disabled for Alice - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return msgDisplayed; })); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return bobData.sent; })); // Assert that message is set as displayed for self (for the read status) membersInfos = libjami::getConversationMembers(aliceId, convId); @@ -1325,85 +1154,25 @@ ConversationTest::testSetMessageDisplayedPreference() && infos["lastDisplayed"] == convId; }) != membersInfos.end()); - libjami::unregisterSignalHandlers(); } void ConversationTest::testSetMessageDisplayedAfterClone() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false, memberMessageGenerated = false, msgDisplayed = false, - aliceRegistered = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - bool conversationReady = false, conversationAlice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - } else if (accountId == alice2Id) { - conversationAlice2Ready = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - std::string aliceLastMsg; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& peer, - const std::string& msgId, - int status) { - if (conversationId == convId && peer == aliceUri && status == 3) { - if (accountId == bobId && msgId == conversationId) - msgDisplayed = true; - else if (accountId == aliceId) - aliceLastMsg = msgId; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = aliceAccount->getVolatileAccountDetails(); - auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "REGISTERED") { - aliceRegistered = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - aliceLastMsg = ""; + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return requestReceived && memberMessageGenerated && !aliceLastMsg.empty(); - })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); aliceAccount->setMessageDisplayed("swarm:" + convId, convId, 3); @@ -1422,7 +1191,7 @@ ConversationTest::testSetMessageDisplayedAfterClone() alice2Id = Manager::instance().addAccount(details); // Disconnect alice2, to create a valid conv betwen Alice and alice1 - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationAlice2Ready; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !alice2Data.conversationId.empty(); })); // Assert that message is set as displayed for self (for the read status) auto membersInfos = libjami::getConversationMembers(aliceId, convId); @@ -1433,8 +1202,6 @@ ConversationTest::testSetMessageDisplayedAfterClone() && infos["lastDisplayed"] == convId; }) != membersInfos.end()); - - libjami::unregisterSignalHandlers(); } void @@ -1510,8 +1277,6 @@ std::string ConversationTest::createFakeConversation(std::shared_ptr<JamiAccount> account, const std::string& fakeCert) { - std::cout << "\nRunning test: " << __func__ << std::endl; - auto repoPath = fileutils::get_data_dir() / account->getAccountID() / "conversations" / "tmp"; @@ -1678,6 +1443,7 @@ void ConversationTest::testVoteNonEmpty() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); @@ -1688,158 +1454,53 @@ ConversationTest::testVoteNonEmpty() auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, errorDetected = false, - carlaConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.deviceAnnounced; })); + + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); + + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::addConversationMember(aliceId, convId, carlaUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); libjami::acceptConversationRequest(carlaId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && bobMsgSize + 2 == bobData.messages.size(); })); // Now Alice removes Carla with a non empty file - errorDetected = false; addVote(aliceAccount, convId, carlaUri, "CONTENT"); simulateRemoval(aliceAccount, convId, carlaUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.errorDetected; })); } void ConversationTest::testNoBadFileInInitialCommit() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); - auto carlaUri = carlaAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); auto convId = createFakeConversation(carlaAccount); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool carlaConnected = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(carlaId, convId, aliceUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.requestReceived; })); libjami::acceptConversationRequest(aliceId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.errorDetected; })); } void ConversationTest::testNoBadCertInInitialCommit() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); @@ -1854,141 +1515,47 @@ ConversationTest::testNoBadCertInInitialCommit() // Create a conversation from Carla with Alice's device auto convId = createFakeConversation(carlaAccount, fakeCert->toString(false)); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool carlaConnected = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(carlaId, convId, aliceUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.requestReceived; })); libjami::acceptConversationRequest(aliceId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.errorDetected; })); } void ConversationTest::testPlainTextNoBadFile() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0; - bool memberMessageGenerated = false; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; std::string convId = libjami::startConversation(aliceId); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == bobId) { - messageBobReceived += 1; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::acceptConversationRequest(bobId, convId); - cv.wait_for(lk, 30s, [&] { return conversationReady && memberMessageGenerated; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); addFile(aliceAccount, convId, "BADFILE"); Json::Value root; root["type"] = "text/plain"; root["body"] = "hi"; commit(aliceAccount, convId, root); - errorDetected = false; libjami::sendMessage(aliceId, convId, "hi"s, ""); // Check not received due to the unwanted file - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testVoteNoBadFile() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); @@ -1999,146 +1566,47 @@ ConversationTest::testVoteNoBadFile() auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, messageCarlaReceived = false, - carlaConnected = false; - ; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - std::string body = ""; - auto it = message.find("body"); - if (it != message.end()) { - body = it->second; - } - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } else if (accountId == carlaId && conversationId == convId && body == "final") { - messageCarlaReceived = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.deviceAnnounced; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); + + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::addConversationMember(aliceId, convId, carlaUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived && aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); libjami::acceptConversationRequest(carlaId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && bobMsgSize + 2 == bobData.messages.size(); })); // Now Alice remove Carla without a vote. Bob will not receive the message - messageBobReceived = false; addFile(aliceAccount, convId, "BADFILE"); + aliceMsgSize = aliceData.messages.size(); libjami::removeConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); - messageCarlaReceived = false; + auto carlaMsgSize = carlaData.messages.size(); libjami::sendMessage(bobId, convId, "final"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageCarlaReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaMsgSize + 1 == carlaData.messages.size(); })); } void ConversationTest::testETooBigClone() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; std::ofstream bad(repoPath / "BADFILE"); CPPUNIT_ASSERT(bad.is_open()); @@ -2147,84 +1615,38 @@ ConversationTest::testETooBigClone() bad.close(); addAll(aliceAccount, convId); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - - errorDetected = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testETooBigFetch() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - cv.wait_for(lk, 30s, [&]() { return requestReceived; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - cv.wait_for(lk, 30s, [&]() { return conversationReady; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; std::ofstream bad(repoPath / "BADFILE"); CPPUNIT_ASSERT(bad.is_open()); - errorDetected = false; for (int i = 0; i < 300 * 1024 * 1024; ++i) bad << "A"; bad.close(); @@ -2236,14 +1658,14 @@ ConversationTest::testETooBigFetch() commit(aliceAccount, convId, json); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testUnknownModeDetected() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); @@ -2257,405 +1679,144 @@ ConversationTest::testUnknownModeDetected() wbuilder["commentStyle"] = "None"; wbuilder["indentation"] = ""; repo.amend(convId, Json::writeString(wbuilder, json)); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - errorDetected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 2) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - errorDetected = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testUpdateProfile() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - std::map<std::string, std::string> profileAlice, profileBob; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationProfileUpdated>( - [&](const auto& accountId, const auto& /* conversationId */, const auto& profile) { - if (accountId == aliceId) { - profileAlice = profile; - } else if (accountId == bobId) { - profileBob = profile; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); - + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - - messageAliceReceived = 0; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && messageAliceReceived == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && !bobData.conversationId.empty(); })); - messageBobReceived = 0; + auto bobMsgSize = bobData.messages.size(); aliceAccount->convModule()->updateConversationInfos(convId, {{"title", "My awesome swarm"}}); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return messageBobReceived == 1 && !profileAlice.empty() && !profileBob.empty(); + return bobMsgSize + 1 == bobData.messages.size() && !aliceData.profile.empty() && !bobData.profile.empty(); })); auto infos = libjami::conversationInfos(bobId, convId); // Verify that we have the same profile everywhere CPPUNIT_ASSERT(infos["title"] == "My awesome swarm"); - CPPUNIT_ASSERT(profileAlice["title"] == "My awesome swarm"); - CPPUNIT_ASSERT(profileBob["title"] == "My awesome swarm"); + CPPUNIT_ASSERT(aliceData.profile["title"] == "My awesome swarm"); + CPPUNIT_ASSERT(bobData.profile["title"] == "My awesome swarm"); CPPUNIT_ASSERT(infos["description"].empty()); - CPPUNIT_ASSERT(profileAlice["description"].empty()); - CPPUNIT_ASSERT(profileBob["description"].empty()); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(aliceData.profile["description"].empty()); + CPPUNIT_ASSERT(bobData.profile["description"].empty()); } void ConversationTest::testGetProfileRequest() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageAliceReceived = 0; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == aliceId) - messageAliceReceived += 1; - cv.notify_one(); - })); - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); - - messageAliceReceived = 0; + auto aliceMsgSize = aliceData.messages.size(); aliceAccount->convModule()->updateConversationInfos(convId, {{"title", "My awesome swarm"}}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); auto infos = libjami::conversationInfos(bobId, convId); CPPUNIT_ASSERT(infos["title"] == "My awesome swarm"); CPPUNIT_ASSERT(infos["description"].empty()); - - libjami::unregisterSignalHandlers(); } void ConversationTest::testCheckProfileInConversationRequest() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); aliceAccount->convModule()->updateConversationInfos(convId, {{"title", "My awesome swarm"}}); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); auto requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 1); CPPUNIT_ASSERT(requests.front()["title"] == "My awesome swarm"); - - libjami::unregisterSignalHandlers(); } void ConversationTest::testCheckProfileInTrustRequest() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - std::string convId = ""; std::string vcard = "BEGIN:VCARD\n\ VERSION:2.1\n\ FN:TITLE\n\ DESCRIPTION:DESC\n\ END:VCARD"; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& payload, - time_t /*received*/) { - auto pstr = std::string(payload.begin(), payload.begin() + payload.size()); - if (account_id == bobId - && std::string(payload.data(), payload.data() + payload.size()) == vcard) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobUri); std::vector<uint8_t> payload(vcard.begin(), vcard.end()); aliceAccount->sendTrustRequest(bobUri, payload); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !convId.empty() && requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return bobData.payloadTrustRequest == vcard; })); } void ConversationTest::testMemberCannotUpdateProfile() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& accountId, - const std::string& conversationId, - int code, - const std::string& /* what */) { - if (accountId == bobId && conversationId == convId && code == 4) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - - messageAliceReceived = 0; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && messageAliceReceived == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && !bobData.conversationId.empty(); })); - messageBobReceived = 0; bobAccount->convModule()->updateConversationInfos(convId, {{"title", "My awesome swarm"}}); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return errorDetected; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testUpdateProfileWithBadFile() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto convId = libjami::startConversation(aliceId); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& accountId, - const std::string& conversationId, - int code, - const std::string& /* what */) { - if (accountId == bobId && conversationId == convId && code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + auto convId = libjami::startConversation(aliceId); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - - messageAliceReceived = 0; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && messageAliceReceived == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && !bobData.conversationId.empty(); })); // Update profile but with bad file addFile(aliceAccount, convId, "BADFILE"); @@ -2668,73 +1829,25 @@ END:VCARD"; Json::Value root; root["type"] = "application/update-profile"; commit(aliceAccount, convId, root); - errorDetected = false; libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationTest::testFetchProfileUnauthorized() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto convId = libjami::startConversation(aliceId); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& accountId, - const std::string& conversationId, - int code, - const std::string& /* what */) { - if (accountId == aliceId && conversationId == convId && code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + auto convId = libjami::startConversation(aliceId); + auto aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - - messageAliceReceived = 0; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && messageAliceReceived == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size() && !bobData.conversationId.empty(); })); // Fake realist profile update std::string vcard = "BEGIN:VCARD\n\ @@ -2746,61 +1859,36 @@ END:VCARD"; Json::Value root; root["type"] = "application/update-profile"; commit(bobAccount, convId, root); - errorDetected = false; libjami::sendMessage(bobId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.errorDetected; })); } void ConversationTest::testSyncingWhileAccepting() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - auto convInfos = libjami::conversationInfos(bobId, convId); + auto convInfos = libjami::conversationInfos(bobId, aliceData.conversationId); CPPUNIT_ASSERT(convInfos["syncing"] == "true"); CPPUNIT_ASSERT(convInfos.find("created") != convInfos.end()); Manager::instance().sendRegister(aliceId, true); // This avoid to sync immediately - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); - convInfos = libjami::conversationInfos(bobId, convId); + convInfos = libjami::conversationInfos(bobId, bobData.conversationId); CPPUNIT_ASSERT(convInfos.find("syncing") == convInfos.end()); } @@ -2843,85 +1931,44 @@ void ConversationTest::testReplayConversation() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - conversationRemoved = false, messageReceived = false; - std::vector<std::string> bobMessages; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == aliceId) - conversationRemoved = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - messageReceived = true; - if (message["type"] == "member") - memberMessageGenerated = true; - } else if (accountId == bobId && message["type"] == "text/plain") { - bobMessages.emplace_back(message["body"]); - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { + return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // removeContact aliceAccount->removeContact(bobUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.removed; })); + std::this_thread::sleep_for(5s); // re-add - CPPUNIT_ASSERT(convId != ""); - auto oldConvId = convId; - convId = ""; + CPPUNIT_ASSERT(bobData.conversationId != ""); + auto oldConvId = bobData.conversationId; + aliceData.conversationId = ""; aliceAccount->addContact(bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty(); })); - messageReceived = false; - libjami::sendMessage(aliceId, convId, "foo"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(aliceId, convId, "bar"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageReceived; })); - convId = ""; - bobMessages.clear(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); + aliceMsgSize = aliceData.messages.size(); + libjami::sendMessage(aliceId, aliceData.conversationId, "foo"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); + libjami::sendMessage(aliceId, aliceData.conversationId, "bar"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); + bobData.messages.clear(); aliceAccount->sendTrustRequest(bobUri, {}); // Should retrieve previous conversation CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return bobMessages.size() == 2 && bobMessages[0] == "foo" && bobMessages[1] == "bar"; + JAMI_ERROR("@@@ {}", bobData.messages.size()); + if (bobData.messages.size() > 0) + JAMI_ERROR("@@@ {}", bobData.messages[0].body["body"]); + return bobData.messages.size() == 2 && bobData.messages[0].body["body"] == "foo" && bobData.messages[1].body["body"] == "bar"; })); } @@ -2929,69 +1976,13 @@ void ConversationTest::testSyncWithoutPinnedCert() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::string convId = ""; - auto requestReceived = false, conversationReady = false, memberMessageGenerated = false, - aliceMessageReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - else if (message["type"] == "text/plain") - aliceMessageReceived = true; - } - cv.notify_one(); - })); - auto bob2Started = false, aliceStopped = false, bob2Stopped = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); - if (!bob2Account) - return; - auto details = bob2Account->getVolatileAccountDetails(); - auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "REGISTERED") - bob2Started = true; - if (daemonStatus == "UNREGISTERED") - bob2Stopped = true; - details = aliceAccount->getVolatileAccountDetails(); - daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "UNREGISTERED") - aliceStopped = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -3007,33 +1998,31 @@ ConversationTest::testSyncWithoutPinnedCert() bob2Id = Manager::instance().addAccount(details); // Disconnect bob2, to create a valid conv betwen Alice and Bob1 - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); - bob2Stopped = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.registered; })); Manager::instance().sendRegister(bob2Id, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Stopped; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.stopped; })); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { + return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Bob send a message - libjami::sendMessage(bobId, convId, "hi"s, ""); - cv.wait_for(lk, 30s, [&]() { return aliceMessageReceived; }); + libjami::sendMessage(bobId, bobData.conversationId, "hi"s, ""); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); }); // Alice off, bob2 On - conversationReady = false; - aliceStopped = false; Manager::instance().sendRegister(aliceId, false); - cv.wait_for(lk, 10s, [&]() { return aliceStopped; }); + cv.wait_for(lk, 10s, [&]() { return aliceData.stopped; }); Manager::instance().sendRegister(bob2Id, true); // Sync + validate - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bob2Data.conversationId.empty(); })); } void @@ -3065,6 +2054,7 @@ void ConversationTest::testRemoveReaddMultipleDevice() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); @@ -3086,67 +2076,6 @@ END:VCARD"; file.close(); } - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReadyBob = true; - } else if (accountId == bob2Id) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto conversationRmBob = false, conversationRmBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRmBob = true; - else if (accountId == bob2Id) - conversationRmBob2 = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -3161,110 +2090,40 @@ END:VCARD"; details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false, requestReceivedBob2 = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); - libjami::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationReadyBob && conversationReadyBob2 && memberMessageGenerated; + return !bobData.conversationId.empty() && !bob2Data.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Remove contact bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRmBob && conversationRmBob2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed && bob2Data.removed; })); // wait that connections are closed. - std::this_thread::sleep_for(10s); + std::this_thread::sleep_for(5s); - // Alice send a message. This will not trigger any request, because contact was removed. - requestReceived = false, requestReceivedBob2 = false; - libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return requestReceived || requestReceivedBob2; })); + // Alice send a message + bobData.requestReceived = false; bob2Data.requestReceived = false; + libjami::sendMessage(aliceId, aliceData.conversationId, "hi"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); } void ConversationTest::testCloneFromMultipleDevice() { - std::cout << "\nRunning test: " << __func__ << std::endl; - - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReadyBob = true; - } else if (accountId == bob2Id) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto conversationRmAlice = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == aliceId) - conversationRmAlice = true; - cv.notify_one(); - })); - auto errorDetected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 1) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); + + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getUsername(); // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; @@ -3280,227 +2139,116 @@ ConversationTest::testCloneFromMultipleDevice() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false, requestReceivedBob2 = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); - libjami::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationReadyBob && conversationReadyBob2 && memberMessageGenerated; + return !bobData.conversationId.empty() && !bob2Data.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Remove contact aliceAccount->removeContact(bobUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRmAlice; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.removed; })); // wait that connections are closed. std::this_thread::sleep_for(10s); // Alice re-adds Bob - auto oldConv = convId; - conversationRmAlice = false; + auto oldConv = bobData.conversationId; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); // This should retrieve the conversation from Bob and don't show any error - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return errorDetected; })); - CPPUNIT_ASSERT(conversationRmAlice); - CPPUNIT_ASSERT(oldConv == convId); // Check that convId didn't change and conversation is ready. + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return aliceData.errorDetected; })); + CPPUNIT_ASSERT(oldConv == aliceData.conversationId); // Check that convId didn't change and conversation is ready. } void ConversationTest::testSendReply() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::vector<std::map<std::string, std::string>> messageBobReceived = {}, - messageAliceReceived = {}; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - if (accountId == bobId) { - messageBobReceived.emplace_back(message); - } else { - messageAliceReceived.emplace_back(message); - } - cv.notify_one(); - })); - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - - // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() - / "conversations" / convId; - CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); - // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived.size() == 2; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); - messageBobReceived.clear(); + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageBobReceived.size() == 1; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.messages.size() == bobMsgSize + 1; })); - auto validId = messageBobReceived.at(0).at("id"); + auto validId = bobData.messages.at(0).id; libjami::sendMessage(aliceId, convId, "foo"s, validId); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return messageBobReceived.size() == 2; })); - CPPUNIT_ASSERT(messageBobReceived.rbegin()->at("reply-to") == validId); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return bobData.messages.size() == bobMsgSize + 2; })); + CPPUNIT_ASSERT(bobData.messages.rbegin()->body.at("reply-to") == validId); // Check if parent doesn't exists, no message is generated libjami::sendMessage(aliceId, convId, "foo"s, "invalid"); - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return messageBobReceived.size() == 3; })); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return bobData.messages.size() == bobMsgSize + 3; })); } void ConversationTest::testSearchInConv() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - messageReceived = false; - std::vector<std::string> bobMessages; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - } else if (accountId == bobId) { - messageReceived = true; - } - cv.notify_one(); - })); - std::vector<std::map<std::string, std::string>> messages; - bool finished = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessagesFound>( - [&](uint32_t, - const std::string&, - const std::string& conversationId, - std::vector<std::map<std::string, std::string>> msg) { - if (conversationId == convId) - messages = msg; - finished = conversationId.empty(); - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; + + auto aliceMsgSize = aliceData.messages.size(); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Add some messages - messageReceived = false; - libjami::sendMessage(aliceId, convId, "message 1"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(aliceId, convId, "message 2"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(aliceId, convId, "Message 3"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageReceived; })); - - libjami::searchConversation(aliceId, convId, "", "", "message", "", 0, 0, 0, 0); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messages.size() == 3 && finished; })); - messages.clear(); - finished = false; - libjami::searchConversation(aliceId, convId, "", "", "Message", "", 0, 0, 0, 1); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messages.size() == 1 && finished; })); - messages.clear(); - finished = false; - libjami::searchConversation(aliceId, convId, "", "", "message 2", "", 0, 0, 0, 0); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messages.size() == 1 && finished; })); - messages.clear(); - finished = false; - libjami::searchConversation(aliceId, convId, "", "", "foo", "", 0, 0, 0, 0); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messages.size() == 0 && finished; })); + auto bobMsgSize = bobData.messages.size(); + libjami::sendMessage(aliceId, aliceData.conversationId, "message 1"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); })); + libjami::sendMessage(aliceId, aliceData.conversationId, "message 2"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 2 == bobData.messages.size(); })); + libjami::sendMessage(aliceId, aliceData.conversationId, "Message 3"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 3 == bobData.messages.size(); })); + + libjami::searchConversation(aliceId, aliceData.conversationId, "", "", "message", "", 0, 0, 0, 0); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messagesFound.size() == 3 && aliceData.searchFinished; })); + aliceData.messagesFound.clear(); + aliceData.searchFinished = false; + libjami::searchConversation(aliceId, aliceData.conversationId, "", "", "Message", "", 0, 0, 0, 1); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messagesFound.size() == 1 && aliceData.searchFinished; })); + aliceData.messagesFound.clear(); + aliceData.searchFinished = false; + libjami::searchConversation(aliceId, aliceData.conversationId, "", "", "message 2", "", 0, 0, 0, 0); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messagesFound.size() == 1 && aliceData.searchFinished; })); + aliceData.messagesFound.clear(); + aliceData.searchFinished = false; + libjami::searchConversation(aliceId, aliceData.conversationId, "", "", "foo", "", 0, 0, 0, 0); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.messagesFound.size() == 0 && aliceData.searchFinished; })); } void ConversationTest::testConversationPreferences() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto uri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, conversationRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == aliceId) - conversationRemoved = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); // Start conversation and set preferences auto convId = libjami::startConversation(aliceId); - cv.wait_for(lk, 30s, [&]() { return conversationReady; }); + cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); }); CPPUNIT_ASSERT(libjami::getConversationPreferences(aliceId, convId).size() == 0); libjami::setConversationPreferences(aliceId, convId, {{"foo", "bar"}}); auto preferences = libjami::getConversationPreferences(aliceId, convId); @@ -3514,7 +2262,7 @@ ConversationTest::testConversationPreferences() CPPUNIT_ASSERT(preferences["bar"] == "foo"); // Remove conversations removes its preferences. CPPUNIT_ASSERT(libjami::removeConversation(aliceId, convId)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.removed; })); CPPUNIT_ASSERT(libjami::getConversationPreferences(aliceId, convId).size() == 0); } @@ -3522,79 +2270,27 @@ void ConversationTest::testConversationPreferencesBeforeClone() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReadyBob = true; - } else if (accountId == bob2Id) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - std::map<std::string, std::string> preferencesBob, preferencesBob2; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationPreferencesUpdated>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> preferences) { - if (accountId == bobId) - preferencesBob = preferences; - else if (accountId == bob2Id) - preferencesBob2 = preferences; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); bobAccount->exportArchive(bobArchive); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReadyBob; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); // Set preferences Manager::instance().sendRegister(aliceId, false); - libjami::setConversationPreferences(bobId, convId, {{"foo", "bar"}, {"bar", "foo"}}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return preferencesBob.size() == 2; })); - CPPUNIT_ASSERT(preferencesBob["foo"] == "bar" && preferencesBob["bar"] == "foo"); + libjami::setConversationPreferences(bobId, bobData.conversationId, {{"foo", "bar"}, {"bar", "foo"}}); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.preferences.size() == 2; })); + CPPUNIT_ASSERT(bobData.preferences["foo"] == "bar" && bobData.preferences["bar"] == "foo"); // Bob2 should sync preferences std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); @@ -3607,71 +2303,20 @@ ConversationTest::testConversationPreferencesBeforeClone() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return bob2Started && conversationReadyBob2 && !preferencesBob2.empty(); + return bob2Data.deviceAnnounced && !bob2Data.conversationId.empty() && !bob2Data.preferences.empty(); })); - CPPUNIT_ASSERT(preferencesBob2["foo"] == "bar" && preferencesBob2["bar"] == "foo"); + CPPUNIT_ASSERT(bob2Data.preferences["foo"] == "bar" && bob2Data.preferences["bar"] == "foo"); } void ConversationTest::testConversationPreferencesMultiDevices() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReadyBob = true; - } else if (accountId == bob2Id) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - std::map<std::string, std::string> preferencesBob, preferencesBob2; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationPreferencesUpdated>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> preferences) { - if (accountId == bobId) - preferencesBob = preferences; - else if (accountId == bob2Id) - preferencesBob2 = preferences; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -3685,50 +2330,39 @@ ConversationTest::testConversationPreferencesMultiDevices() details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); - libjami::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReadyBob && conversationReadyBob2; })); - libjami::setConversationPreferences(bobId, convId, {{"foo", "bar"}, {"bar", "foo"}}); + cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && !bob2Data.conversationId.empty(); })); + libjami::setConversationPreferences(bobId, bobData.conversationId, {{"foo", "bar"}, {"bar", "foo"}}); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return preferencesBob.size() == 2 && preferencesBob2.size() == 2; + return bobData.preferences.size() == 2 && bob2Data.preferences.size() == 2; })); - CPPUNIT_ASSERT(preferencesBob["foo"] == "bar" && preferencesBob["bar"] == "foo"); - CPPUNIT_ASSERT(preferencesBob2["foo"] == "bar" && preferencesBob2["bar"] == "foo"); + CPPUNIT_ASSERT(bobData.preferences["foo"] == "bar" && bobData.preferences["bar"] == "foo"); + CPPUNIT_ASSERT(bob2Data.preferences["foo"] == "bar" && bob2Data.preferences["bar"] == "foo"); } void ConversationTest::testFixContactDetails() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::string convId = ""; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - aliceAccount->addContact(bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !convId.empty(); })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !aliceData.conversationId.empty(); })); auto details = aliceAccount->getContactDetails(bobUri); - CPPUNIT_ASSERT(details["conversationId"] == convId); + CPPUNIT_ASSERT(details["conversationId"] == aliceData.conversationId); // Erase convId from contact details, this should be fixed by next reload. - CPPUNIT_ASSERT(aliceAccount->updateConvForContact(bobUri, convId, "")); + CPPUNIT_ASSERT(aliceAccount->updateConvForContact(bobUri, aliceData.conversationId, "")); details = aliceAccount->getContactDetails(bobUri); CPPUNIT_ASSERT(details["conversationId"].empty()); @@ -3737,136 +2371,77 @@ ConversationTest::testFixContactDetails() std::this_thread::sleep_for(5s); // Let the daemon fix the structures details = aliceAccount->getContactDetails(bobUri); - CPPUNIT_ASSERT(details["conversationId"] == convId); + CPPUNIT_ASSERT(details["conversationId"] == aliceData.conversationId); } void ConversationTest::testRemoveOneToOneNotInDetails() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::string convId = "", secondConv; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - if (convId.empty()) - convId = conversationId; - else - secondConv = conversationId; - } - cv.notify_one(); - })); - bool conversationRemoved = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string& cid) { - if (accountId == aliceId && cid == secondConv) - conversationRemoved = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - aliceAccount->addContact(bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !convId.empty(); })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !aliceData.conversationId.empty(); })); auto details = aliceAccount->getContactDetails(bobUri); - CPPUNIT_ASSERT(details["conversationId"] == convId); + CPPUNIT_ASSERT(details["conversationId"] == aliceData.conversationId); + auto firstConv = aliceData.conversationId; // Create a duplicate std::this_thread::sleep_for(2s); // Avoid to get same id aliceAccount->convModule()->startConversation(ConversationMode::ONE_TO_ONE, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return !secondConv.empty(); })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return firstConv != aliceData.conversationId; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() - / "conversations" / secondConv; + auto repoPath = fileutils::get_data_dir() / aliceId + / "conversations" / aliceData.conversationId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); aliceAccount->convModule()->loadConversations(); // Check that conv is removed - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.removed; })); } void ConversationTest::testMessageEdition() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::vector<std::map<std::string, std::string>> messageBobReceived; - bool conversationReady = false, memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - if (accountId == bobId) { - messageBobReceived.emplace_back(message); - } else if (accountId == aliceId && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - auto errorDetected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); - auto msgSize = messageBobReceived.size(); + cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && aliceData.messages.size() == aliceMsgSize + 1; })); + + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageBobReceived.size() == msgSize + 1; })); - msgSize = messageBobReceived.size(); - auto editedId = messageBobReceived.rbegin()->at("id"); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.messages.size() == bobMsgSize + 1; })); + auto editedId = bobData.messages.rbegin()->id; + // Should trigger MessageUpdated + bobMsgSize = bobData.messagesUpdated.size(); libjami::sendMessage(aliceId, convId, "New body"s, editedId, 1); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return messageBobReceived.size() == msgSize + 1; })); - CPPUNIT_ASSERT(messageBobReceived.rbegin()->at("edit") == editedId); - CPPUNIT_ASSERT(messageBobReceived.rbegin()->at("body") == "New body"); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return bobData.messagesUpdated.size() == bobMsgSize + 1; })); + CPPUNIT_ASSERT(bobData.messagesUpdated.rbegin()->body.at("body") == "New body"); // Not an existing message - msgSize = messageBobReceived.size(); + bobMsgSize = bobData.messagesUpdated.size(); libjami::sendMessage(aliceId, convId, "New body"s, "invalidId", 1); CPPUNIT_ASSERT( - !cv.wait_for(lk, 10s, [&]() { return messageBobReceived.size() == msgSize + 1; })); + !cv.wait_for(lk, 10s, [&]() { return bobData.messagesUpdated.size() == bobMsgSize + 1; })); // Invalid author libjami::sendMessage(aliceId, convId, "New body"s, convId, 1); CPPUNIT_ASSERT( - !cv.wait_for(lk, 10s, [&]() { return messageBobReceived.size() == msgSize + 1; })); + !cv.wait_for(lk, 10s, [&]() { return bobData.messagesUpdated.size() == bobMsgSize + 1; })); // Add invalid edition Json::Value root; root["type"] = "application/edited-message"; @@ -3875,113 +2450,71 @@ ConversationTest::testMessageEdition() Json::StreamWriterBuilder wbuilder; wbuilder["commentStyle"] = "None"; wbuilder["indentation"] = ""; - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; auto message = Json::writeString(wbuilder, root); commitInRepo(repoPath, aliceAccount, message); - errorDetected = false; + bobData.errorDetected = false; libjami::sendMessage(aliceId, convId, "trigger"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); + } void ConversationTest::testMessageReaction() { std::cout << "\nRunning test: " << __func__ << std::endl; - - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - std::vector<std::map<std::string, std::string>> messageAliceReceived; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - if (accountId == aliceId) - messageAliceReceived.emplace_back(message); - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) - conversationReady = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + connectSignals(); auto convId = libjami::startConversation(aliceId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - auto msgSize = messageAliceReceived.size(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); + auto msgSize = aliceData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived.size() == msgSize + 1; })); - msgSize = messageAliceReceived.size(); - - auto reactId = messageAliceReceived.rbegin()->at("id"); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == msgSize + 1; })); + msgSize = aliceData.messages.size(); + // Add reaction + auto reactId = aliceData.messages.rbegin()->id; libjami::sendMessage(aliceId, convId, "👋"s, reactId, 2); CPPUNIT_ASSERT( - cv.wait_for(lk, 10s, [&]() { return messageAliceReceived.size() == msgSize + 1; })); - CPPUNIT_ASSERT(messageAliceReceived.rbegin()->at("react-to") == reactId); - CPPUNIT_ASSERT(messageAliceReceived.rbegin()->at("body") == "👋"); + cv.wait_for(lk, 10s, [&]() { return aliceData.reactions.size() == 1; })); + CPPUNIT_ASSERT(aliceData.reactions.rbegin()->at("react-to") == reactId); + CPPUNIT_ASSERT(aliceData.reactions.rbegin()->at("body") == "👋"); + auto emojiId = aliceData.reactions.rbegin()->at("id"); + + // Remove reaction + libjami::sendMessage(aliceId, convId, ""s, emojiId, 1); + CPPUNIT_ASSERT( + cv.wait_for(lk, 10s, [&]() { return aliceData.reactionRemoved.size() == 1; })); + CPPUNIT_ASSERT(emojiId == aliceData.reactionRemoved[0]); } void ConversationTest::testLoadPartiallyRemovedConversation() { std::cout << "\nRunning test: " << __func__ << std::endl; + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - std::string convId = ""; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } - cv.notify_one(); - })); - bool conversationRemoved = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == aliceId) - conversationRemoved = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Copy alice's conversation temporary - auto repoPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations" / convId; - std::filesystem::copy(repoPathAlice, fmt::format("./{}", convId), std::filesystem::copy_options::recursive); + auto repoPathAlice = fileutils::get_data_dir() / aliceId / "conversations" / aliceData.conversationId; + std::filesystem::copy(repoPathAlice, fmt::format("./{}", aliceData.conversationId), std::filesystem::copy_options::recursive); // removeContact aliceAccount->removeContact(bobUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.removed; })); std::this_thread::sleep_for(10s); // Wait for connection to close and async tasks to finish // Copy back alice's conversation - std::filesystem::copy(fmt::format("./{}", convId), repoPathAlice, std::filesystem::copy_options::recursive); - std::filesystem::remove_all(fmt::format("./{}", convId)); + std::filesystem::copy(fmt::format("./{}", aliceData.conversationId), repoPathAlice, std::filesystem::copy_options::recursive); + std::filesystem::remove_all(fmt::format("./{}", aliceData.conversationId)); // Reloading conversation should remove directory CPPUNIT_ASSERT(std::filesystem::is_directory(repoPathAlice)); diff --git a/test/unitTest/conversation/conversationMembersEvent.cpp b/test/unitTest/conversation/conversationMembersEvent.cpp index e3730f103c44cc0be68a554ae62f54748bbcba57..8efab0997eaeda825af00499c8e63895fad10bb5 100644 --- a/test/unitTest/conversation/conversationMembersEvent.cpp +++ b/test/unitTest/conversation/conversationMembersEvent.cpp @@ -44,6 +44,21 @@ using namespace libjami::Account; namespace jami { namespace test { +struct UserData { + std::string conversationId; + bool removed {false}; + bool requestReceived {false}; + bool requestRemoved {false}; + bool errorDetected {false}; + bool registered {false}; + bool stopped {false}; + bool deviceAnnounced {false}; + bool contactRemoved {false}; + std::string payloadTrustRequest; + std::vector<libjami::SwarmMessage> messages; + std::vector<libjami::SwarmMessage> messagesUpdated; +}; + class ConversationMembersEventTest : public CppUnit::TestFixture { public: @@ -90,15 +105,22 @@ public: void testBanHostWhileHosting(); void testRemoveContactTwice(); void testAddContactTwice(); + void testBanFromNewDevice(); std::string aliceId; + UserData aliceData; std::string bobId; + UserData bobData; std::string bob2Id; + UserData bob2Data; std::string carlaId; + UserData carlaData; std::mutex mtx; std::unique_lock<std::mutex> lk {mtx}; std::condition_variable cv; + void connectSignals(); + private: CPPUNIT_TEST_SUITE(ConversationMembersEventTest); CPPUNIT_TEST(testRemoveConversationNoMember); @@ -136,6 +158,7 @@ private: CPPUNIT_TEST(testBanHostWhileHosting); CPPUNIT_TEST(testRemoveContactTwice); CPPUNIT_TEST(testAddContactTwice); + CPPUNIT_TEST(testBanFromNewDevice); CPPUNIT_TEST_SUITE_END(); }; @@ -145,6 +168,8 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConversationMembersEventTest, void ConversationMembersEventTest::setUp() { + connectSignals(); + // Init daemon libjami::init( libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG)); @@ -156,6 +181,11 @@ ConversationMembersEventTest::setUp() bobId = actors["bob"]; carlaId = actors["carla"]; + aliceData = {}; + bobData = {}; + bob2Data = {}; + carlaData = {}; + Manager::instance().sendRegister(carlaId, false); wait_for_announcement_of({aliceId, bobId}); } @@ -163,6 +193,8 @@ ConversationMembersEventTest::setUp() void ConversationMembersEventTest::tearDown() { + connectSignals(); + auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); if (bob2Id.empty()) { @@ -172,6 +204,178 @@ ConversationMembersEventTest::tearDown() } } +void +ConversationMembersEventTest::connectSignals() +{ + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string& accountId, const std::map<std::string, std::string>&) { + if (accountId == aliceId) { + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto details = aliceAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + aliceData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + aliceData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + aliceData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bobId) { + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto details = bobAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bobData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bobData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bobData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bob2Id) { + auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); + auto details = bob2Account->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bob2Data.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bob2Data.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bob2Data.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == carlaId) { + auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); + auto details = carlaAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + carlaData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + carlaData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + carlaData.deviceAnnounced = deviceAnnounced == "true"; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == aliceId) { + aliceData.conversationId = conversationId; + } else if (accountId == bobId) { + bobData.conversationId = conversationId; + } else if (accountId == bob2Id) { + bob2Data.conversationId = conversationId; + } else if (accountId == carlaId) { + carlaData.conversationId = conversationId; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( + [&](const std::string& account_id, + const std::string& /*from*/, + const std::string& /*conversationId*/, + const std::vector<uint8_t>& payload, + time_t /*received*/) { + auto payloadStr = std::string(payload.data(), payload.data() + payload.size()); + if (account_id == aliceId) + aliceData.payloadTrustRequest = payloadStr; + else if (account_id == bobId) + bobData.payloadTrustRequest = payloadStr; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + std::map<std::string, std::string> /*metadatas*/) { + if (accountId == aliceId) { + aliceData.requestReceived = true; + } else if (accountId == bobId) { + bobData.requestReceived = true; + } else if (accountId == bob2Id) { + bob2Data.requestReceived = true; + } else if (accountId == carlaId) { + carlaData.requestReceived = true; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( + [&](const std::string& accountId, const std::string&) { + if (accountId == bobId) { + bobData.requestRemoved = true; + } else if (accountId == bob2Id) { + bob2Data.requestRemoved = true; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messages.emplace_back(message); + } else if (accountId == bobId) { + bobData.messages.emplace_back(message); + } else if (accountId == bob2Id) { + bob2Data.messages.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messages.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageUpdated>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messagesUpdated.emplace_back(message); + } else if (accountId == bobId) { + bobData.messagesUpdated.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messagesUpdated.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + int /*code*/, + const std::string& /* what */) { + if (accountId == aliceId) + aliceData.errorDetected = true; + else if (accountId == bobId) + bobData.errorDetected = true; + else if (accountId == carlaId) + carlaData.errorDetected = true; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( + [&](const std::string& accountId, const std::string&) { + if (accountId == aliceId) + aliceData.removed = true; + else if (accountId == bobId) + bobData.removed = true; + else if (accountId == bob2Id) + bob2Data.removed = true; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( + [&](const std::string& accountId, const std::string&, bool) { + if (accountId == bobId) { + bobData.contactRemoved = true; + } else if (accountId == bob2Id) { + bob2Data.contactRemoved = true; + } + cv.notify_one(); + })); + libjami::registerSignalHandlers(confHandlers); +} + void ConversationMembersEventTest::generateFakeInvite(std::shared_ptr<JamiAccount> account, const std::string& convId, @@ -221,28 +425,16 @@ ConversationMembersEventTest::generateFakeInvite(std::shared_ptr<JamiAccount> ac void ConversationMembersEventTest::testRemoveConversationNoMember() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto uri = aliceAccount->getUsername(); - - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == aliceId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + connectSignals(); // Start conversation auto convId = libjami::startConversation(aliceId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !aliceData.conversationId.empty(); })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; - auto dataPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto dataPath = fileutils::get_data_dir() / aliceId / "conversation_data" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); CPPUNIT_ASSERT(std::filesystem::is_directory(dataPath)); @@ -260,73 +452,35 @@ ConversationMembersEventTest::testRemoveConversationNoMember() void ConversationMembersEventTest::testRemoveConversationWithMember() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - bobSeeAliceRemoved = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - auto itFind = message.find("type"); - if (itFind == message.end()) - return; - if (accountId == aliceId && conversationId == convId && itFind->second == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } else if (accountId == bobId && conversationId == convId - && itFind->second == "member") { - bobSeeAliceRemoved = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvitedFile = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvitedFile)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - auto clonedPath = fileutils::get_data_dir() / bobAccount->getAccountID() + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); + auto clonedPath = fileutils::get_data_dir() / bobId / "conversations" / convId; - CPPUNIT_ASSERT(std::filesystem::is_directory(clonedPath)); bobInvitedFile = clonedPath / "invited" / bobUri; CPPUNIT_ASSERT(!std::filesystem::is_regular_file(bobInvitedFile)); // Remove conversation from alice once member confirmed - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - bobSeeAliceRemoved = false; + auto bobMsgSize = bobData.messages.size(); libjami::removeConversation(aliceId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobSeeAliceRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size() && bobData.messages.rbegin()->type == "member"; })); std::this_thread::sleep_for(3s); CPPUNIT_ASSERT(!std::filesystem::is_directory(repoPath)); } @@ -334,50 +488,24 @@ ConversationMembersEventTest::testRemoveConversationWithMember() void ConversationMembersEventTest::testAddMember() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - auto clonedPath = fileutils::get_data_dir() / bobAccount->getAccountID() + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); + auto clonedPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(clonedPath)); bobInvited = clonedPath / "invited" / bobUri; @@ -389,38 +517,13 @@ ConversationMembersEventTest::testAddMember() void ConversationMembersEventTest::testMemberAddedNoBadFile() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, errorDetected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& accountId, - const std::string& conversationId, - int code, - const std::string& /* what */) { - if (accountId == bobId && conversationId == convId && code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + addFile(aliceAccount, convId, "BADFILE"); // NOTE: Add certificate because no DHT lookup aliceAccount->certStore().pinCertificate(bobAccount->identity().second); @@ -430,51 +533,31 @@ ConversationMembersEventTest::testMemberAddedNoBadFile() std::string(bobAccount->currentDeviceId()), {{"application/invite+json", "{\"conversationId\":\"" + convId + "\"}"}}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - errorDetected = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationMembersEventTest::testAddOfflineMemberThenConnects() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == carlaId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(aliceId, convId, carlaUri); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.requestReceived; })); libjami::acceptConversationRequest(carlaId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - auto clonedPath = fileutils::get_data_dir() / carlaAccount->getAccountID() + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !carlaData.conversationId.empty(); })); + auto clonedPath = fileutils::get_data_dir() / carlaId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(clonedPath)); - libjami::unregisterSignalHandlers(); } void @@ -521,48 +604,19 @@ ConversationMembersEventTest::testAddAcceptOfflineThenConnects() void ConversationMembersEventTest::testGetMembers() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageReceived = false; - bool requestReceived = false; - bool conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == aliceId) { - messageReceived = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); // Start a conversation and add member auto convId = libjami::startConversation(aliceId); - messageReceived = false; libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return messageReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return bobData.requestReceived; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); @@ -573,74 +627,39 @@ ConversationMembersEventTest::testGetMembers() CPPUNIT_ASSERT(members[1]["uri"] == bobUri); CPPUNIT_ASSERT(members[1]["role"] == "invited"); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - messageReceived = false; + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - cv.wait_for(lk, 30s, [&]() { return conversationReady; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); members = libjami::getConversationMembers(bobId, convId); CPPUNIT_ASSERT(members.size() == 2); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return messageReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); members = libjami::getConversationMembers(aliceId, convId); CPPUNIT_ASSERT(members.size() == 2); CPPUNIT_ASSERT(members[0]["uri"] == aliceAccount->getUsername()); CPPUNIT_ASSERT(members[0]["role"] == "admin"); CPPUNIT_ASSERT(members[1]["uri"] == bobUri); CPPUNIT_ASSERT(members[1]["role"] == "member"); - libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testRemoveMember() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - cv.notify_one(); - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - voteMessageGenerated = false; libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 3 /* vote + ban */; })); auto members = libjami::getConversationMembers(aliceId, convId); auto bobBanned = false; for (auto& member : members) { @@ -648,146 +667,65 @@ ConversationMembersEventTest::testRemoveMember() bobBanned = member["role"] == "banned"; } CPPUNIT_ASSERT(bobBanned); - libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testRemovedMemberDoesNotReceiveMessage() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - bool memberMessageGenerated = false, voteMessageGenerated = false, messageBobReceived = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") - voteMessageGenerated = true; - else if (accountId == aliceId && conversationId == convId && message["type"] == "member") - memberMessageGenerated = true; - else if (accountId == bobId && conversationId == convId) - messageBobReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - voteMessageGenerated = false; libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 3 /* vote + ban */; })); // Now, bob is banned so they shoud not receive any message - messageBobReceived = false; + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return messageBobReceived; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); })); } void ConversationMembersEventTest::testRemoveInvitedMember() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto carlaUri = carlaAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - bool carlaConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - bool voteMessageGenerated = false, memberMessageGenerated = false, carlaMessageReceived; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") - voteMessageGenerated = true; - else if (accountId == aliceId && conversationId == convId && message["type"] == "member") - memberMessageGenerated = true; - else if (accountId == carlaId && message["type"] == "text/plain" - && message["body"] == "hi") - carlaMessageReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Add carla Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.deviceAnnounced; })); libjami::addConversationMember(aliceId, convId, carlaUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(carlaId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Invite Alice - requestReceived = false; libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); auto members = libjami::getConversationMembers(aliceId, convId); CPPUNIT_ASSERT(members.size() == 3); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - voteMessageGenerated = false; + aliceMsgSize = aliceData.messages.size(); libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); members = libjami::getConversationMembers(aliceId, convId); auto bobBanned = false; for (auto& member : members) { @@ -797,14 +735,16 @@ ConversationMembersEventTest::testRemoveInvitedMember() CPPUNIT_ASSERT(bobBanned); // Check that Carla is still able to sync + auto carlaMsgSize = carlaData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaMessageReceived; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return carlaMsgSize + 1 == carlaData.messages.size(); })); } void ConversationMembersEventTest::testMemberBanNoBadFile() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); @@ -814,190 +754,69 @@ ConversationMembersEventTest::testMemberBanNoBadFile() auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, errorDetected = false, - carlaConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& accountId, - const std::string& conversationId, - int code, - const std::string& /* what */) { - if (accountId == bobId && conversationId == convId && code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::addConversationMember(aliceId, convId, carlaUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived; })); + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::acceptConversationRequest(carlaId, convId); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); - memberMessageGenerated = false; - voteMessageGenerated = false; addFile(aliceAccount, convId, "BADFILE"); libjami::removeConversationMember(aliceId, convId, carlaUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationMembersEventTest::testMemberTryToRemoveAdmin() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") - memberMessageGenerated = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; libjami::removeConversationMember(bobId, convId, aliceUri); auto members = libjami::getConversationMembers(aliceId, convId); - CPPUNIT_ASSERT(members.size() == 2 && !memberMessageGenerated); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(members.size() == 2 && aliceMsgSize + 2 != aliceData.messages.size()); } void ConversationMembersEventTest::testBannedMemberCannotSendMessage() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, aliceMessageReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "text/plain") { - aliceMessageReceived = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); - memberMessageGenerated = false; - voteMessageGenerated = false; libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 3 == aliceData.messages.size(); })); auto members = libjami::getConversationMembers(aliceId, convId); auto bobBanned = false; @@ -1008,65 +827,33 @@ ConversationMembersEventTest::testBannedMemberCannotSendMessage() CPPUNIT_ASSERT(bobBanned); // Now check that alice doesn't receive a message from Bob - aliceMessageReceived = false; libjami::sendMessage(bobId, convId, "hi"s, ""); - CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return aliceMessageReceived; })); + CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 4 == aliceData.messages.size(); })); libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testAdminCanReAddMember() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - cv.notify_one(); - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - voteMessageGenerated = false; libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 3 == aliceData.messages.size(); })); auto members = libjami::getConversationMembers(aliceId, convId); @@ -1078,211 +865,96 @@ ConversationMembersEventTest::testAdminCanReAddMember() CPPUNIT_ASSERT(bobBanned); // Then check that bobUri can be re-added - memberMessageGenerated = false, voteMessageGenerated = false; + aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); members = libjami::getConversationMembers(aliceId, convId); CPPUNIT_ASSERT(members.size() == 2); - libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testMemberCannotBanOther() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, errorDetected = false, - carlaConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string&, const std::string&, std::map<std::string, std::string>) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::addConversationMember(aliceId, convId, carlaUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived; })); + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::acceptConversationRequest(carlaId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); // Now Carla remove Bob as a member - errorDetected = false; - messageBobReceived = false; // remove from member & add into banned without voting for the ban simulateRemoval(carlaAccount, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.errorDetected; })); + bobMsgSize = bobData.messages.size(); libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageBobReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); })); } void ConversationMembersEventTest::testMemberCannotUnBanOther() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, errorDetected = false, - carlaConnected = false, messageCarlaReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string&, const std::string&, std::map<std::string, std::string>) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } else if (accountId == carlaId && conversationId == convId) { - messageCarlaReceived = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::addConversationMember(aliceId, convId, carlaUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived; })); + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::acceptConversationRequest(carlaId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - messageCarlaReceived = false; - voteMessageGenerated = false; + auto carlaMsgSize = carlaData.messages.size(); libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return memberMessageGenerated && voteMessageGenerated && messageCarlaReceived; + return carlaMsgSize + 2 == carlaData.messages.size();; })); - memberMessageGenerated = false; - voteMessageGenerated = false; + aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(carlaId, convId, bobUri); CPPUNIT_ASSERT( - !cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + !cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size();; })); auto members = libjami::getConversationMembers(aliceId, convId); auto bobBanned = false; for (auto& member : members) { @@ -1295,134 +967,46 @@ ConversationMembersEventTest::testMemberCannotUnBanOther() void ConversationMembersEventTest::testCheckAdminFakeAVoteIsDetected() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, messageBobReceived = false, errorDetected = false, - carlaConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) { - messageBobReceived = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.deviceAnnounced; })); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; + cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - requestReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::addConversationMember(aliceId, convId, carlaUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestReceived && memberMessageGenerated; })); - memberMessageGenerated = false; - messageBobReceived = false; + cv.wait_for(lk, 30s, [&]() { return carlaData.requestReceived; })); + aliceMsgSize = aliceData.messages.size(); + auto bobMsgSize = bobData.messages.size(); libjami::acceptConversationRequest(carlaId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && messageBobReceived; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size() && bobMsgSize + 1 == bobData.messages.size(); })); // Now Alice remove Carla without a vote. Bob will not receive the message - errorDetected = false; simulateRemoval(aliceAccount, convId, carlaUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationMembersEventTest::testAdminCannotKickTheirself() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto aliceUri = aliceAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - voteMessageGenerated = false, aliceMessageReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == aliceId && conversationId == convId - && message["type"] == "text/plain") { - aliceMessageReceived = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); auto members = libjami::getConversationMembers(aliceId, convId); CPPUNIT_ASSERT(members.size() == 1); libjami::removeConversationMember(aliceId, convId, aliceUri); @@ -1433,68 +1017,26 @@ ConversationMembersEventTest::testAdminCannotKickTheirself() void ConversationMembersEventTest::testCommitUnauthorizedUser() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto bobUri = bobAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool errorDetected = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size();; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); - // Wait that alice sees Bob - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 2; })); // Add commit from invalid user Json::Value root; @@ -1506,73 +1048,33 @@ ConversationMembersEventTest::testCommitUnauthorizedUser() auto message = Json::writeString(wbuilder, root); commitInRepo(repoPath, carlaAccount, message); - errorDetected = false; libjami::sendMessage(bobId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.errorDetected; })); libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testMemberJoinsNoBadFile() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, errorDetected = false, carlaConnected = false, - memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == carlaId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto aliceMsgSize = aliceData.messages.size(); aliceAccount->convModule()->addConversationMember(convId, carlaUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Cp conversations & convInfo - auto repoPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations"; - auto repoPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "conversations"; + auto repoPathAlice = fileutils::get_data_dir() / aliceId / "conversations"; + auto repoPathCarla = fileutils::get_data_dir() / carlaId / "conversations"; std::filesystem::copy(repoPathAlice, repoPathCarla, std::filesystem::copy_options::recursive); - auto ciPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto ciPathAlice = fileutils::get_data_dir() / aliceId / "convInfo"; - auto ciPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() + auto ciPathCarla = fileutils::get_data_dir() / carlaId / "convInfo"; std::remove(ciPathCarla.c_str()); std::filesystem::copy(ciPathAlice, ciPathCarla); @@ -1603,76 +1105,35 @@ ConversationMembersEventTest::testMemberJoinsNoBadFile() // Start Carla, should merge and all messages should be there carlaAccount->convModule()->loadConversations(); // Because of the copy Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); - errorDetected = false; libjami::sendMessage(carlaId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return aliceData.errorDetected; })); } void ConversationMembersEventTest::testMemberAddedNoCertificate() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, errorDetected = false, carlaConnected = false, - memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == carlaId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto aliceMsgSize = aliceData.messages.size(); aliceAccount->convModule()->addConversationMember(convId, carlaUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Cp conversations & convInfo - auto repoPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations"; - auto repoPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "conversations"; + auto repoPathAlice = fileutils::get_data_dir() / aliceId / "conversations"; + auto repoPathCarla = fileutils::get_data_dir() / carlaId / "conversations"; std::filesystem::copy(repoPathAlice, repoPathCarla, std::filesystem::copy_options::recursive); - auto ciPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto ciPathAlice = fileutils::get_data_dir() / aliceId / "convInfo"; - auto ciPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() + auto ciPathCarla = fileutils::get_data_dir() / carlaId / "convInfo"; std::remove(ciPathCarla.c_str()); std::filesystem::copy(ciPathAlice, ciPathCarla); @@ -1694,75 +1155,34 @@ ConversationMembersEventTest::testMemberAddedNoCertificate() // Start Carla, should merge and all messages should be there carlaAccount->convModule()->loadConversations(); // Because of the copy Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); libjami::sendMessage(carlaId, convId, "hi"s, ""); - errorDetected = false; - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return aliceData.errorDetected; })); } void ConversationMembersEventTest::testMemberJoinsInviteRemoved() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, errorDetected = false, carlaConnected = false, - memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == carlaId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = carlaAccount->getVolatileAccountDetails(); - auto deviceAnnounced - = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; - if (deviceAnnounced == "true") { - carlaConnected = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + auto aliceMsgSize = aliceData.messages.size(); aliceAccount->convModule()->addConversationMember(convId, carlaUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&] { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Cp conversations & convInfo - auto repoPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "conversations"; - auto repoPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "conversations"; + auto repoPathAlice = fileutils::get_data_dir() / aliceId / "conversations"; + auto repoPathCarla = fileutils::get_data_dir() / carlaId / "conversations"; std::filesystem::copy(repoPathAlice, repoPathCarla, std::filesystem::copy_options::recursive); - auto ciPathAlice = fileutils::get_data_dir() / aliceAccount->getAccountID() / "convInfo"; - auto ciPathCarla = fileutils::get_data_dir() / carlaAccount->getAccountID() / "convInfo"; + auto ciPathAlice = fileutils::get_data_dir() / aliceId / "convInfo"; + auto ciPathCarla = fileutils::get_data_dir() / carlaId / "convInfo"; std::remove(ciPathCarla.c_str()); std::filesystem::copy(ciPathAlice, ciPathCarla); @@ -1792,186 +1212,78 @@ ConversationMembersEventTest::testMemberJoinsInviteRemoved() // Start Carla, should merge and all messages should be there carlaAccount->convModule()->loadConversations(); // Because of the copy Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); libjami::sendMessage(carlaId, convId, "hi"s, ""); - errorDetected = false; - - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return errorDetected; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return aliceData.errorDetected; })); } void ConversationMembersEventTest::testFailAddMemberInOneToOne() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); auto carlaUri = carlaAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !convId.empty(); })); - memberMessageGenerated = false; - libjami::addConversationMember(aliceId, convId, carlaUri); - CPPUNIT_ASSERT(!cv.wait_for(lk, 5s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + libjami::addConversationMember(aliceId, aliceData.conversationId, carlaUri); + CPPUNIT_ASSERT(!cv.wait_for(lk, 5s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); } void ConversationMembersEventTest::testOneToOneFetchWithNewMemberRefused() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); auto carlaUri = carlaAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - messageBob = false, errorDetected = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId - && message["type"] == "member") { - messageBob = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - int code, - const std::string& /* what */) { - if (code == 3) - errorDetected = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - memberMessageGenerated = false; CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size();; })); - errorDetected = false; // NOTE: Add certificate because no DHT lookup aliceAccount->certStore().pinCertificate(carlaAccount->identity().second); - generateFakeInvite(aliceAccount, convId, carlaUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return errorDetected; })); + generateFakeInvite(aliceAccount, aliceData.conversationId, carlaUri); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.errorDetected; })); } void ConversationMembersEventTest::testConversationMemberEvent() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberAddGenerated = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& /* conversationId */) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationMemberEvent>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& uri, - int event) { - if (accountId == aliceId && conversationId == convId && uri == bobUri - && event == 0) { - memberAddGenerated = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberAddGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto repoPath = fileutils::get_data_dir() / aliceId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); // Check created files auto bobInvited = repoPath / "invited" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobInvited)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - auto clonedPath = fileutils::get_data_dir() / bobAccount->getAccountID() + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); + auto clonedPath = fileutils::get_data_dir() / bobId / "conversations" / convId; CPPUNIT_ASSERT(std::filesystem::is_directory(clonedPath)); bobInvited = clonedPath / "invited" / bobUri; @@ -1983,42 +1295,20 @@ ConversationMembersEventTest::testConversationMemberEvent() void ConversationMembersEventTest::testGetConversationsMembersWhileSyncing() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - auto members = libjami::getConversationMembers(bobId, convId); + auto members = libjami::getConversationMembers(bobId, aliceData.conversationId); CPPUNIT_ASSERT(std::find_if(members.begin(), members.end(), [&](auto memberInfo) { return memberInfo["uri"] == aliceUri; }) @@ -2032,6 +1322,8 @@ ConversationMembersEventTest::testGetConversationsMembersWhileSyncing() void ConversationMembersEventTest::testGetConversationMembersWithSelfOneOne() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto aliceUri = aliceAccount->getUsername(); std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; @@ -2054,66 +1346,25 @@ ConversationMembersEventTest::testGetConversationMembersWithSelfOneOne() void ConversationMembersEventTest::testAvoidTwoOneToOne() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId && conversationId == convId) { - conversationReadyBob = true; - } - cv.notify_one(); - })); - auto memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - } - cv.notify_one(); - })); - auto conversationRmBob = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRmBob = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - libjami::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReadyBob && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 1; })); // Remove contact bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRmBob; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); // wait that connections are closed. std::this_thread::sleep_for(10s); @@ -2121,78 +1372,19 @@ ConversationMembersEventTest::testAvoidTwoOneToOne() // Bob add Alice, this should re-add old conversation bobAccount->addContact(aliceUri); bobAccount->sendTrustRequest(aliceUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReadyBob; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.conversationId == aliceData.conversationId; })); } void ConversationMembersEventTest::testAvoidTwoOneToOneMultiDevices() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId = ""; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId && conversationId == convId) { - conversationReadyBob = true; - } else if (accountId == bob2Id && conversationId == convId) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "member") - memberMessageGenerated = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto conversationRmBob = false, conversationRmBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRmBob = true; - else if (accountId == bob2Id) - conversationRmBob2 = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -2207,21 +1399,21 @@ ConversationMembersEventTest::testAvoidTwoOneToOneMultiDevices() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); - libjami::acceptConversationRequest(bobId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationReadyBob && conversationReadyBob2 && memberMessageGenerated; + return !bobData.conversationId.empty() && !bob2Data.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Remove contact bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRmBob && conversationRmBob2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed && bob2Data.removed; })); // wait that connections are closed. std::this_thread::sleep_for(10s); @@ -2230,52 +1422,19 @@ ConversationMembersEventTest::testAvoidTwoOneToOneMultiDevices() bobAccount->addContact(aliceUri); bobAccount->sendTrustRequest(aliceUri, {}); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReadyBob && conversationReadyBob2; })); + cv.wait_for(lk, 30s, [&]() { return bobData.conversationId == aliceData.conversationId && bob2Data.conversationId == aliceData.conversationId; })); } void ConversationMembersEventTest::testRemoveRequestBannedMultiDevices() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto bob2ContactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool banned) { - if (accountId == bob2Id && uri == aliceUri && banned) { - bob2ContactRemoved = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -2290,92 +1449,29 @@ ConversationMembersEventTest::testRemoveRequestBannedMultiDevices() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); CPPUNIT_ASSERT(libjami::getConversationRequests(bob2Id).size() == 1); // Bob bans alice, should update bob2 bobAccount->removeContact(aliceUri, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2ContactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.contactRemoved; })); CPPUNIT_ASSERT(libjami::getConversationRequests(bob2Id).size() == 0); } void ConversationMembersEventTest::testBanUnbanMultiDevice() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto bob2ContactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool banned) { - if (accountId == bob2Id && uri == aliceUri && banned) { - bob2ContactRemoved = true; - } - cv.notify_one(); - })); - auto memberMessageGenerated = false, voteMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - auto itFind = message.find("type"); - if (itFind == message.end()) - return; - if (accountId == aliceId && conversationId == convId) { - if (itFind->second == "member") - memberMessageGenerated = true; - if (itFind->second == "vote") - voteMessageGenerated = true; - } - cv.notify_one(); - })); - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReadyBob = true; - } else if (accountId == bob2Id && conversationId == convId) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -2390,117 +1486,40 @@ ConversationMembersEventTest::testBanUnbanMultiDevice() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false; libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return memberMessageGenerated && requestReceived && requestReceivedBob2; - })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); // Alice kick Bob while invited - memberMessageGenerated = false; - voteMessageGenerated = false; + auto aliceMsgSize = aliceData.messages.size(); libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); // Alice re-add Bob while invited - memberMessageGenerated = false; - voteMessageGenerated = false; + aliceMsgSize = aliceData.messages.size(); libjami::addConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); // bob accepts libjami::acceptConversationRequest(bobId, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReadyBob && conversationReadyBob2; })); + cv.wait_for(lk, 30s, [&]() { return bobData.conversationId == aliceData.conversationId && bob2Data.conversationId == aliceData.conversationId; })); } void ConversationMembersEventTest::testBanUnbanGotFirstConv() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, requestReceivedBob2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - else if (accountId == bob2Id) - requestReceivedBob2 = true; - cv.notify_one(); - })); - std::string convId; - auto conversationReadyBob = false, conversationReadyBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId && conversationId == convId) { - conversationReadyBob = true; - } else if (accountId == bob2Id && conversationId == convId) { - conversationReadyBob2 = true; - } - cv.notify_one(); - })); - auto bob2Started = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (accountId == bob2Id) { - auto daemonStatus = details.at( - libjami::Account::VolatileProperties::DEVICE_ANNOUNCED); - if (daemonStatus == "true") - bob2Started = true; - } - cv.notify_one(); - })); - auto bob2ContactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool banned) { - if (accountId == bob2Id && uri == aliceUri && banned) { - bob2ContactRemoved = true; - } - cv.notify_one(); - })); - auto bobMsgReceived = false, bob2MsgReceived = false, memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId) { - auto itFind = message.find("type"); - if (itFind != message.end() && itFind->second == "member") - memberMessageGenerated = true; - } else if (accountId == bobId && conversationId == convId) - bobMsgReceived = true; - else if (accountId == bob2Id && conversationId == convId) - bob2MsgReceived = true; - cv.notify_one(); - })); - auto contactAddedBob = false, contactAddedBob2 = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactAdded>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) { - contactAddedBob = true; - } else if (accountId == bob2Id && uri == aliceUri) { - contactAddedBob2 = true; - } - cv.notify_one(); - })); - - libjami::registerSignalHandlers(confHandlers); - // Bob creates a second device auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; std::remove(bobArchive.c_str()); @@ -2515,105 +1534,72 @@ ConversationMembersEventTest::testBanUnbanGotFirstConv() details[ConfProperties::ARCHIVE_PATH] = bobArchive; bob2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Started; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); // Alice adds bob - requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived && requestReceivedBob2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && bob2Data.requestReceived; })); CPPUNIT_ASSERT(libjami::getConversationRequests(bob2Id).size() == 1); // Accepts requests - libjami::acceptConversationRequest(bobId, convId); + auto aliceMsgSize = aliceData.messages.size(); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationReadyBob && conversationReadyBob2 && memberMessageGenerated; + return !bobData.conversationId.empty() && !bob2Data.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Bob bans alice, should update bob2 bobAccount->removeContact(aliceUri, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2ContactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.contactRemoved; })); // Alice sends messages, bob & bob2 should not get it! - bobMsgReceived = false, bob2MsgReceived = false; - libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return bobMsgReceived && bob2MsgReceived; })); + auto bobMsgSize = bobData.messages.size(); + auto bob2MsgSize = bob2Data.messages.size(); + libjami::sendMessage(aliceId, aliceData.conversationId, "hi"s, ""); + CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return bobMsgSize != bobData.messages.size() && bob2MsgSize != bob2Data.messages.size(); })); // Bobs re-add Alice - contactAddedBob = false, contactAddedBob2 = false; bobAccount->addContact(aliceUri); bobAccount->sendTrustRequest(aliceUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactAddedBob && contactAddedBob2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.conversationId == aliceData.conversationId && bob2Data.conversationId == aliceData.conversationId; })); // Alice can sends some messages now - bobMsgReceived = false, bob2MsgReceived = false; - libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgReceived && bob2MsgReceived; })); + bobMsgSize = bobData.messages.size(); + bob2MsgSize = bob2Data.messages.size(); + libjami::sendMessage(aliceId, aliceData.conversationId, "hi"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize != bobData.messages.size() && bob2MsgSize != bob2Data.messages.size(); })); } void ConversationMembersEventTest::testBanHostWhileHosting() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto aliceUri = aliceAccount->getUsername(); auto bobUri = bobAccount->getUsername(); auto convId = libjami::startConversation(aliceId); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - bool memberMessageGenerated = false, callMessageGenerated = false, voteMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "vote") { - voteMessageGenerated = true; - cv.notify_one(); - } else if (accountId == aliceId && conversationId == convId) { - if (message["type"] == "application/call-history+json") { - callMessageGenerated = true; - } else if (message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Now, Bob starts a call + aliceMsgSize = aliceData.messages.size(); auto callId = libjami::placeCallWithMedia(bobId, "swarm:" + convId, {}); // should get message - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return callMessageGenerated; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize != aliceData.messages.size(); })); // get active calls = 1 CPPUNIT_ASSERT(libjami::getActiveCalls(aliceId, convId).size() == 1); // Now check that alice, has the only admin, can remove bob - memberMessageGenerated = false; - voteMessageGenerated = false; + aliceMsgSize = aliceData.messages.size(); libjami::removeConversationMember(aliceId, convId, bobUri); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated && voteMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); auto members = libjami::getConversationMembers(aliceId, convId); auto bobBanned = false; for (auto& member : members) { @@ -2621,141 +1607,120 @@ ConversationMembersEventTest::testBanHostWhileHosting() bobBanned = member["role"] == "banned"; } CPPUNIT_ASSERT(bobBanned); - - libjami::unregisterSignalHandlers(); } void ConversationMembersEventTest::testRemoveContactTwice() { + connectSignals(); + std::cout << "\nRunning test: " << __func__ << std::endl; auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string&, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - std::string convId = ""; auto conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) - convId = conversationId; - else if (accountId == bobId) - conversationReady = true; - cv.notify_one(); - })); - auto conversationRemoved = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRemoved = true; - cv.notify_one(); - })); - auto contactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) - contactRemoved = true; - cv.notify_one(); - })); - auto memberMessageGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - if (accountId == aliceId && message["type"] == "member") - memberMessageGenerated = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // removeContact bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); // wait that connections are closed. std::this_thread::sleep_for(10s); // re-add via a new message. Trigger a new request - requestReceived = false; - libjami::sendMessage(aliceId, convId, "foo"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + bobData.requestReceived = false; + libjami::sendMessage(aliceId, aliceData.conversationId, "foo"s, ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // removeContact again (should remove the trust request/conversation) - contactRemoved = false; + bobData.removed = false; bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); } void ConversationMembersEventTest::testAddContactTwice() { + connectSignals(); std::cout << "\nRunning test: " << __func__ << std::endl; auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string&, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - std::string convId = ""; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) - convId = conversationId; - cv.notify_one(); - })); - auto requestDeclined = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - requestDeclined = true; - cv.notify_one(); - })); - auto contactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == aliceId && uri == bobUri) - contactRemoved = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return requestReceived; })); - requestReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return bobData.requestReceived; })); aliceAccount->removeContact(bobUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return contactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return aliceData.removed; })); // wait that connections are closed. std::this_thread::sleep_for(10s); + bobData.requestReceived = false; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return requestDeclined && requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&]() { return bobData.requestRemoved && bobData.requestReceived; })); +} + +void +ConversationMembersEventTest::testBanFromNewDevice() +{ + connectSignals(); + + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); + auto aliceUri = aliceAccount->getUsername(); + auto bobUri = bobAccount->getUsername(); + auto carlaUri = carlaAccount->getUsername(); + + Manager::instance().sendRegister(carlaId, true); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return carlaData.deviceAnnounced; })); + + auto convId = libjami::startConversation(bobId); + + libjami::addConversationMember(bobId, convId, aliceUri); + libjami::addConversationMember(bobId, convId, carlaUri); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return carlaData.requestReceived; })); + + libjami::acceptConversationRequest(carlaId, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !carlaData.conversationId.empty(); })); + + Manager::instance().sendRegister(carlaId, false); + + // Bob creates a second device + auto bobArchive = std::filesystem::current_path().string() + "/bob.gz"; + std::remove(bobArchive.c_str()); + bobAccount->exportArchive(bobArchive); + std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); + details[ConfProperties::TYPE] = "RING"; + details[ConfProperties::DISPLAYNAME] = "BOB2"; + details[ConfProperties::ALIAS] = "BOB2"; + details[ConfProperties::UPNP_ENABLED] = "true"; + details[ConfProperties::ARCHIVE_PASSWORD] = ""; + details[ConfProperties::ARCHIVE_PIN] = ""; + details[ConfProperties::ARCHIVE_PATH] = bobArchive; + bob2Id = Manager::instance().addAccount(details); + + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bob2Data.deviceAnnounced; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bob2Data.conversationId.empty(); })); + + + auto bobMsgSize = bobData.messages.size(); + libjami::removeConversationMember(bob2Id, convId, aliceUri); + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return bobData.messages.size() == bobMsgSize + 2 /* vote + ban */; })); + + Manager::instance().sendRegister(bob2Id, false); + auto carlaMsgSize = carlaData.messages.size(); + Manager::instance().sendRegister(carlaId, true); + // Should sync! + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return carlaData.messages.size() > carlaMsgSize; })); } } // namespace test diff --git a/test/unitTest/conversation/conversationRequest.cpp b/test/unitTest/conversation/conversationRequest.cpp index 646ddfc7a32cd141893d2554b0767dc0581a4242..4bb753fd871fa817e9dc1b5d57a4915463e6265e 100644 --- a/test/unitTest/conversation/conversationRequest.cpp +++ b/test/unitTest/conversation/conversationRequest.cpp @@ -46,6 +46,22 @@ using namespace libjami::Account; namespace jami { namespace test { +struct UserData { + std::string conversationId; + bool removed {false}; + bool requestReceived {false}; + bool requestRemoved {false}; + bool registered {false}; + bool stopped {false}; + bool deviceAnnounced {false}; + bool contactAdded {false}; + bool contactRemoved {false}; + std::string profilePath; + std::string payloadTrustRequest; + std::vector<libjami::SwarmMessage> messages; + std::vector<libjami::SwarmMessage> messagesUpdated; +}; + class ConversationRequestTest : public CppUnit::TestFixture { public: @@ -62,7 +78,6 @@ public: void testDeclineConversationRequestRemoveTrustRequest(); void testMalformedTrustRequest(); void testAddContactDeleteAndReAdd(); - void testInviteFromMessageAfterRemoved(); void testRemoveContact(); void testRemoveContactMultiDevice(); void testRemoveSelfDoesntRemoveConversation(); @@ -79,9 +94,19 @@ public: void testRemoveContactRemoveTrustRequest(); void testAddConversationNoPresenceThenConnects(); std::string aliceId; + UserData aliceData; std::string bobId; + UserData bobData; std::string bob2Id; + UserData bob2Data; std::string carlaId; + UserData carlaData; + + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + + void connectSignals(); private: CPPUNIT_TEST_SUITE(ConversationRequestTest); @@ -93,7 +118,6 @@ private: CPPUNIT_TEST(testDeclineConversationRequestRemoveTrustRequest); CPPUNIT_TEST(testMalformedTrustRequest); CPPUNIT_TEST(testAddContactDeleteAndReAdd); - CPPUNIT_TEST(testInviteFromMessageAfterRemoved); CPPUNIT_TEST(testRemoveContact); CPPUNIT_TEST(testRemoveContactMultiDevice); CPPUNIT_TEST(testRemoveSelfDoesntRemoveConversation); @@ -127,10 +151,178 @@ ConversationRequestTest::setUp() aliceId = actors["alice"]; bobId = actors["bob"]; carlaId = actors["carla"]; + aliceData = {}; + bobData = {}; + bob2Data = {}; + carlaData = {}; Manager::instance().sendRegister(carlaId, false); wait_for_announcement_of({aliceId, bobId}); } +void +ConversationRequestTest::connectSignals() +{ + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string& accountId, const std::map<std::string, std::string>&) { + if (accountId == aliceId) { + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto details = aliceAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + aliceData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + aliceData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + aliceData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bobId) { + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto details = bobAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bobData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bobData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bobData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bob2Id) { + auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); + auto details = bob2Account->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bob2Data.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bob2Data.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bob2Data.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == carlaId) { + auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); + auto details = carlaAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + carlaData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + carlaData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + carlaData.deviceAnnounced = deviceAnnounced == "true"; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == aliceId) { + aliceData.conversationId = conversationId; + } else if (accountId == bobId) { + bobData.conversationId = conversationId; + } else if (accountId == bob2Id) { + bob2Data.conversationId = conversationId; + } else if (accountId == carlaId) { + carlaData.conversationId = conversationId; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( + [&](const std::string& account_id, + const std::string& /*from*/, + const std::string& /*conversationId*/, + const std::vector<uint8_t>& payload, + time_t /*received*/) { + auto payloadStr = std::string(payload.data(), payload.data() + payload.size()); + if (account_id == aliceId) + aliceData.payloadTrustRequest = payloadStr; + else if (account_id == bobId) + bobData.payloadTrustRequest = payloadStr; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + std::map<std::string, std::string> /*metadatas*/) { + if (accountId == aliceId) { + aliceData.requestReceived = true; + } else if (accountId == bobId) { + bobData.requestReceived = true; + } else if (accountId == bob2Id) { + bob2Data.requestReceived = true; + } else if (accountId == carlaId) { + carlaData.requestReceived = true; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( + [&](const std::string& accountId, const std::string&) { + if (accountId == bobId) { + bobData.requestRemoved = true; + } else if (accountId == bob2Id) { + bob2Data.requestRemoved = true; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messages.emplace_back(message); + } else if (accountId == bobId) { + bobData.messages.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messages.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageUpdated>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messagesUpdated.emplace_back(message); + } else if (accountId == bobId) { + bobData.messagesUpdated.emplace_back(message); + } else if (accountId == carlaId) { + carlaData.messagesUpdated.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( + [&](const std::string& accountId, const std::string&) { + if (accountId == aliceId) + aliceData.removed = true; + else if (accountId == bobId) + bobData.removed = true; + else if (accountId == bob2Id) + bob2Data.removed = true; + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactAdded>( + [&](const std::string& accountId, const std::string&, bool) { + if (accountId == bobId) { + bobData.contactAdded = true; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( + [&](const std::string& accountId, const std::string&, bool) { + if (accountId == bobId) { + bobData.contactRemoved = true; + } else if (accountId == bob2Id) { + bob2Data.contactRemoved = true; + } + cv.notify_one(); + })); + + libjami::registerSignalHandlers(confHandlers); +} + void ConversationRequestTest::tearDown() @@ -148,224 +340,109 @@ ConversationRequestTest::tearDown() void ConversationRequestTest::testAcceptTrustRemoveConvReq() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 1); - libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 0); } void ConversationRequestTest::acceptConvReqAlsoAddContact() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false, memberMessageGenerated = false; - int conversationReady = 0; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady += 1; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + bobData.requestReceived = false; auto convId2 = libjami::startConversation(aliceId); - requestReceived = false; libjami::addConversationMember(aliceId, convId2, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::acceptConversationRequest(bobId, convId2); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady == 2; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); + std::this_thread::sleep_for(5s); CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 0); } void ConversationRequestTest::testGetRequests() { - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + connectSignals(); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); auto requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 1); CPPUNIT_ASSERT(requests.front()["id"] == convId); - libjami::unregisterSignalHandlers(); } void ConversationRequestTest::testDeclineRequest() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - auto convId = libjami::startConversation(aliceId); libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); libjami::declineConversationRequest(bobId, convId); // Decline request auto requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 0); - libjami::unregisterSignalHandlers(); } void ConversationRequestTest::testAddContact() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !convId.empty(); })); - ConversationRepository repo(aliceAccount, convId); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !aliceData.conversationId.empty(); })); + ConversationRepository repo(aliceAccount, aliceData.conversationId); // Mode must be one to one CPPUNIT_ASSERT(repo.mode() == ConversationMode::ONE_TO_ONE); // Assert that repository exists - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() - / "conversations" / convId; + auto repoPath = fileutils::get_data_dir() / aliceId + / "conversations" / aliceData.conversationId; CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); - auto clonedPath = fileutils::get_data_dir() / bobAccount->getAccountID() - / "conversations" / convId; + cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); + auto clonedPath = fileutils::get_data_dir() / bobId + / "conversations" / aliceData.conversationId; CPPUNIT_ASSERT(std::filesystem::is_directory(clonedPath)); auto bobMember = clonedPath / "members" / (bobUri + ".crt"); CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobMember)); @@ -374,56 +451,22 @@ ConversationRequestTest::testAddContact() void ConversationRequestTest::testDeclineConversationRequestRemoveTrustRequest() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Decline request auto requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 1); auto trustRequests = libjami::getTrustRequests(bobId); CPPUNIT_ASSERT(trustRequests.size() == 1); - libjami::declineConversationRequest(bobId, convId); + libjami::declineConversationRequest(bobId, aliceData.conversationId); requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 0); trustRequests = libjami::getTrustRequests(bobId); @@ -433,51 +476,15 @@ ConversationRequestTest::testDeclineConversationRequestRemoveTrustRequest() void ConversationRequestTest::testMalformedTrustRequest() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - requestDeclined = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); // Decline request auto requests = libjami::getConversationRequests(bobId); @@ -485,7 +492,7 @@ ConversationRequestTest::testMalformedTrustRequest() auto trustRequests = libjami::getTrustRequests(bobId); CPPUNIT_ASSERT(trustRequests.size() == 1); // This will let the trust request (not libjami::declineConversationRequest) - bobAccount->convModule()->declineConversationRequest(convId); + bobAccount->convModule()->declineConversationRequest(aliceData.conversationId); requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 0); trustRequests = libjami::getTrustRequests(bobId); @@ -497,6 +504,7 @@ ConversationRequestTest::testMalformedTrustRequest() auto start = std::chrono::steady_clock::now(); + auto requestDeclined = false; do { trustRequests = libjami::getTrustRequests(bobId); requestDeclined = trustRequests.size() == 0; @@ -510,227 +518,83 @@ ConversationRequestTest::testMalformedTrustRequest() void ConversationRequestTest::testAddContactDeleteAndReAdd() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // removeContact aliceAccount->removeContact(bobUri, false); std::this_thread::sleep_for(5s); // wait a bit that connections are closed // re-add - CPPUNIT_ASSERT(convId != ""); - auto oldConvId = convId; - convId = ""; + CPPUNIT_ASSERT(aliceData.conversationId != ""); + auto oldConvId = aliceData.conversationId; aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); // Should retrieve previous conversation - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return oldConvId == convId; })); -} - -void -ConversationRequestTest::testInviteFromMessageAfterRemoved() -{ - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string&, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - requestReceived = false; - aliceAccount->addContact(bobUri); - aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); - - // removeContact - bobAccount->removeContact(aliceUri, false); - std::this_thread::sleep_for(10s); // wait a bit that connections are closed - - // bob sends a message, this should generate a new request for Alice - requestReceived = false; - libjami::sendMessage(aliceId, convId, "hi"s, ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - conversationReady = false; - CPPUNIT_ASSERT(bobAccount->getContacts().size() == 0); - libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - CPPUNIT_ASSERT(bobAccount->getContacts().size() == 1); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return oldConvId == aliceData.conversationId; })); } void ConversationRequestTest::testRemoveContact() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - bool conversationRemovedAlice = false, conversationRemovedBob = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == aliceId) - conversationRemovedAlice = true; - else if (accountId == bobId) - conversationRemovedBob = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); // Check created files - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); - conversationRemovedBob = false; bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemovedBob; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); auto details = bobAccount->getContactDetails(aliceUri); - CPPUNIT_ASSERT(details.size() == 0); + CPPUNIT_ASSERT(details.find("removed") != details.end() && details["removed"] != "0"); - conversationRemovedAlice = false; aliceAccount->removeContact(bobUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]() { return conversationRemovedAlice; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&]() { return aliceData.removed; })); std::this_thread::sleep_for( 10s); // There is no signal, but daemon should then erase the repository - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() - / "conversations" / convId; + auto repoPath = fileutils::get_data_dir() / aliceId + / "conversations" / aliceData.conversationId; CPPUNIT_ASSERT(!std::filesystem::is_directory(repoPath)); - repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() - / "conversations" / convId; + repoPath = fileutils::get_data_dir() / bobId + / "conversations" / bobData.conversationId; CPPUNIT_ASSERT(!std::filesystem::is_directory(repoPath)); } void ConversationRequestTest::testRemoveContactMultiDevice() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; // Add second device for Bob std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; @@ -749,50 +613,102 @@ ConversationRequestTest::testRemoveContactMultiDevice() bob2Id = Manager::instance().addAccount(details); - wait_for_announcement_of(bob2Id); - auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); - - bool requestB1Removed = false, requestB2Removed = false, requestB1Received = false, requestB2Received = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestB1Received = true; - else if (account_id == bob2Id) - requestB2Received = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) { - requestB1Removed = true; - } else if (accountId == bob2Id) { - requestB2Removed = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { + return bob2Data.deviceAnnounced; + })); // First, Alice adds Bob aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return requestB1Received && requestB2Received; + return bobData.requestReceived && bob2Data.requestReceived; })); // Bob1 decline via removeContact, both device should remove the request bobAccount->removeContact(aliceUri, false); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return requestB1Removed && requestB2Removed; })); + cv.wait_for(lk, 30s, [&]() { return bobData.requestRemoved && bob2Data.requestRemoved; })); } void ConversationRequestTest::testRemoveSelfDoesntRemoveConversation() +{ + connectSignals(); + + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getUsername(); + auto aliceUri = aliceAccount->getUsername(); + + aliceAccount->addContact(bobUri); + aliceAccount->sendTrustRequest(bobUri, {}); + // Check created files + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); + + aliceAccount->removeContact(aliceUri, false); + CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return aliceData.removed; })); + auto repoPath = fileutils::get_data_dir() / aliceId + / "conversations" / aliceData.conversationId; + CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); +} + +void +ConversationRequestTest::testRemoveConversationUpdateContactDetails() +{ + connectSignals(); + + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getUsername(); + auto aliceUri = aliceAccount->getUsername(); + + aliceAccount->addContact(bobUri); + aliceAccount->sendTrustRequest(bobUri, {}); + // Check created files + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); + CPPUNIT_ASSERT( + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); + + libjami::removeConversation(bobId, bobData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); + + auto details = bobAccount->getContactDetails(aliceUri); + CPPUNIT_ASSERT(details[libjami::Account::TrustRequest::CONVERSATIONID] == ""); +} + +void +ConversationRequestTest::testBanContact() +{ + connectSignals(); + + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto bobUri = bobAccount->getUsername(); + auto aliceUri = aliceAccount->getUsername(); + + aliceAccount->addContact(bobUri); + aliceAccount->sendTrustRequest(bobUri, {}); + // Check created files + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); + CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); + + bobAccount->removeContact(aliceUri, true); + CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 2 == aliceData.messages.size(); })); + auto repoPath = fileutils::get_data_dir() / bobId + / "conversations" / bobData.conversationId; + CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); +} + + +void +ConversationRequestTest::testBanContactRestartAccount() { auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); @@ -802,205 +718,7 @@ ConversationRequestTest::testRemoveSelfDoesntRemoveConversation() std::unique_lock<std::mutex> lk {mtx}; std::condition_variable cv; std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - conversationRemoved = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRemoved = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - aliceAccount->addContact(bobUri); - aliceAccount->sendTrustRequest(bobUri, {}); - // Check created files - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); - memberMessageGenerated = false; - CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); - - conversationRemoved = false; - aliceAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(!cv.wait_for(lk, 10s, [&]() { return conversationRemoved; })); - auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID() - / "conversations" / convId; - CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); -} - -void -ConversationRequestTest::testRemoveConversationUpdateContactDetails() -{ - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false, - conversationRemoved = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - conversationRemoved = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - aliceAccount->addContact(bobUri); - aliceAccount->sendTrustRequest(bobUri, {}); - // Check created files - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !convId.empty() && requestReceived; })); - memberMessageGenerated = false; - CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); - - conversationRemoved = false; - libjami::removeConversation(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); - - auto details = bobAccount->getContactDetails(aliceUri); - CPPUNIT_ASSERT(details[libjami::Account::TrustRequest::CONVERSATIONID] == ""); -} - -void -ConversationRequestTest::testBanContact() -{ - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - aliceAccount->addContact(bobUri); - aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return !convId.empty(); })); - // Check created files - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - memberMessageGenerated = false; - CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - - memberMessageGenerated = false; - bobAccount->removeContact(aliceUri, true); - CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return memberMessageGenerated; })); - auto repoPath = fileutils::get_data_dir() / bobAccount->getAccountID() - / "conversations" / convId; - CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath)); -} - - -void -ConversationRequestTest::testBanContactRestartAccount() -{ - auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; + bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; std::string convId = ""; confHandlers.insert( libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( @@ -1088,50 +806,19 @@ ConversationRequestTest::testBanContactRestartAccount() void ConversationRequestTest::testBanContactRemoveTrustRequest() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, requestDeclined = true; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) - requestDeclined = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); // Check created files - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); bobAccount->removeContact(aliceUri, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return requestDeclined; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 5s, [&]() { return bobData.requestRemoved; })); auto requests = libjami::getConversationRequests(bobId); CPPUNIT_ASSERT(requests.size() == 0); } @@ -1139,194 +826,71 @@ ConversationRequestTest::testBanContactRemoveTrustRequest() void ConversationRequestTest::testAddOfflineContactThenConnect() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto carlaAccount = Manager::instance().getAccount<JamiAccount>(carlaId); auto carlaUri = carlaAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); aliceAccount->trackBuddyPresence(carlaUri, true); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == carlaId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == carlaId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(carlaUri); aliceAccount->sendTrustRequest(carlaUri, {}); cv.wait_for(lk, 5s); // Wait 5 secs for the put to happen - CPPUNIT_ASSERT(!convId.empty()); Manager::instance().sendRegister(carlaId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&]() { return requestReceived; })); - memberMessageGenerated = false; + CPPUNIT_ASSERT(cv.wait_for(lk, std::chrono::seconds(60), [&]() { return carlaData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(carlaAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && memberMessageGenerated; })); + cv.wait_for(lk, 30s, [&]() { return aliceData.messages.size() == aliceMsgSize + 1; })); } void ConversationRequestTest::testDeclineTrustRequestDoNotGenerateAnother() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); aliceAccount->trackBuddyPresence(bobUri, true); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, memberMessageGenerated = false; - std::string convId = ""; - auto bobConnected = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string&, const std::map<std::string, std::string>&) { - auto details = bobAccount->getVolatileAccountDetails(); - auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; - if (daemonStatus == "REGISTERED") { - bobConnected = true; - cv.notify_one(); - } else if (daemonStatus == "UNREGISTERED") { - bobConnected = false; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); CPPUNIT_ASSERT(bobAccount->discardTrustRequest(aliceUri)); cv.wait_for(lk, 10s); // Wait a bit - bobConnected = true; Manager::instance().sendRegister(bobId, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobConnected; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.stopped; })); // Trigger on peer online - requestReceived = false; + bobData.deviceAnnounced = false; bobData.requestReceived = false; Manager::instance().sendRegister(bobId, true); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobConnected; })); - CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.deviceAnnounced; })); + CPPUNIT_ASSERT(!cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); } void ConversationRequestTest::testRemoveContactRemoveSyncing() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, contactAdded = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& convId, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId && !convId.empty()) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactAdded>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) { - contactAdded = true; - } - cv.notify_one(); - })); - bool contactRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactRemoved>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) { - contactRemoved = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactAdded; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.contactAdded; })); CPPUNIT_ASSERT(libjami::getConversations(bobId).size() == 1); bobAccount->removeContact(aliceUri, false); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactRemoved; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.contactRemoved; })); CPPUNIT_ASSERT(libjami::getConversations(bobId).size() == 0); } @@ -1334,65 +898,25 @@ ConversationRequestTest::testRemoveContactRemoveSyncing() void ConversationRequestTest::testRemoveConversationRemoveSyncing() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, contactAdded = false, requestReceived = false, - conversationRemoved = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& convId, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId && !convId.empty()) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) { - conversationRemoved = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactAdded>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) { - contactAdded = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactAdded; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.contactAdded; })); // At this point the conversation should be there and syncing. CPPUNIT_ASSERT(libjami::getConversations(bobId).size() == 1); - libjami::removeConversation(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationRemoved; })); + libjami::removeConversation(bobId, aliceData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.removed; })); CPPUNIT_ASSERT(libjami::getConversations(bobId).size() == 0); } @@ -1400,91 +924,47 @@ ConversationRequestTest::testRemoveConversationRemoveSyncing() void ConversationRequestTest::testCacheRequestFromClient() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + aliceAccount->addContact(bobUri); std::vector<uint8_t> payload = {0x64, 0x64, 0x64}; aliceAccount->sendTrustRequest(bobUri, payload); // Random payload, just care with the file - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - auto cachedPath = fileutils::get_cache_dir() / aliceAccount->getAccountID() + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto cachedPath = fileutils::get_cache_dir() / aliceId / "requests" / bobUri; CPPUNIT_ASSERT(std::filesystem::is_regular_file(cachedPath)); CPPUNIT_ASSERT(fileutils::loadFile(cachedPath) == payload); CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 1); - libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + libjami::acceptConversationRequest(bobId, aliceData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return !bobData.conversationId.empty(); })); CPPUNIT_ASSERT(!std::filesystem::is_regular_file(cachedPath)); } void ConversationRequestTest::testNeedsSyncingWithForCloning() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); auto aliceDevice = std::string(aliceAccount->currentDeviceId()); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool contactAdded = false, requestReceived = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& convId, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId && !convId.empty()) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ContactAdded>( - [&](const std::string& accountId, const std::string& uri, bool) { - if (accountId == bobId && uri == aliceUri) { - contactAdded = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); + CPPUNIT_ASSERT(!bobAccount->convModule()->needsSyncingWith(aliceUri, aliceDevice)); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); Manager::instance().sendRegister(aliceId, false); // This avoid to sync immediately CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return contactAdded; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.contactAdded; })); // At this point the conversation should be there and syncing. CPPUNIT_ASSERT(libjami::getConversations(bobId).size() == 1); @@ -1494,13 +974,12 @@ ConversationRequestTest::testNeedsSyncingWithForCloning() void ConversationRequestTest::testRemoveContactRemoveTrustRequest() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; // Add second device for Bob std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; @@ -1519,75 +998,29 @@ ConversationRequestTest::testRemoveContactRemoveTrustRequest() bob2Id = Manager::instance().addAccount(details); - wait_for_announcement_of(bob2Id); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { + return bob2Data.deviceAnnounced; + })); auto bob2Account = Manager::instance().getAccount<JamiAccount>(bob2Id); - bool conversationB1Ready = false, conversationB2Ready = false, conversationB1Removed = false, - conversationB2Removed = false, requestB1Received = false, requestB2Received = false, - memberMessageGenerated = false; - std::string convId = ""; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestB1Received = true; - else if (account_id == bob2Id) - requestB2Received = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationB1Ready = true; - } else if (accountId == bob2Id) { - conversationB2Ready = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string&) { - if (accountId == bobId) { - conversationB1Removed = true; - } else if (accountId == bob2Id) { - conversationB2Removed = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> message) { - if (accountId == aliceId && conversationId == convId && message["type"] == "member") { - memberMessageGenerated = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - // First, Alice adds Bob aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return !convId.empty() && requestB1Received && requestB2Received; + return bobData.requestReceived && bob2Data.requestReceived; })); // Bob1 accepts, both device should get it + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationB1Ready && conversationB2Ready && memberMessageGenerated; + return !bobData.conversationId.empty() && !bob2Data.conversationId.empty() && aliceMsgSize + 1 == aliceData.messages.size(); })); // Bob2 remove Alice ; Bob1 should not have any trust requests bob2Account->removeContact(aliceUri, false); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationB1Removed && conversationB2Removed; })); + cv.wait_for(lk, 30s, [&]() { return bobData.contactRemoved && bob2Data.contactRemoved; })); std::this_thread::sleep_for(10s); // Wait a bit to ensure that everything is update (via synced) CPPUNIT_ASSERT(bobAccount->getTrustRequests().size() == 0); CPPUNIT_ASSERT(bob2Account->getTrustRequests().size() == 0); diff --git a/test/unitTest/syncHistory/syncHistory.cpp b/test/unitTest/syncHistory/syncHistory.cpp index 7c2d52469c50140936c0bd4d3ff56766aac11602..9d58e838882157a1d993e7089625bd2ff6abe1d1 100644 --- a/test/unitTest/syncHistory/syncHistory.cpp +++ b/test/unitTest/syncHistory/syncHistory.cpp @@ -41,6 +41,24 @@ using namespace std::literals::chrono_literals; namespace jami { namespace test { +struct UserData { + std::string conversationId; + bool removed {false}; + bool requestReceived {false}; + bool requestRemoved {false}; + bool errorDetected {false}; + bool registered {false}; + bool stopped {false}; + bool deviceAnnounced {false}; + bool sending {false}; + bool sent {false}; + std::string profilePath; + std::string payloadTrustRequest; + std::vector<libjami::SwarmMessage> messages; + std::vector<libjami::SwarmMessage> messagesLoaded; + std::vector<libjami::SwarmMessage> messagesUpdated; +}; + class SyncHistoryTest : public CppUnit::TestFixture { public: @@ -57,8 +75,16 @@ public: void tearDown(); std::string aliceId; + UserData aliceData; std::string bobId; + UserData bobData; std::string alice2Id; + UserData alice2Data; + + std::mutex mtx; + std::unique_lock<std::mutex> lk {mtx}; + std::condition_variable cv; + void connectSignals(); private: void testCreateConversationThenSync(); @@ -103,6 +129,9 @@ SyncHistoryTest::setUp() aliceId = actors["alice"]; bobId = actors["bob"]; alice2Id = ""; + aliceData = {}; + bobData = {}; + alice2Data = {}; } void @@ -117,9 +146,201 @@ SyncHistoryTest::tearDown() } } +void +SyncHistoryTest::connectSignals() +{ + std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( + [&](const std::string& accountId, const std::map<std::string, std::string>&) { + if (accountId == aliceId) { + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto details = aliceAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + aliceData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + aliceData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + aliceData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == bobId) { + auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); + auto details = bobAccount->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + bobData.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + bobData.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + bobData.deviceAnnounced = deviceAnnounced == "true"; + } else if (accountId == alice2Id) { + auto alice2Account = Manager::instance().getAccount<JamiAccount>(alice2Id); + auto details = alice2Account->getVolatileAccountDetails(); + auto daemonStatus = details[libjami::Account::ConfProperties::Registration::STATUS]; + if (daemonStatus == "REGISTERED") { + alice2Data.registered = true; + } else if (daemonStatus == "UNREGISTERED") { + alice2Data.stopped = true; + } + auto deviceAnnounced = details[libjami::Account::VolatileProperties::DEVICE_ANNOUNCED]; + alice2Data.deviceAnnounced = deviceAnnounced == "true"; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( + [&](const std::string& accountId, const std::string& conversationId) { + if (accountId == aliceId) { + aliceData.conversationId = conversationId; + } else if (accountId == bobId) { + bobData.conversationId = conversationId; + } else if (accountId == alice2Id) { + alice2Data.conversationId = conversationId; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ProfileReceived>( + [&](const std::string& accountId, const std::string& peerId, const std::string& path) { + if (accountId == bobId) + bobData.profilePath = path; + else if (accountId == aliceId) + aliceData.profilePath = path; + else if (accountId == alice2Id) + alice2Data.profilePath = path; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( + [&](const std::string& accountId, + const std::string& /*conversationId*/, + const std::string& /*peer*/, + const std::string& /*msgId*/, + int status) { + if (accountId == aliceId) { + if (status == 2) + aliceData.sending = true; + if (status == 3) + aliceData.sent = true; + } else if (accountId == alice2Id) { + if (status == 2) + alice2Data.sending = true; + if (status == 3) + alice2Data.sent = true; + } else if (accountId == bobId) { + if (status == 2) + bobData.sending = true; + if (status == 3) + bobData.sent = true; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( + [&](const std::string& account_id, + const std::string& /*from*/, + const std::string& /*conversationId*/, + const std::vector<uint8_t>& payload, + time_t /*received*/) { + auto payloadStr = std::string(payload.data(), payload.data() + payload.size()); + if (account_id == aliceId) + aliceData.payloadTrustRequest = payloadStr; + else if (account_id == bobId) + bobData.payloadTrustRequest = payloadStr; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + std::map<std::string, std::string> /*metadatas*/) { + if (accountId == aliceId) { + aliceData.requestReceived = true; + } else if (accountId == bobId) { + bobData.requestReceived = true; + } else if (accountId == alice2Id) { + alice2Data.requestReceived = true; + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( + [&](const std::string& accountId, const std::string&) { + if (accountId == bobId) { + bobData.requestRemoved = true; + } else if (accountId == aliceId) { + aliceData.requestRemoved = true; + } else if (accountId == alice2Id) { + alice2Data.requestRemoved = true; + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageReceived>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messages.emplace_back(message); + } else if (accountId == bobId) { + bobData.messages.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmLoaded>( + [&](uint32_t, const std::string& accountId, + const std::string& /* conversationId */, + std::vector<libjami::SwarmMessage> messages) { + if (accountId == aliceId) { + aliceData.messagesLoaded.insert(aliceData.messagesLoaded.end(), messages.begin(), messages.end()); + } else if (accountId == alice2Id) { + alice2Data.messagesLoaded.insert(alice2Data.messagesLoaded.end(), messages.begin(), messages.end()); + } else if (accountId == bobId) { + bobData.messagesLoaded.insert(bobData.messagesLoaded.end(), messages.begin(), messages.end()); + } + cv.notify_one(); + })); + confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::SwarmMessageUpdated>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + libjami::SwarmMessage message) { + if (accountId == aliceId) { + aliceData.messagesUpdated.emplace_back(message); + } else if (accountId == bobId) { + bobData.messagesUpdated.emplace_back(message); + } + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::OnConversationError>( + [&](const std::string& accountId, + const std::string& /* conversationId */, + int /*code*/, + const std::string& /* what */) { + if (accountId == aliceId) + aliceData.errorDetected = true; + else if (accountId == bobId) + bobData.errorDetected = true; + cv.notify_one(); + })); + confHandlers.insert( + libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( + [&](const std::string& accountId, const std::string&) { + if (accountId == aliceId) + aliceData.removed = true; + else if (accountId == bobId) + bobData.removed = true; + else if (accountId == alice2Id) + alice2Data.removed = true; + cv.notify_one(); + })); + libjami::registerSignalHandlers(confHandlers); +} + void SyncHistoryTest::testCreateConversationThenSync() { + connectSignals(); + auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); // Start conversation auto convId = libjami::startConversation(aliceId); @@ -136,37 +357,14 @@ SyncHistoryTest::testCreateConversationThenSync() details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto conversationReady = false, alice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Ready && conversationReady; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); } void SyncHistoryTest::testCreateConversationWithOnlineDevice() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); // Now create alice2 @@ -180,77 +378,26 @@ SyncHistoryTest::testCreateConversationWithOnlineDevice() details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - - // Start conversation now auto convId = libjami::startConversation(aliceId); - auto conversationReady = false, alice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return alice2Ready && conversationReady; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); } void SyncHistoryTest::testCreateConversationWithMessagesThenAddDevice() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto convId = libjami::startConversation(aliceId); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto conversationReady = false; - auto messageReceived = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - messageReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - confHandlers.clear(); - // Start conversation - messageReceived = false; + auto aliceMsgSize = aliceData.messages.size(); libjami::sendMessage(aliceId, convId, std::string("Message 1"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 1 == aliceData.messages.size(); })); libjami::sendMessage(aliceId, convId, std::string("Message 2"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 2 == aliceData.messages.size(); })); libjami::sendMessage(aliceId, convId, std::string("Message 3"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 3 == aliceData.messages.size(); })); // Now create alice2 auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; @@ -264,31 +411,15 @@ SyncHistoryTest::testCreateConversationWithMessagesThenAddDevice() details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; alice2Id = Manager::instance().addAccount(details); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); - // Check if conversation is ready - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return conversationReady; })); - std::vector<std::map<std::string, std::string>> messages; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationLoaded>( - [&](uint32_t, - const std::string& accountId, - const std::string& conversationId, - std::vector<std::map<std::string, std::string>> msg) { - if (accountId == alice2Id && conversationId == convId) { - messages = msg; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - libjami::loadConversationMessages(alice2Id, convId, "", 0); - cv.wait_for(lk, 30s); - libjami::unregisterSignalHandlers(); - confHandlers.clear(); + libjami::loadConversation(alice2Id, convId, "", 0); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.messagesLoaded.size() == 4; })); // Check messages - CPPUNIT_ASSERT(messages.size() == 4 /* 3 + initial */); - CPPUNIT_ASSERT(messages[0]["body"] == "Message 3"); - CPPUNIT_ASSERT(messages[1]["body"] == "Message 2"); - CPPUNIT_ASSERT(messages[2]["body"] == "Message 1"); + CPPUNIT_ASSERT(alice2Data.messagesLoaded[0].body["body"] == "Message 3"); + CPPUNIT_ASSERT(alice2Data.messagesLoaded[1].body["body"] == "Message 2"); + CPPUNIT_ASSERT(alice2Data.messagesLoaded[2].body["body"] == "Message 1"); } void @@ -346,56 +477,25 @@ SyncHistoryTest::testCreateMultipleConversationThenAddDevice() // Check if conversation is ready CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return conversationReady == 4; })); - libjami::unregisterSignalHandlers(); } void SyncHistoryTest::testReceivesInviteThenAddDevice() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); // Export alice auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; aliceAccount->exportArchive(aliceArchive); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto uri = aliceAccount->getUsername(); // Start conversation for Alice auto convId = libjami::startConversation(bobId); - // Check that alice receives the request - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false, memberEvent = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == aliceId && conversationId == convId) { - requestReceived = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationMemberEvent>( - [&](const std::string& /*accountId*/, - const std::string& /*conversationId*/, - const std::string& /*memberUri*/, - int /*event*/) { - memberEvent = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - - memberEvent = false; libjami::addConversationMember(bobId, convId, uri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return memberEvent && requestReceived; })); - libjami::unregisterSignalHandlers(); - confHandlers.clear(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceData.requestReceived; })); // Now create alice2 std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); @@ -408,26 +508,13 @@ SyncHistoryTest::testReceivesInviteThenAddDevice() details[ConfProperties::ARCHIVE_PATH] = aliceArchive; alice2Id = Manager::instance().addAccount(details); - requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == alice2Id && conversationId == convId) { - requestReceived = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return requestReceived; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.requestReceived; })); } void SyncHistoryTest::testRemoveConversationOnAllDevices() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); // Now create alice2 @@ -441,53 +528,18 @@ SyncHistoryTest::testRemoveConversationOnAllDevices() details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - - // Start conversation now auto convId = libjami::startConversation(aliceId); - bool alice2Ready = false; - auto conversationReady = false, conversationRemoved = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationRemoved>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == alice2Id && conversationId == convId) { - conversationRemoved = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return alice2Ready && conversationReady; })); - libjami::removeConversation(aliceId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return conversationRemoved; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return !alice2Data.conversationId.empty(); })); + libjami::removeConversation(aliceId, aliceData.conversationId); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.removed; })); } void SyncHistoryTest::testSyncCreateAccountExportDeleteReimportOldBackup() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); @@ -499,65 +551,11 @@ SyncHistoryTest::testSyncCreateAccountExportDeleteReimportOldBackup() // Start conversation auto convId = libjami::startConversation(aliceId); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool alice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); - + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); - - // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return messageAliceReceived == 1; }); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size() && !bobData.conversationId.empty(); })); // disable account (same as removed) Manager::instance().sendRegister(aliceId, false); @@ -571,27 +569,25 @@ SyncHistoryTest::testSyncCreateAccountExportDeleteReimportOldBackup() details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - requestReceived = false; - conversationReady = false; alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Ready; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.deviceAnnounced; })); // This will trigger a conversation request. Cause alice2 can't know first conversation libjami::sendMessage(bobId, convId, std::string("hi"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.requestReceived; })); libjami::acceptConversationRequest(alice2Id, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); - messageBobReceived = 0; + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(alice2Id, convId, std::string("hi"), ""); - cv.wait_for(lk, 30s, [&]() { return messageBobReceived == 1; }); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); })); } void SyncHistoryTest::testSyncCreateAccountExportDeleteReimportWithConvId() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); @@ -600,76 +596,16 @@ SyncHistoryTest::testSyncCreateAccountExportDeleteReimportWithConvId() // Start conversation auto convId = libjami::startConversation(aliceId); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool alice2Ready = false; - bool memberAddGenerated = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationMemberEvent>( - [&](const std::string& accountId, - const std::string& conversationId, - const std::string& uri, - int event) { - if (accountId == aliceId && conversationId == convId && uri == bobUri - && event == 0) { - memberAddGenerated = true; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& /*accountId*/, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (conversationId != convId) - return; - if (accountId == bobId || accountId == alice2Id) - conversationReady = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(aliceId, convId, bobUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); libjami::acceptConversationRequest(bobId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // We need to track presence to know when to sync bobAccount->trackBuddyPresence(aliceUri, true); - // Wait that alice sees Bob - cv.wait_for(lk, 30s, [&]() { return memberAddGenerated; }); - // Backup alice after startConversation with member auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; aliceAccount->exportArchive(aliceArchive); @@ -686,83 +622,27 @@ SyncHistoryTest::testSyncCreateAccountExportDeleteReimportWithConvId() details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - requestReceived = false; - conversationReady = false; alice2Id = Manager::instance().addAccount(details); // Should retrieve conversation, no need for action as the convInfos is in the archive - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Ready && conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); - messageBobReceived = 0; + auto bobMsgSize = bobData.messages.size(); libjami::sendMessage(alice2Id, convId, std::string("hi"), ""); - cv.wait_for(lk, 30s, [&]() { return messageBobReceived == 1; }); - libjami::unregisterSignalHandlers(); + cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); }); } void SyncHistoryTest::testSyncCreateAccountExportDeleteReimportWithConvReq() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); - auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto bobUri = bobAccount->getUsername(); auto aliceUri = aliceAccount->getUsername(); // Start conversation auto convId = libjami::startConversation(bobId); - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageBobReceived = 0, messageAliceReceived = 0; - bool requestReceived = false; - bool conversationReady = false; - bool alice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { - messageBobReceived += 1; - } else { - messageAliceReceived += 1; - } - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == aliceId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId) { - conversationReady = true; - cv.notify_one(); - } - - if (accountId == alice2Id && conversationId == convId) { - conversationReady = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(bobId, convId, aliceUri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceData.requestReceived; })); // Backup alice after startConversation with member auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; @@ -780,54 +660,24 @@ SyncHistoryTest::testSyncCreateAccountExportDeleteReimportWithConvReq() details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - conversationReady = false; alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Ready; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Data.deviceAnnounced; })); // Should get the same request as before. - messageBobReceived = 0; + auto bobMsgSize = bobData.messages.size(); libjami::acceptConversationRequest(alice2Id, convId); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && messageBobReceived == 1; })); - libjami::unregisterSignalHandlers(); + cv.wait_for(lk, 30s, [&]() { return bobMsgSize + 1 == bobData.messages.size(); })); } void SyncHistoryTest::testSyncOneToOne() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - // Start conversation - std::string convId; - - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto conversationReady = false, alice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) - convId = conversationId; - else if (accountId == alice2Id && conversationId == convId) - conversationReady = true; - cv.notify_one(); - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::VolatileDetailsChanged>( - [&](const std::string& accountId, const std::map<std::string, std::string>& details) { - if (alice2Id != accountId) { - return; - } - alice2Ready = details.at(libjami::Account::VolatileProperties::DEVICE_ANNOUNCED) - == "true"; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobAccount->getUsername()); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !convId.empty(); })); - // Now create alice2 auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; aliceAccount->exportArchive(aliceArchive); @@ -841,47 +691,28 @@ SyncHistoryTest::testSyncOneToOne() details[ConfProperties::ARCHIVE_PATH] = aliceArchive; alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return alice2Ready && conversationReady; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return !alice2Data.conversationId.empty(); })); } void SyncHistoryTest::testConversationRequestRemoved() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); + auto uri = aliceAccount->getUsername(); // Export alice auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; aliceAccount->exportArchive(aliceArchive); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); - auto uri = aliceAccount->getUsername(); // Start conversation for Alice auto convId = libjami::startConversation(bobId); // Check that alice receives the request - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == aliceId && conversationId == convId) { - requestReceived = true; - cv.notify_one(); - } - })); - libjami::registerSignalHandlers(confHandlers); - libjami::addConversationMember(bobId, convId, uri); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return requestReceived; })); - libjami::unregisterSignalHandlers(); - confHandlers.clear(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceData.requestReceived; })); // Now create alice2 std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); @@ -894,43 +725,17 @@ SyncHistoryTest::testConversationRequestRemoved() details[ConfProperties::ARCHIVE_PATH] = aliceArchive; alice2Id = Manager::instance().addAccount(details); - requestReceived = false; - bool requestDeclined = false, requestDeclined2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& conversationId, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == alice2Id && conversationId == convId) { - requestReceived = true; - cv.notify_one(); - } - })); - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestDeclined>( - [&](const std::string& accountId, const std::string& conversationId) { - if (conversationId != convId) - return; - if (accountId == aliceId) - requestDeclined = true; - if (accountId == alice2Id) - requestDeclined2 = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceData.requestReceived; })); // Now decline trust request, this should trigger ConversationRequestDeclined both sides for Alice libjami::declineConversationRequest(aliceId, convId); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return requestDeclined && requestDeclined2; })); - - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&] { return aliceData.requestRemoved && alice2Data.requestRemoved; })); } void SyncHistoryTest::testProfileReceivedMultiDevice() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto aliceUri = aliceAccount->getUsername(); @@ -946,9 +751,9 @@ VERSION:2.1\n\ FN:TITLE\n\ DESCRIPTION:DESC\n\ END:VCARD"; - auto alicePath = fileutils::get_data_dir() / aliceAccount->getAccountID() + auto alicePath = fileutils::get_data_dir() / aliceId / "profile.vcf"; - auto bobPath = fileutils::get_data_dir() / bobAccount->getAccountID() + auto bobPath = fileutils::get_data_dir() / bobId / "profile.vcf"; // Save VCard auto p = std::filesystem::path(alicePath); @@ -966,59 +771,15 @@ END:VCARD"; bobFile.close(); } - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - bool conversationReady = false, requestReceived = false, bobProfileReceived = false, - aliceProfileReceived = false, bobProfileReceivedAlice2 = false; - std::string convId = ""; - std::string bobDest = aliceAccount->dataTransfer()->profilePath(bobUri); - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::IncomingTrustRequest>( - [&](const std::string& account_id, - const std::string& /*from*/, - const std::string& /*conversationId*/, - const std::vector<uint8_t>& /*payload*/, - time_t /*received*/) { - if (account_id == bobId) - requestReceived = true; - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == aliceId) { - convId = conversationId; - } else if (accountId == bobId) { - conversationReady = true; - } - cv.notify_one(); - })); - confHandlers.insert(libjami::exportable_callback<libjami::ConfigurationSignal::ProfileReceived>( - [&](const std::string& accountId, const std::string& peerId, const std::string& path) { - if (accountId == aliceId && peerId == bobUri) { - bobProfileReceived = true; - auto p = std::filesystem::path(bobDest); - dhtnet::fileutils::recursive_mkdir(p.parent_path()); - std::rename(path.c_str(), bobDest.c_str()); - } else if (accountId == bobId && peerId == aliceUri) { - aliceProfileReceived = true; - } else if (accountId == alice2Id && peerId == bobUri) { - bobProfileReceivedAlice2 = true; - } else if (accountId == alice2Id && peerId == aliceUri) { - aliceProfileReceived = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { - return conversationReady && bobProfileReceived && aliceProfileReceived; + return !bobData.profilePath.empty() && !aliceData.profilePath.empty() && !bobData.conversationId.empty(); })); - CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobDest)); + CPPUNIT_ASSERT(std::filesystem::is_regular_file(bobData.profilePath)); // Now create alice2 std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); @@ -1029,96 +790,44 @@ END:VCARD"; details[ConfProperties::ARCHIVE_PASSWORD] = ""; details[ConfProperties::ARCHIVE_PIN] = ""; details[ConfProperties::ARCHIVE_PATH] = aliceArchive; - bobProfileReceived = false, aliceProfileReceived = false; + bobData.profilePath = {}; + alice2Data.profilePath = {}; alice2Id = Manager::instance().addAccount(details); - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { return aliceProfileReceived && bobProfileReceivedAlice2; })); - libjami::unregisterSignalHandlers(); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&] { + return alice2Data.deviceAnnounced && !bobData.profilePath.empty() && !alice2Data.profilePath.empty(); })); } void SyncHistoryTest::testLastInteractionAfterClone() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto aliceUri = aliceAccount->getUsername(); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::string convId; - - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageReceived = false; - std::string msgId = ""; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& accountId , - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - if (accountId == bobId) { - messageReceived = true; - msgId = message["id"]; - cv.notify_one(); - } - })); - auto conversationReady = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId || accountId == alice2Id) { - convId = conversationId; - conversationReady = true; - } - cv.notify_one(); - })); - auto requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& /*conversationId*/, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - auto messageDisplayed = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - const std::string& /* username */, - const std::string& /* msgId */, - int status) { - if (bobId == accountId && status == 3) - messageDisplayed = true; - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - confHandlers.clear(); aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived; })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Start conversation - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 1"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 2"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 3"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - - messageDisplayed = false; - libjami::setMessageDisplayed(aliceId, "swarm:" + convId, msgId, 3); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageDisplayed; })); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 1"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 2 == aliceData.messages.size(); })); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 2"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 3 == aliceData.messages.size(); })); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 3"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 4 == aliceData.messages.size(); })); + + auto msgId = aliceData.messages.rbegin()->id; + libjami::setMessageDisplayed(aliceId, "swarm:" + aliceData.conversationId, msgId, 3); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceData.sent; })); // Now create alice2 - conversationReady = false; auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; aliceAccount->exportArchive(aliceArchive); std::map<std::string, std::string> details = libjami::getAccountTemplate("RING"); @@ -1132,9 +841,9 @@ SyncHistoryTest::testLastInteractionAfterClone() alice2Id = Manager::instance().addAccount(details); // Check if conversation is ready - CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return conversationReady; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 60s, [&]() { return !alice2Data.conversationId.empty(); })); // Check that last displayed is synched - auto membersInfos = libjami::getConversationMembers(alice2Id, convId); + auto membersInfos = libjami::getConversationMembers(alice2Id, alice2Data.conversationId); CPPUNIT_ASSERT(std::find_if(membersInfos.begin(), membersInfos.end(), [&](auto infos) { @@ -1147,65 +856,11 @@ SyncHistoryTest::testLastInteractionAfterClone() void SyncHistoryTest::testLastInteractionAfterSomeMessages() { + connectSignals(); auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId); auto aliceUri = aliceAccount->getUsername(); auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId); auto bobUri = bobAccount->getUsername(); - std::string convId; - - std::mutex mtx; - std::unique_lock<std::mutex> lk {mtx}; - std::condition_variable cv; - std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers; - auto messageReceived = false; - std::string msgId = ""; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::MessageReceived>( - [&](const std::string& /* accountId */, - const std::string& /* conversationId */, - std::map<std::string, std::string> message) { - messageReceived = true; - msgId = message["id"]; - cv.notify_one(); - })); - auto conversationReady = false, conversationAlice2Ready = false; - confHandlers.insert(libjami::exportable_callback<libjami::ConversationSignal::ConversationReady>( - [&](const std::string& accountId, const std::string& conversationId) { - if (accountId == bobId) { - convId = conversationId; - conversationReady = true; - } else if (accountId == alice2Id) { - conversationAlice2Ready = true; - } - cv.notify_one(); - })); - auto requestReceived = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConversationSignal::ConversationRequestReceived>( - [&](const std::string& accountId, - const std::string& /*conversationId*/, - std::map<std::string, std::string> /*metadatas*/) { - if (accountId == bobId) - requestReceived = true; - cv.notify_one(); - })); - auto messageDisplayed = false, messageDisplayedAlice2 = false; - confHandlers.insert( - libjami::exportable_callback<libjami::ConfigurationSignal::AccountMessageStatusChanged>( - [&](const std::string& accountId, - const std::string& /* conversationId */, - const std::string& /* username */, - const std::string& msgId, - int status) { - if (status == 3) { - if (accountId == aliceId) - messageDisplayed = true; - else if (accountId == alice2Id) - messageDisplayedAlice2 = true; - } - cv.notify_one(); - })); - libjami::registerSignalHandlers(confHandlers); - confHandlers.clear(); // Creates alice2 auto aliceArchive = std::filesystem::current_path().string() + "/alice.gz"; @@ -1222,30 +877,26 @@ SyncHistoryTest::testLastInteractionAfterSomeMessages() aliceAccount->addContact(bobUri); aliceAccount->sendTrustRequest(bobUri, {}); - CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return requestReceived; })); + CPPUNIT_ASSERT(cv.wait_for(lk, 30s, [&]() { return bobData.requestReceived && !alice2Data.conversationId.empty(); })); + auto aliceMsgSize = aliceData.messages.size(); CPPUNIT_ASSERT(bobAccount->acceptTrustRequest(aliceUri)); CPPUNIT_ASSERT( - cv.wait_for(lk, 30s, [&]() { return conversationReady && conversationAlice2Ready; })); + cv.wait_for(lk, 30s, [&]() { return aliceMsgSize + 1 == aliceData.messages.size(); })); // Start conversation - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 1"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 2"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - messageReceived = false; - libjami::sendMessage(bobId, convId, std::string("Message 3"), ""); - CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return messageReceived; })); - - messageDisplayed = false; - messageDisplayedAlice2 = false; - auto displayedId = msgId; - libjami::setMessageDisplayed(aliceId, "swarm:" + convId, displayedId, 3); - CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return messageDisplayed && messageDisplayedAlice2; })); - - auto membersInfos = libjami::getConversationMembers(alice2Id, convId); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 1"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 2 == aliceData.messages.size(); })); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 2"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 3 == aliceData.messages.size(); })); + libjami::sendMessage(bobId, aliceData.conversationId, std::string("Message 3"), ""); + CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return aliceMsgSize + 4 == aliceData.messages.size(); })); + + auto displayedId = aliceData.messages.rbegin()->id; + libjami::setMessageDisplayed(aliceId, "swarm:" + aliceData.conversationId, displayedId, 3); + CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return aliceData.sent && alice2Data.sent; })); + + auto membersInfos = libjami::getConversationMembers(alice2Id, alice2Data.conversationId); CPPUNIT_ASSERT(std::find_if(membersInfos.begin(), membersInfos.end(), [&](auto infos) {