From ff362e99d9283733152d6074b6fdee08b7c95db8 Mon Sep 17 00:00:00 2001 From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com> Date: Tue, 4 Mar 2025 17:13:34 +0100 Subject: [PATCH] Add tests to verify behaviour of a basic chatroom with CPIM and IMDN enabled Make more robust database migration code as the user may set database paths but instruct the core not to initialize the database. This behaviour can de achieved by the following lines in the rc file: [misc] use_database=1 [storage] uri=null By not explicitely disabling friends, call log and chat database, the SDK assumes that they are enabled and migration sould be carried out --- coreapi/linphonecore.c | 14 ++-- src/c-wrapper/api/c-friend.cpp | 9 ++- src/chat/chat-message/chat-message.cpp | 16 ++-- src/chat/chat-room/chat-room.cpp | 6 +- src/core/core.cpp | 2 + tester/CMakeLists.txt | 1 + tester/group_chat_tester.c | 101 +++++++++++++++++++++---- tester/rcfiles/empty_with_some_db_rc | 15 ++++ tester/setup_tester.c | 37 +++++++-- tester/tester.c | 1 + 10 files changed, 163 insertions(+), 39 deletions(-) create mode 100644 tester/rcfiles/empty_with_some_db_rc diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 0827aae812..decbdedfdc 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -6368,12 +6368,13 @@ void linphone_core_set_call_logs_database_path(LinphoneCore *lc, const char *pat CoreLogContextualizer logContextualizer(lc); if (!linphone_core_conference_server_enabled(lc)) { auto &mainDb = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb; - if (mainDb) { + if (mainDb && mainDb->isInitialized()) { mainDb->import(LinphonePrivate::MainDb::Sqlite3, path); linphone_core_migrate_logs_from_rc_to_db(lc); } else { - ms_warning("linphone_core_set_call_logs_database_path() needs to be called once linphone_core_start() has " - "been called"); + ms_warning("%s() needs to be called once linphone_core_start() has been called or Database has not been " + "initialized, therefore it is not possible to import call log database at %s", + __func__, path); } } } @@ -8922,12 +8923,13 @@ void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path) { CoreLogContextualizer logContextualizer(lc); if (!linphone_core_conference_server_enabled(lc)) { auto &mainDb = L_GET_PRIVATE_FROM_C_OBJECT(lc)->mainDb; - if (mainDb) { + if (mainDb && mainDb->isInitialized()) { mainDb->import(LinphonePrivate::MainDb::Sqlite3, path); L_GET_PRIVATE_FROM_C_OBJECT(lc)->loadChatRooms(); } else { - ms_warning("linphone_core_set_chat_database_path() needs to be called once linphone_core_start() has " - "been called"); + ms_warning("%s() needs to be called once linphone_core_start() has been called or Database has not been " + "initialized, therefore it is not possible to import chat database at %s", + __func__, path); } } } diff --git a/src/c-wrapper/api/c-friend.cpp b/src/c-wrapper/api/c-friend.cpp index bb240074e5..dce4d693be 100644 --- a/src/c-wrapper/api/c-friend.cpp +++ b/src/c-wrapper/api/c-friend.cpp @@ -898,9 +898,14 @@ void linphone_core_set_friends_database_path(LinphoneCore *lc, const char *path) lc->friends_db_file = ms_strdup(path); } - if (L_GET_PRIVATE(lc->cppPtr)->mainDb) { - if (L_GET_PRIVATE(lc->cppPtr)->mainDb->import(LinphonePrivate::MainDb::Sqlite3, path)) + auto &mainDb = L_GET_PRIVATE(lc->cppPtr)->mainDb; + if (mainDb && mainDb->isInitialized()) { + if (mainDb->import(LinphonePrivate::MainDb::Sqlite3, path)) linphone_core_friends_storage_resync_friends_lists(lc); + } else { + ms_warning( + "Database has not been initialized, therefore it is not possible to import friends database at path %s", + path); } } } diff --git a/src/chat/chat-message/chat-message.cpp b/src/chat/chat-message/chat-message.cpp index 7152e1a4d0..fc5dd10c2b 100644 --- a/src/chat/chat-message/chat-message.cpp +++ b/src/chat/chat-message/chat-message.cpp @@ -816,8 +816,8 @@ void ChatMessagePrivate::setChatRoom(const shared_ptr<AbstractChatRoom> &chatRoo if (isBasicChatRoom) { localAddress = account->getAccountParams()->getIdentityAddress(); lInfo() << *chatRoom << " with ID " << conferenceId - << " is a basic chatroom therefore set the local address of message [" << q - << "] to the account identity address " << *localAddress; + << " is a basic chatroom therefore set the local address of message [" << q << "] to the account [" + << account << "]'s identity address " << *localAddress; } else { localAddress = account->getContactAddress(); if (localAddress) { @@ -828,10 +828,14 @@ void ChatMessagePrivate::setChatRoom(const shared_ptr<AbstractChatRoom> &chatRoo } } if (!localAddress) { - lInfo() << *chatRoom << " with ID " << conferenceId - << " has no account associated to or the contact or the identity address is not available yet, setting " - "conference ID's local address as message local address"; localAddress = conferenceId.getLocalAddress(); + if (localAddress) { + lInfo() + << *chatRoom << " with ID " << conferenceId + << " has no account associated to or the contact or the identity address is not available yet, setting " + "conference ID's local address as message local address " + << *localAddress; + } } if (localAddress) { @@ -840,6 +844,8 @@ void ChatMessagePrivate::setChatRoom(const shared_ptr<AbstractChatRoom> &chatRoo } else { localAddress = localAddress->clone()->toSharedPtr(); } + } else { + lError() << "Unable to set local address of message [" << q << "] in " << *chatRoom; } auto peerAddress = conferenceId.getPeerAddress()->clone()->toSharedPtr(); diff --git a/src/chat/chat-room/chat-room.cpp b/src/chat/chat-room/chat-room.cpp index eae6947e9e..b7f37db5dc 100644 --- a/src/chat/chat-room/chat-room.cpp +++ b/src/chat/chat-room/chat-room.cpp @@ -724,10 +724,12 @@ void ChatRoom::notifyAggregatedChatMessages() { bctbx_list_t *cEvents = L_GET_RESOLVED_C_LIST_FROM_CPP_LIST(eventsList); _linphone_chat_room_notify_chat_messages_received(cChatRoom, cEvents); - // Notify delivery + // Notify delivery - do the same things as when chat messages are not aggregated: send the delivery notification + // when the message is in the Delivered state for (auto &chatMessage : aggregatedMessages) { - chatMessage->getPrivate()->setParticipantState(getMe()->getAddress(), ChatMessage::State::DeliveredToUser, + chatMessage->getPrivate()->setParticipantState(getMe()->getAddress(), ChatMessage::State::Delivered, ::ms_time(nullptr)); + sendDeliveryNotification(chatMessage); } bctbx_list_free_with_data(cMessages, (bctbx_list_free_func)linphone_chat_message_unref); diff --git a/src/core/core.cpp b/src/core/core.cpp index 242f4df012..cc7ac2dac2 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -231,6 +231,8 @@ void CorePrivate::init() { linphone_core_set_friends_database_path(lc, friendsDbPath.c_str()); } else lWarning() << "Friends database explicitely not requested"; } + } else { + lInfo() << "The Core was explicitely requested not to use any database"; } createConferenceCleanupTimer(); diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 1855e4df8a..b58e258193 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -148,6 +148,7 @@ set(RC_FILES rcfiles/chloe_dual_proxy_rc rcfiles/conference_focus_rc rcfiles/empty_rc + rcfiles/empty_with_some_db_rc rcfiles/friends_rc rcfiles/groupchat_rc rcfiles/invalid_friends_rc diff --git a/tester/group_chat_tester.c b/tester/group_chat_tester.c index 25e4e5bf01..68ca6b1c16 100644 --- a/tester/group_chat_tester.c +++ b/tester/group_chat_tester.c @@ -61,9 +61,7 @@ static bool_t wait_for_chat_room_participants(bctbx_list_t *lcs, LinphoneChatRoo linphone_core_iterate((LinphoneCore *)(iterator->data)); } #ifdef LINPHONE_WINDOWS_UWP - { - bc_tester_process_events(); - } + { bc_tester_process_events(); } #elif defined(LINPHONE_WINDOWS_DESKTOP) { MSG msg; @@ -6201,7 +6199,7 @@ end: linphone_core_manager_destroy(chloe); } -static void basic_chat_room_with_cpim_base(bool_t use_gruu) { +static void basic_chat_room_with_cpim_base(bool_t use_gruu, bool_t enable_imdn) { LinphoneCoreManager *marie = linphone_core_manager_create("marie_rc"); LinphoneCoreManager *pauline = linphone_core_manager_create("pauline_rc"); bctbx_list_t *coresManagerList = NULL; @@ -6213,6 +6211,15 @@ static void basic_chat_room_with_cpim_base(bool_t use_gruu) { bctbx_list_t *coresList = init_core_for_conference(coresManagerList); start_core_for_conference(coresManagerList); + if (enable_imdn) { + // Enable IMDN + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(marie->lc)); + linphone_im_notif_policy_enable_all(linphone_core_get_im_notif_policy(pauline->lc)); + } + + linphone_core_set_chat_messages_aggregation_enabled(marie->lc, TRUE); + linphone_config_set_int(linphone_core_get_config(marie->lc), "sip", "chat_messages_aggregation_delay", 10); + // Enable CPIM LinphoneAccount *marie_account = linphone_core_get_default_account(marie->lc); const LinphoneAccountParams *marie_account_params = linphone_account_get_params(marie_account); @@ -6247,19 +6254,27 @@ static void basic_chat_room_with_cpim_base(bool_t use_gruu) { // Marie sends a message in a basic chatroom const char *marie_text = "This is a basic chat room"; + LinphoneChatMessage *marie_msg = NULL; if (marieCr) { const LinphoneAddress *peer_address = linphone_chat_room_get_peer_address(marieCr); BC_ASSERT_TRUE(linphone_address_has_uri_param(peer_address, "gr")); - LinphoneChatMessage *sent_msg = _send_message(marieCr, marie_text); + linphone_chat_room_compose(marieCr); + BC_ASSERT_TRUE(wait_for(pauline->lc, marie->lc, &pauline->stat.number_of_LinphoneIsComposingActiveReceived, 1)); + BC_ASSERT_FALSE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, 1, 2000)); + marie_msg = _send_message(marieCr, marie_text); BC_ASSERT_TRUE( wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageSent, 1, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneChatRoomStateCreated, 1, liblinphone_tester_sip_timeout)); BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageReceived, 1, liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDelivered, 1, - liblinphone_tester_sip_timeout)); - linphone_chat_message_unref(sent_msg); + if (enable_imdn) { + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDeliveredToUser, 1, + liblinphone_tester_sip_timeout)); + } else { + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDelivered, 1, + liblinphone_tester_sip_timeout)); + } } LinphoneConferenceParams *pauline_params = linphone_core_create_conference_params(pauline->lc); @@ -6275,7 +6290,23 @@ static void basic_chat_room_with_cpim_base(bool_t use_gruu) { linphone_chat_room_params_unref(pauline_params); const char *pauline_text = "Yes Madam"; + LinphoneChatMessage *pauline_msg = NULL; if (paulineCr) { + linphone_chat_room_compose(paulineCr); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneIsComposingActiveReceived, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_FALSE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneIsComposingActiveReceived, 2, 2000)); + BC_ASSERT_FALSE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, 1, 2000)); + if (enable_imdn) { + linphone_chat_room_mark_as_read(paulineCr); + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDisplayed, 1, + liblinphone_tester_sip_timeout)); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDisplayed, 1, + liblinphone_tester_sip_timeout)); + } + if (marie_msg) { + linphone_chat_message_unref(marie_msg); + } LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(paulineCr); if (BC_ASSERT_PTR_NOT_NULL(msg)) { BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg), marie_text); @@ -6283,27 +6314,60 @@ static void basic_chat_room_with_cpim_base(bool_t use_gruu) { } const LinphoneAddress *local_address = linphone_chat_room_get_local_address(paulineCr); BC_ASSERT_TRUE(linphone_address_has_uri_param(local_address, "gr")); - LinphoneChatMessage *sent_msg = _send_message(paulineCr, pauline_text); + pauline_msg = _send_message(paulineCr, pauline_text); BC_ASSERT_TRUE( wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageSent, 1, liblinphone_tester_sip_timeout)); BC_ASSERT_FALSE(wait_for_list(coresList, &marie->stat.number_of_LinphoneChatRoomStateCreated, 2, 2000)); - BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageReceived, 1, - liblinphone_tester_sip_timeout)); - BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDelivered, 1, + BC_ASSERT_TRUE(wait_for_list(coresList, &marie->stat.number_of_LinphoneAggregatedMessagesReceived, 1, liblinphone_tester_sip_timeout)); - linphone_chat_message_unref(sent_msg); + if (enable_imdn) { + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDeliveredToUser, 1, + liblinphone_tester_sip_timeout)); + } else { + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDelivered, 1, + liblinphone_tester_sip_timeout)); + } } + LinphoneChatMessageState expected_msg_state = + (enable_imdn) ? LinphoneChatMessageStateDisplayed : LinphoneChatMessageStateDelivered; if (marieCr) { + if (enable_imdn) { + linphone_chat_room_mark_as_read(marieCr); + BC_ASSERT_TRUE(wait_for_list(coresList, &pauline->stat.number_of_LinphoneMessageDisplayed, 2, + liblinphone_tester_sip_timeout)); + // As Marie enables chat message aggregation, the message state changed is not called + BC_ASSERT_FALSE(wait_for_list(coresList, &marie->stat.number_of_LinphoneMessageDisplayed, 2, 1000)); + } + if (pauline_msg) { + linphone_chat_message_unref(pauline_msg); + } + LinphoneChatMessage *msg = linphone_chat_room_get_last_message_in_history(marieCr); if (BC_ASSERT_PTR_NOT_NULL(msg)) { BC_ASSERT_STRING_EQUAL(linphone_chat_message_get_text(msg), pauline_text); linphone_chat_message_unref(msg); } + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(marieCr), 2, int, "%d"); + bctbx_list_t *marie_history = linphone_chat_room_get_history(marieCr, 3); + for (bctbx_list_t *item = marie_history; item; item = bctbx_list_next(item)) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)bctbx_list_get_data(item); + BC_ASSERT_EQUAL(linphone_chat_message_get_state(msg), expected_msg_state, int, "%d"); + } + bctbx_list_free_with_data(marie_history, (bctbx_list_free_func)linphone_chat_message_unref); linphone_core_manager_delete_chat_room(marie, marieCr, coresList); linphone_chat_room_unref(marieCr); } - if (paulineCr) linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList); + if (paulineCr) { + BC_ASSERT_EQUAL(linphone_chat_room_get_history_size(paulineCr), 2, int, "%d"); + bctbx_list_t *pauline_history = linphone_chat_room_get_history(paulineCr, 3); + for (bctbx_list_t *item = pauline_history; item; item = bctbx_list_next(item)) { + LinphoneChatMessage *msg = (LinphoneChatMessage *)bctbx_list_get_data(item); + BC_ASSERT_EQUAL(linphone_chat_message_get_state(msg), expected_msg_state, int, "%d"); + } + bctbx_list_free_with_data(pauline_history, (bctbx_list_free_func)linphone_chat_message_unref); + linphone_core_manager_delete_chat_room(pauline, paulineCr, coresList); + } bctbx_list_free(coresList); bctbx_list_free(coresManagerList); @@ -6313,11 +6377,15 @@ static void basic_chat_room_with_cpim_base(bool_t use_gruu) { } static void basic_chat_room_with_cpim_gruu(void) { - basic_chat_room_with_cpim_base(TRUE); + basic_chat_room_with_cpim_base(TRUE, FALSE); +} + +static void basic_chat_room_with_cpim_gruu_imdn(void) { + basic_chat_room_with_cpim_base(TRUE, TRUE); } static void basic_chat_room_with_cpim_without_gruu(void) { - basic_chat_room_with_cpim_base(FALSE); + basic_chat_room_with_cpim_base(FALSE, FALSE); } static void find_one_to_one_chat_room(void) { @@ -9629,6 +9697,7 @@ test_t group_chat2_tests[] = { TEST_NO_TAG("IMDN updated for group chat room with one participant offline", imdn_updated_for_group_chat_room_with_one_participant_offline), TEST_NO_TAG("Basic chat room with CPIM and GRUU", basic_chat_room_with_cpim_gruu), + TEST_NO_TAG("Basic chat room with CPIM, GRUU and IMDN", basic_chat_room_with_cpim_gruu_imdn), TEST_NO_TAG("Basic chat room with CPIM and without GRUU", basic_chat_room_with_cpim_without_gruu), TEST_NO_TAG("Find one-to-one chat room", find_one_to_one_chat_room), TEST_NO_TAG("Exhumed one-to-one chat room 1", exhume_one_to_one_chat_room_1), diff --git a/tester/rcfiles/empty_with_some_db_rc b/tester/rcfiles/empty_with_some_db_rc new file mode 100644 index 0000000000..01ffeb09e0 --- /dev/null +++ b/tester/rcfiles/empty_with_some_db_rc @@ -0,0 +1,15 @@ + +[sip] +# Request no port to be bound. +# By default, liblinphone binds on port 5060. This is a problem as multiple bindings for UDP is allowed and liblinphone_tester suite usually runs on parallel +# which cause port conflicts that are undetected. +sip_port=-2 +sip_tcp_port=-2 +sip_tls_port=-2 + +[storage] +# Disable main database only +uri=null + +[tester] +test_env=1 diff --git a/tester/setup_tester.c b/tester/setup_tester.c index 506352c24a..09e271ce7a 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -177,19 +177,25 @@ static void linphone_version_update_test(void) { linphone_core_manager_destroy(lcm); } -static void core_init_test(void) { +static void core_init_test_base(bool_t use_database, bool_t disable_main_db_only) { LinphoneCore *lc; FILE *in; - lc = - linphone_factory_create_core_3(linphone_factory_get(), NULL, liblinphone_tester_get_empty_rc(), system_context); + char *empty_with_some_db_rc_path = bc_tester_res("rcfiles/empty_with_some_db_rc"); + lc = linphone_factory_create_core_3( + linphone_factory_get(), NULL, + (disable_main_db_only) ? empty_with_some_db_rc_path : liblinphone_tester_get_empty_rc(), system_context); if (BC_ASSERT_PTR_NOT_NULL(lc)) { linphone_config_set_int(linphone_core_get_config(lc), "lime", "enabled", 0); + linphone_core_enable_database(lc, use_database); linphone_core_start(lc); - const char *uri = linphone_config_get_string(linphone_core_get_config(lc), "storage", "uri", NULL); - BC_ASSERT_STRING_EQUAL(uri, "null"); - in = fopen(uri, "rb"); - if (!BC_ASSERT_PTR_NULL(in)) // "null" file should not exists - fclose(in); + if (use_database) { + const char *uri = linphone_config_get_string(linphone_core_get_config(lc), "storage", "uri", NULL); + BC_ASSERT_STRING_EQUAL(uri, "null"); + in = fopen(uri, "rb"); + if (!BC_ASSERT_PTR_NULL(in)) // "null" file should not exists + fclose(in); + } + BC_ASSERT_TRUE(linphone_core_database_enabled(lc) == use_database); /* until we have good certificates on our test server... */ linphone_core_verify_server_certificates(lc, FALSE); BC_ASSERT_EQUAL(linphone_core_get_global_state(lc), LinphoneGlobalOn, int, "%i"); @@ -237,6 +243,19 @@ static void core_init_test(void) { linphone_core_stop(lc); linphone_core_unref(lc); } + ms_free(empty_with_some_db_rc_path); +} + +static void core_init_test(void) { + core_init_test_base(TRUE, FALSE); +} + +static void core_init_test_some_database(void) { + core_init_test_base(TRUE, TRUE); +} + +static void core_init_test_no_database(void) { + core_init_test_base(FALSE, FALSE); } static void core_init_test_2(void) { @@ -3860,6 +3879,8 @@ test_t setup_tests[] = { TEST_NO_TAG("Linphone proxy config server address change (internal api)", linphone_proxy_config_is_server_config_changed_test), TEST_NO_TAG("Linphone core init/uninit", core_init_test), + TEST_NO_TAG("Linphone core init/uninit with some database", core_init_test_some_database), + TEST_NO_TAG("Linphone core init/uninit without database", core_init_test_no_database), TEST_NO_TAG("Linphone core init/uninit from existing factory rc", core_init_test_2), TEST_NO_TAG("Linphone core init/uninit withtout any rc", core_init_test_3), TEST_NO_TAG("Linphone core init/uninit from existing default rc", core_init_test_4), diff --git a/tester/tester.c b/tester/tester.c index 4467d6909b..1c255e5a49 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -3461,6 +3461,7 @@ void messages_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneChatRoom *room), c counters = get_stats(lc); int count = (int)bctbx_list_size(messages); counters->number_of_LinphoneAggregatedMessagesReceived += count; + ms_message("Received %0d aggregated messages", count); } void message_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneChatRoom *room), LinphoneChatMessage *msg) { -- GitLab