From 4cd6ef67b46d52a96355018dc37a33098bd528bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Thu, 23 Sep 2021 14:04:47 +0200 Subject: [PATCH 1/7] Extract is_exported function to backend_module --- src/auth/mongoose_gen_auth.erl | 8 ++------ src/backend_module.erl | 8 +++++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/auth/mongoose_gen_auth.erl b/src/auth/mongoose_gen_auth.erl index b8923f47c0..77f093071b 100644 --- a/src/auth/mongoose_gen_auth.erl +++ b/src/auth/mongoose_gen_auth.erl @@ -20,6 +20,8 @@ -ignore_xref([behaviour_info/1]). +-import(backend_module, [is_exported/3]). + %% Mandatory callbacks -callback start(HostType :: mongooseim:host_type()) -> ok. @@ -232,9 +234,3 @@ check_password(Mod, HostType, LUser, LServer, Password, Digest, DigestGen) -> true -> Mod:check_password(HostType, LUser, LServer, Password, Digest, DigestGen); false -> false end. - -%% Internal functions - -is_exported(Mod, F, Arity) -> - code:ensure_loaded(Mod), - erlang:function_exported(Mod, F, Arity). diff --git a/src/backend_module.erl b/src/backend_module.erl index 471c1b405c..89dca06cf9 100644 --- a/src/backend_module.erl +++ b/src/backend_module.erl @@ -26,7 +26,7 @@ -author('alexey@process-one.net'). -author('konrad.zemek@erlang-solutions.com'). --export([create/2, backend_module/2, create/3]). +-export([create/2, backend_module/2, create/3, is_exported/3]). -ignore_xref([create/2, backend_module/2, behaviour_info/1]). @@ -56,6 +56,12 @@ create(Module, Backend, TrackedFuns) -> {ok, ProxyModule} end. +-spec is_exported(Module :: module(), Function :: atom(), + Arity :: integer()) -> boolean(). +is_exported(Module, Function, Arity) -> + code:ensure_loaded(Module), + erlang:function_exported(Module, Function, Arity). + %% Internal functions -spec proxy_module(Module :: module()) -> module(). From 016471ad5e02464dcd280a3dfb6f36f7eef749b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Wed, 22 Sep 2021 14:43:13 +0200 Subject: [PATCH 2/7] Add remove domain to mod_roster --- src/mod_roster.erl | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/mod_roster.erl b/src/mod_roster.erl index 61d73eb12c..519d8b65a1 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -61,6 +61,7 @@ get_subscription_lists/2, get_jid_info/4, remove_user/3, + remove_domain/3, get_versioning_feature/2, get_personal_data/3 ]). @@ -79,6 +80,7 @@ {?MOD_ROSTER_BACKEND, get_subscription_lists, 3}, {?MOD_ROSTER_BACKEND, read_roster_version, 3}, {?MOD_ROSTER_BACKEND, remove_user_t, 3}, + {?MOD_ROSTER_BACKEND, remove_domain_t, 2}, {?MOD_ROSTER_BACKEND, roster_subscribe_t, 2}, {?MOD_ROSTER_BACKEND, init, 2}, {?MOD_ROSTER_BACKEND, transaction, 2}, @@ -87,7 +89,7 @@ behaviour_info/1, get_jid_info/4, get_personal_data/3, get_subscription_lists/2, get_user_roster/2, get_user_rosters_length/2, get_versioning_feature/2, in_subscription/5, item_to_xml/1, out_subscription/4, process_subscription_t/6, - remove_user/3, transaction/2 + remove_user/3, remove_domain/3, transaction/2 ]). -include("mongoose.hrl"). @@ -143,6 +145,10 @@ -callback remove_user_t(mongooseim:host_type(), jid:luser(), jid:lserver()) -> ok. +-callback remove_domain_t(mongooseim:host_type(), jid:lserver()) -> ok. + +-optional_callbacks([remove_domain_t/2]). + %%-------------------------------------------------------------------- %% gdpr callback %%-------------------------------------------------------------------- @@ -224,6 +230,7 @@ hooks(HostType) -> {roster_get_subscription_lists, HostType, ?MODULE, get_subscription_lists, 50}, {roster_get_jid_info, HostType, ?MODULE, get_jid_info, 50}, {remove_user, HostType, ?MODULE, remove_user, 50}, + {remove_domain, HostType, ?MODULE, remove_domain, 50}, {anonymous_purge_hook, HostType, ?MODULE, remove_user, 50}, {roster_get_versioning_feature, HostType, ?MODULE, get_versioning_feature, 50}, {get_personal_data, HostType, ?MODULE, get_personal_data, 50}]. @@ -878,6 +885,25 @@ send_presence_type(From, To, Type) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec remove_domain(mongoose_hooks:simple_acc(), + mongooseim:host_type(), jid:lserver()) -> + mongoose_hooks:simple_acc(). +remove_domain(Acc, HostType, Domain) -> + case backend_module:is_exported(mod_roster_backend, remove_domain_t, 2) of + true -> + F = fun() -> mod_roster_backend:remove_domain_t(HostType, Domain) end, + case transaction(HostType, F) of + {atomic, ok} -> + ok; + Result -> + ?LOG_ERROR(#{what => remove_domain_transaction_failed, + reason => Result}) + end; + false -> + ok + end, + Acc. + -spec set_items(mongooseim:host_type(), jid:jid(), exml:element()) -> ok | {error, any()}. set_items(HostType, #jid{luser = LUser, lserver = LServer}, SubEl) -> F = fun() -> set_items_t(HostType, LUser, LServer, SubEl) end, From 624a230c0550983846167bf0757ecc8b59cb1b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Wed, 22 Sep 2021 14:46:25 +0200 Subject: [PATCH 3/7] Handle domain removal in mod_roster_rdbms backend --- src/mod_roster_rdbms.erl | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/mod_roster_rdbms.erl b/src/mod_roster_rdbms.erl index 8e2c0dd1bc..7930472dae 100644 --- a/src/mod_roster_rdbms.erl +++ b/src/mod_roster_rdbms.erl @@ -28,7 +28,8 @@ roster_subscribe_t/2, update_roster_t/2, del_roster_t/4, - remove_user_t/3]). + remove_user_t/3, + remove_domain_t/2]). %% mod_roster backend API @@ -114,6 +115,13 @@ remove_user_t(HostType, LUser, LServer) -> mongoose_rdbms:execute_successfully(HostType, roster_group_delete, [LServer, LUser]), ok. +-spec remove_domain_t(mongooseim:host_type(), jid:lserver()) -> ok. +remove_domain_t(HostType, Domain) -> + mongoose_rdbms:execute_successfully(HostType, rosterusers_remove_domain, [Domain]), + mongoose_rdbms:execute_successfully(HostType, rostergroups_remove_domain, [Domain]), + mongoose_rdbms:execute_successfully(HostType, roster_version_remove_domain, [Domain]), + ok. + %% Query preparation prepare_queries(HostType) -> @@ -144,6 +152,12 @@ prepare_queries(HostType) -> mongoose_rdbms:prepare(roster_group_delete_by_jid, rostergroups, [server, username, jid], <<"DELETE FROM rostergroups" " WHERE server = ? AND username = ? AND jid = ?">>), + mongoose_rdbms:prepare(rosterusers_remove_domain, rosterusers, [server], + <<"DELETE FROM rosterusers WHERE server = ?">>), + mongoose_rdbms:prepare(rostergroups_remove_domain, rostergroups, [server], + <<"DELETE FROM rostergroups WHERE server = ?">>), + mongoose_rdbms:prepare(roster_version_remove_domain, roster_version, [server], + <<"DELETE FROM roster_version WHERE server = ?">>), prepare_roster_upsert(HostType), prepare_version_upsert(HostType), ok. From e453448d667b09f797483956467aeb0ef38c6887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Wed, 22 Sep 2021 14:48:22 +0200 Subject: [PATCH 4/7] Add test case for roster domain removal in domain_removal_SUITE --- big_tests/tests/domain_removal_SUITE.erl | 40 +++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/big_tests/tests/domain_removal_SUITE.erl b/big_tests/tests/domain_removal_SUITE.erl index 7d5e5a7ce9..880fac04b5 100644 --- a/big_tests/tests/domain_removal_SUITE.erl +++ b/big_tests/tests/domain_removal_SUITE.erl @@ -15,7 +15,8 @@ inbox_removal/1, muc_light_removal/1, muc_light_blocking_removal/1, - private_removal/1]). + private_removal/1, + roster_removal/1]). -import(distributed_helper, [mim/0, rpc/4, subhost_pattern/1]). -import(domain_helper, [host_type/0, domain/0]). @@ -30,7 +31,8 @@ all() -> [{group, mam_removal}, {group, inbox_removal}, {group, muc_light_removal}, - {group, private_removal}]. + {group, private_removal}, + {group, roster_removal}]. groups() -> [ @@ -39,7 +41,8 @@ groups() -> {inbox_removal, [], [inbox_removal]}, {muc_light_removal, [], [muc_light_removal, muc_light_blocking_removal]}, - {private_removal, [], [private_removal]} + {private_removal, [], [private_removal]}, + {roster_removal, [], [roster_removal]} ]. %%%=================================================================== @@ -84,7 +87,9 @@ group_to_modules(muc_light_removal) -> group_to_modules(inbox_removal) -> [{mod_inbox, []}]; group_to_modules(private_removal) -> - [{mod_private, [{backend, rdbms}]}]. + [{mod_private, [{backend, rdbms}]}]; +group_to_modules(roster_removal) -> + [{mod_roster, [{backend, rdbms}]}]. %%%=================================================================== %%% Testcase specific setup/teardown @@ -197,6 +202,33 @@ private_removal(Config) -> ?assert_equal_extra(<<>>, Val2, #{stanza => Res2}) end). +bobs_default_groups() -> [<<"friends">>]. + +bobs_default_name() -> <<"Bobby">>. + +roster_removal(Config) -> + escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> + %% add contact + Stanza = escalus_stanza:roster_add_contact(Bob, bobs_default_groups(), + bobs_default_name()), + escalus:send(Alice, Stanza), + Received = escalus:wait_for_stanzas(Alice, 2), + escalus:assert_many([is_roster_set, is_iq_result], Received), + + %% check roster + BobJid = escalus_client:short_jid(Bob), + Received2 = escalus:send_iq_and_wait_for_result(Alice, escalus_stanza:roster_get()), + escalus:assert(is_roster_result, Received2), + escalus:assert(roster_contains, [BobJid], Received2), + escalus:assert(count_roster_items, [1], Received2), + + %% remove domain and check roster + run_remove_domain(), + Received3 = escalus:send_iq_and_wait_for_result(Alice, escalus_stanza:roster_get()), + escalus:assert(is_roster_result, Received3), + escalus:assert(count_roster_items, [0], Received3) + end). + run_remove_domain() -> rpc(mim(), mongoose_hooks, remove_domain, [host_type(), domain()]). From 1de9089a535ecdceda7e26ea71375ce8906ad5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Thu, 23 Sep 2021 13:13:10 +0200 Subject: [PATCH 5/7] Extract set/restore versioning functions to roster_helper module --- big_tests/tests/presence_SUITE.erl | 19 ++----------------- big_tests/tests/roster_helper.erl | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 big_tests/tests/roster_helper.erl diff --git a/big_tests/tests/presence_SUITE.erl b/big_tests/tests/presence_SUITE.erl index 9cf681eb6e..4d6eb9040d 100644 --- a/big_tests/tests/presence_SUITE.erl +++ b/big_tests/tests/presence_SUITE.erl @@ -26,6 +26,8 @@ -import(domain_helper, [host_type/0]). +-import(roster_helper, [set_versioning/3, restore_versioning/1]). + %%-------------------------------------------------------------------- %% Suite configuration %%-------------------------------------------------------------------- @@ -733,23 +735,6 @@ remove_roster(Config, UserSpec) -> end end. -set_versioning(Versioning, VersionStore, Config) -> - RosterVersioning = rpc(mim(), gen_mod, get_module_opt, - [host_type(), mod_roster, versioning, false]), - RosterVersionOnDb = rpc(mim(), gen_mod, get_module_opt, - [host_type(), mod_roster, store_current_id, false]), - rpc(mim(), gen_mod, set_module_opt, [host_type(), mod_roster, versioning, Versioning]), - rpc(mim(), gen_mod, set_module_opt, [host_type(), mod_roster, store_current_id, VersionStore]), - [{versioning, RosterVersioning}, - {store_current_id, RosterVersionOnDb} | Config]. - -restore_versioning(Config) -> - RosterVersioning = proplists:get_value(versioning, Config), - RosterVersionOnDb = proplists:get_value(store_current_id, Config), - rpc(mim(), gen_mod, get_module_opt, [host_type(), mod_roster, versioning, RosterVersioning]), - rpc(mim(), gen_mod, get_module_opt, [host_type(), mod_roster, store_current_id, RosterVersionOnDb]). - - check_roster_count(User, ExpectedCount) -> % the user sends get_roster iq escalus_client:send(User, escalus_stanza:roster_get()), diff --git a/big_tests/tests/roster_helper.erl b/big_tests/tests/roster_helper.erl new file mode 100644 index 0000000000..5c0787dab0 --- /dev/null +++ b/big_tests/tests/roster_helper.erl @@ -0,0 +1,23 @@ +-module(roster_helper). +-export([set_versioning/3, restore_versioning/1]). + +-import(distributed_helper, [mim/0, rpc/4]). +-import(domain_helper, [host_type/0]). + +-spec set_versioning(boolean(), boolean(), escalus_config:config()) -> escalus_config:config(). +set_versioning(Versioning, VersionStore, Config) -> + RosterVersioning = rpc(mim(), gen_mod, get_module_opt, + [host_type(), mod_roster, versioning, false]), + RosterVersionOnDb = rpc(mim(), gen_mod, get_module_opt, + [host_type(), mod_roster, store_current_id, false]), + rpc(mim(), gen_mod, set_module_opt, [host_type(), mod_roster, versioning, Versioning]), + rpc(mim(), gen_mod, set_module_opt, [host_type(), mod_roster, store_current_id, VersionStore]), + [{versioning, RosterVersioning}, + {store_current_id, RosterVersionOnDb} | Config]. + +-spec restore_versioning(escalus_config:config()) -> escalus_config:config(). +restore_versioning(Config) -> + RosterVersioning = proplists:get_value(versioning, Config), + RosterVersionOnDb = proplists:get_value(store_current_id, Config), + rpc(mim(), gen_mod, get_module_opt, [host_type(), mod_roster, versioning, RosterVersioning]), + rpc(mim(), gen_mod, get_module_opt, [host_type(), mod_roster, store_current_id, RosterVersionOnDb]). From 1727d1cd80172e89de2caa121e98274d23ac0902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Thu, 23 Sep 2021 13:17:25 +0200 Subject: [PATCH 6/7] Enable versioning in roster domain removal test case --- big_tests/tests/domain_removal_SUITE.erl | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/big_tests/tests/domain_removal_SUITE.erl b/big_tests/tests/domain_removal_SUITE.erl index 880fac04b5..2a4c614ea0 100644 --- a/big_tests/tests/domain_removal_SUITE.erl +++ b/big_tests/tests/domain_removal_SUITE.erl @@ -95,9 +95,15 @@ group_to_modules(roster_removal) -> %%% Testcase specific setup/teardown %%%=================================================================== +init_per_testcase(roster_removal, ConfigIn) -> + Config = roster_helper:set_versioning(true, true, ConfigIn), + escalus:init_per_testcase(roster_removal, Config); init_per_testcase(TestCase, Config) -> escalus:init_per_testcase(TestCase, Config). +end_per_testcase(roster_removal, Config) -> + roster_helper:restore_versioning(Config), + escalus:end_per_testcase(roster_removal, Config); end_per_testcase(TestCase, Config) -> escalus:end_per_testcase(TestCase, Config). @@ -202,15 +208,10 @@ private_removal(Config) -> ?assert_equal_extra(<<>>, Val2, #{stanza => Res2}) end). -bobs_default_groups() -> [<<"friends">>]. - -bobs_default_name() -> <<"Bobby">>. - roster_removal(Config) -> escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> %% add contact - Stanza = escalus_stanza:roster_add_contact(Bob, bobs_default_groups(), - bobs_default_name()), + Stanza = escalus_stanza:roster_add_contact(Bob, [<<"friends">>], <<"Bobby">>), escalus:send(Alice, Stanza), Received = escalus:wait_for_stanzas(Alice, 2), escalus:assert_many([is_roster_set, is_iq_result], Received), From 379b5f9967e37750707b7e096c5e6656f99fc356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Wojtasik?= Date: Thu, 23 Sep 2021 13:18:00 +0200 Subject: [PATCH 7/7] Add DB tables checks before and after domain removal --- big_tests/tests/domain_removal_SUITE.erl | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/big_tests/tests/domain_removal_SUITE.erl b/big_tests/tests/domain_removal_SUITE.erl index 2a4c614ea0..d43f2857ef 100644 --- a/big_tests/tests/domain_removal_SUITE.erl +++ b/big_tests/tests/domain_removal_SUITE.erl @@ -223,13 +223,33 @@ roster_removal(Config) -> escalus:assert(roster_contains, [BobJid], Received2), escalus:assert(count_roster_items, [1], Received2), + {selected, [_]} = select_rosterusers(host_type(), domain()), + {selected, [_]} = select_rostergroups(host_type(), domain()), + {selected, [_]} = select_roster_version(host_type(), domain()), + %% remove domain and check roster run_remove_domain(), Received3 = escalus:send_iq_and_wait_for_result(Alice, escalus_stanza:roster_get()), escalus:assert(is_roster_result, Received3), - escalus:assert(count_roster_items, [0], Received3) + escalus:assert(count_roster_items, [0], Received3), + + {selected, []} = select_rosterusers(host_type(), domain()), + {selected, []} = select_rostergroups(host_type(), domain()), + {selected, []} = select_roster_version(host_type(), domain()) end). +select_rosterusers(HostType, Domain) -> + Query = "SELECT * FROM rosterusers WHERE server='" ++ binary_to_list(Domain) ++ "'", + rpc(mim(), mongoose_rdbms, sql_query, [HostType, Query]). + +select_rostergroups(HostType, Domain) -> + Query = "SELECT * FROM rostergroups WHERE server='" ++ binary_to_list(Domain) ++ "'", + rpc(mim(), mongoose_rdbms, sql_query, [HostType, Query]). + +select_roster_version(HostType, Domain) -> + Query = "SELECT * FROM roster_version WHERE server='" ++ binary_to_list(Domain) ++ "'", + rpc(mim(), mongoose_rdbms, sql_query, [HostType, Query]). + run_remove_domain() -> rpc(mim(), mongoose_hooks, remove_domain, [host_type(), domain()]).