diff --git a/big_tests/tests/gdpr_SUITE.erl b/big_tests/tests/gdpr_SUITE.erl index fb9725d255b..72f48a36651 100644 --- a/big_tests/tests/gdpr_SUITE.erl +++ b/big_tests/tests/gdpr_SUITE.erl @@ -21,6 +21,9 @@ dont_remove_other_user_private_xml/1, retrieve_roster/1, retrieve_mam_pm/1, + retrieve_mam_muc/1, + retrieve_mam_muc_private_msg/1, + retrieve_mam_muc_store_pm/1, retrieve_mam_muc_light/1, retrieve_mam_pm_and_muc_light_interfere/1, retrieve_mam_pm_and_muc_light_dont_interfere/1, @@ -130,8 +133,8 @@ groups() -> ]}, {retrieve_personal_data_mam_rdbms, [], mam_testcases()}, {retrieve_personal_data_mam_riak, [], mam_testcases()}, - {retrieve_personal_data_mam_cassandra, [], mam_testcases()}, - {retrieve_personal_data_mam_elasticsearch, [], [retrieve_mam_pm]}, + {retrieve_personal_data_mam_cassandra, [], all_mam_testcases()}, + {retrieve_personal_data_mam_elasticsearch, [], all_mam_testcases()}, {remove_personal_data, [], removal_testcases()}, {remove_personal_data_with_mods_disabled, [], removal_testcases()}, {remove_personal_data_inbox, [], [remove_inbox, remove_inbox_muclight, remove_inbox_muc]}]. @@ -156,6 +159,14 @@ mam_testcases() -> retrieve_mam_pm_and_muc_light_dont_interfere ]. +all_mam_testcases() -> + [ + retrieve_mam_muc, + retrieve_mam_muc_private_msg, + retrieve_mam_muc_store_pm + | mam_testcases() + ]. + init_per_suite(Config) -> Config1 = [{{ejabberd_cwd, mim()}, get_mim_cwd()} | dynamic_modules:save_modules(domain(), Config)], gdpr_removal_for_disabled_modules(true), @@ -247,7 +258,10 @@ init_per_testcase(CN, Config) when CN =:= remove_private; private_started(), escalus:init_per_testcase(CN, Config); -init_per_testcase(CN, Config) when CN =:= retrieve_mam_muc_light; +init_per_testcase(CN, Config) when CN =:= retrieve_mam_muc; + CN =:= retrieve_mam_muc_private_msg; + CN =:= retrieve_mam_muc_store_pm; + CN =:= retrieve_mam_muc_light; CN =:= retrieve_mam_pm_and_muc_light_interfere; CN =:= retrieve_mam_pm_and_muc_light_dont_interfere; CN =:= retrieve_mam_pm -> @@ -331,9 +345,21 @@ mam_required_modules(CN, Backend) when CN =:= retrieve_mam_pm_and_muc_light_dont mam_required_modules(retrieve_mam_pm_and_muc_light_interfere, Backend) -> [{mod_mam_meta, [{backend, Backend}, {rdbms_message_format, simple}, %% ignored for any other than rdbms backend + simple, %% used only by cassandra backend {pm, [{archive_groupchats, true}]}, {muc, [{host, "muclight.@HOST@"}]}]}, - {mod_muc_light, [{host, "muclight.@HOST@"}]}]. + {mod_muc_light, [{host, "muclight.@HOST@"}]}]; +mam_required_modules(CN, Backend) when CN =:= retrieve_mam_muc_private_msg; + CN =:= retrieve_mam_muc -> + [{mod_mam_meta, [{backend, Backend}, + {pm, [{archive_groupchats, false}]}, + {muc, [{host, "muc.@HOST@"}]}]}, + {mod_muc, [{host, "muc.@HOST@"}]}]; +mam_required_modules(retrieve_mam_muc_store_pm, Backend) -> + [{mod_mam_meta, [{backend, Backend}, + {pm, [{archive_groupchats, true}]}, + {muc, [{host, "muc.@HOST@"}]}]}, + {mod_muc, [{host, "muc.@HOST@"}]}]. pick_enabled_backend() -> BackendsList = [ @@ -594,6 +620,174 @@ retrieve_mam_pm(Config) -> end, escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). +retrieve_mam_muc(Config) -> + F = fun(Alice, Bob, Kate) -> + AliceUserCfg = escalus_users:get_user_by_name(alice), + RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), + [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], + AllRoomMembers = [Alice, Bob, Kate], + + muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, + {Bob, <<"Sid">>}, + {Kate, <<"Johnny">>}]), + + Body1 = <<"1some simple muc message">>, + Body2 = <<"2another one">>, + Body3 = <<"3third message">>, + muc_helper:send_to_room(RoomCfg, Alice, Body1), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), + muc_helper:send_to_room(RoomCfg, Alice, Body2), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), + muc_helper:send_to_room(RoomCfg, Bob, Body3), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), + + mam_helper:wait_for_room_archive_size(Domain, Room, 3), + + ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, + #{"message" => [{contains, binary_to_list(Body2)}]}], + + ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], + + BackendModule = choose_mam_backend(Config, mam_muc), + maybe_stop_and_unload_module(mod_mam_muc, BackendModule, Config), + + AliceDir = retrieve_all_personal_data(Alice, Config), + BobDir = retrieve_all_personal_data(Bob, Config), + KateDir = retrieve_all_personal_data(Kate, Config), + + validate_personal_data( + AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), + validate_personal_data( + BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), + refute_personal_data(KateDir, "mam_muc"), + + [refute_personal_data(Dir, "mam_pm") || Dir <- [AliceDir, BobDir, KateDir]], + + muc_helper:destroy_room(RoomCfg) + end, + escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). + +retrieve_mam_muc_private_msg(Config) -> + F = fun(Alice, Bob) -> + AliceUserCfg = escalus_users:get_user_by_name(alice), + RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), + [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], + + muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, {Bob, <<"Sid">>}]), + + PMBody = <<"Hi, Bob!">>, + {PrivAddrAlice, _} = send_recieve_muc_private_message( + Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), + + [mam_helper:wait_for_archive_size(User, 1) || User <- [Alice, Bob]], + + PMExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(PMBody)}], + "from" => [{jid, escalus_client:full_jid(Alice)}]}], + PMExpectedItemsBob = [#{"message" => [{contains, binary_to_list(PMBody)}], + "from" => [{jid, PrivAddrAlice}]}], + + MamBackends = choose_mam_backend(Config, mam), + MamMucBackends = choose_mam_backend(Config, mam_muc), + maybe_stop_and_unload_module(mod_mam, MamBackends, Config), + maybe_stop_and_unload_module(mod_mam_muc, MamMucBackends, Config), + + AliceDir = retrieve_all_personal_data(Alice, Config), + BobDir = retrieve_all_personal_data(Bob, Config), + + validate_personal_data( + AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, []), + validate_personal_data( + BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, []), + + refute_personal_data(AliceDir, "mam_muc"), + refute_personal_data(BobDir, "mam_muc"), + + muc_helper:destroy_room(RoomCfg) + end, + escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). + + + +retrieve_mam_muc_store_pm(Config) -> + F = fun(Alice, Bob, Kate) -> + AliceUserCfg = escalus_users:get_user_by_name(alice), + RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), + [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], + AllRoomMembers = [Alice, Bob, Kate], + + muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, + {Bob, <<"Sid">>}, + {Kate, <<"Johnny">>}]), + + Body1 = <<"1some simple muc message">>, + Body2 = <<"2another one">>, + Body3 = <<"3third message">>, + muc_helper:send_to_room(RoomCfg, Alice, Body1), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), + muc_helper:send_to_room(RoomCfg, Alice, Body2), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), + muc_helper:send_to_room(RoomCfg, Bob, Body3), + muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), + + PMBody = <<"4Hi, Bob!">>, + {PrivAddrAlice, PrivAddrBob} = send_recieve_muc_private_message( + Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), + + mam_helper:wait_for_room_archive_size(Domain, Room, 3), + mam_helper:wait_for_archive_size(Kate, 4), + [mam_helper:wait_for_archive_size(User, 5) || User <- [Alice, Bob]], + + MamBackends = choose_mam_backend(Config, mam), + MamMucBackends = choose_mam_backend(Config, mam_muc), + maybe_stop_and_unload_module(mod_mam, MamBackends, Config), + maybe_stop_and_unload_module(mod_mam_muc, MamMucBackends, Config), + + AliceDir = retrieve_all_personal_data(Alice, Config), + BobDir = retrieve_all_personal_data(Bob, Config), + KateDir = retrieve_all_personal_data(Kate, Config), + + ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, + #{"message" => [{contains, binary_to_list(Body2)}]}], + ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], + + validate_personal_data( + AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), + validate_personal_data( + BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), + refute_personal_data(KateDir, "mam_muc"), + + RoomJID = <>, + MsgFromAliceToRoom = #{"message" => [{contains, "[1,2]"}], + "from" => [{jid, PrivAddrAlice}]}, + PMExpectedItemsKate = [#{"message" => [{contains, ""}], + "from" => [{jid, RoomJID}]}, + MsgFromAliceToRoom, MsgFromAliceToRoom, + #{"message" => [{contains, binary_to_list(Body3)}], + "from" => [{jid, PrivAddrBob}]} + ], + PMExpectedItemsAlice = PMExpectedItemsKate ++ + [#{"message" => [{contains, binary_to_list(PMBody)}], + "from" => [{jid, escalus_client:full_jid(Alice)}]}], + MsgFromAlice = #{"message" => [{contains, "[1,2,4]"}], + "from" => [{jid, PrivAddrAlice}]}, + PMExpectedItemsBob = [#{"message" => [{contains, ""}], + "from" => [{jid, RoomJID}]}, + MsgFromAlice, MsgFromAlice, MsgFromAlice, + #{"message" => [{contains, binary_to_list(Body3)}], + "from" => [{jid, PrivAddrBob}]} + ], + SortFn = muc_msg_first(RoomJID), + validate_personal_data( + KateDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsKate, SortFn), + validate_personal_data( + AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, SortFn), + validate_personal_data( + BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, SortFn), + + muc_helper:destroy_room(RoomCfg) + end, + escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). + retrieve_mam_muc_light(Config) -> F = fun(Alice, Bob, Kate) -> RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, [{Bob, member}, {Kate, member}]), @@ -609,10 +803,8 @@ retrieve_mam_muc_light(Config) -> M3 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, Body3, <<"Id3">>), muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M3), - mam_helper:wait_for_room_archive_size(Domain, Room, 4), - ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, #{"message" => [{contains, binary_to_list(Body2)}]}], @@ -1314,17 +1506,20 @@ compare_maps([Key | T], Map1, Map2) -> end. muc_msg_first(MucJid) -> - N = erlang:byte_size(MucJid), + MucJidNormalized = escalus_utils:jid_to_lower(to_binary(MucJid)), + N = erlang:byte_size(MucJidNormalized), fun(#{"from" := JID1}, #{"from" := JID2}) -> - case {JID1, JID2} of - {<>, <>} -> - JID1 =< JID2; - {<>, _} -> + Jid1Normalized = escalus_utils:jid_to_lower(to_binary(JID1)), + Jid2Normalized = escalus_utils:jid_to_lower(to_binary(JID2)), + case {Jid1Normalized, Jid2Normalized} of + {<>, <>} -> + Jid1Normalized =< Jid2Normalized; + {<>, _} -> true; - {_, <>} -> + {_, <>} -> false; {_, _} -> - JID1 =< JID2 + Jid1Normalized =< Jid2Normalized end end. @@ -1492,17 +1687,17 @@ check_list(List) -> choose_mam_backend(Config, mam) -> case proplists:get_value(mam_backend, Config) of - rdbms -> mod_mam_rdbms_arch; - riak -> mod_mam_riak_timed_arch_yz; - cassandra -> [mod_mam_cassandra_arch, mod_mam_cassandra_arch_params]; - elasticsearch -> mod_mam_elasticsearch_arch + rdbms -> [mod_mam_rdbms_arch, mod_mam_rdbms_user, mod_mam_cache_user]; + riak -> mod_mam_riak_timed_arch_yz; + cassandra -> [mod_mam_cassandra_arch, mod_mam_cassandra_arch_params]; + elasticsearch -> mod_mam_elasticsearch_arch end; choose_mam_backend(Config, mam_muc) -> case proplists:get_value(mam_backend, Config) of - rdbms -> mod_mam_muc_rdbms_arch; - riak -> mod_mam_riak_timed_arch_yz; - cassandra -> [mod_mam_muc_cassandra_arch, mod_mam_muc_cassandra_arch_params]; - elasticsearch -> mod_mam_muc_elasticsearch_arch + rdbms -> [mod_mam_muc_rdbms_arch, mod_mam_rdbms_user, mod_mam_cache_user]; + riak -> mod_mam_riak_timed_arch_yz; + cassandra -> [mod_mam_muc_cassandra_arch, mod_mam_muc_cassandra_arch_params]; + elasticsearch -> mod_mam_muc_elasticsearch_arch end. expected_header(mod_roster) -> ["jid", "name", "subscription", @@ -1514,3 +1709,15 @@ given_fresh_muc_room(UserSpec, RoomOpts) -> From = muc_helper:generate_rpc_jid({user, UserSpec}), muc_helper:create_instant_room(<<"localhost">>, RoomName, From, Username, RoomOpts), {ok, RoomName}. + +send_recieve_muc_private_message(Room, Domain, {User1, Nickname1}, {User2, Nickname2}, Text) -> + RoomPrivAddrUser1 = <>, + RoomPrivAddrUser2 = <>, + Msg = escalus_stanza:chat_to(RoomPrivAddrUser2, Text), + escalus:send(User1, Msg), + PMStanza = escalus:wait_for_stanza(User2), + escalus:assert(is_chat_message_from_to, + [RoomPrivAddrUser1, escalus_client:full_jid(User2), Text], PMStanza), + {RoomPrivAddrUser1, RoomPrivAddrUser2}. + + diff --git a/big_tests/tests/mam_SUITE.erl b/big_tests/tests/mam_SUITE.erl index dea1bf8ac36..673c413f0d9 100644 --- a/big_tests/tests/mam_SUITE.erl +++ b/big_tests/tests/mam_SUITE.erl @@ -689,7 +689,7 @@ init_modules(rdbms, muc_all, Config) -> init_module(host(), mod_mam_muc, [{host, muc_domain(Config)}]), Config; init_modules(rdbms_simple, muc_all, Config) -> - init_module(host(), mod_mam_muc_rdbms_arch, [muc, simple]), + init_module(host(), mod_mam_muc_rdbms_arch, [muc, rdbms_simple_opts()]), init_module(host(), mod_mam_rdbms_prefs, [muc]), init_module(host(), mod_mam_rdbms_user, [muc]), init_module(host(), mod_mam_muc, [{host, muc_domain(Config)}]), @@ -750,7 +750,7 @@ init_modules(rdbms, C, Config) -> Config; init_modules(rdbms_simple, C, Config) -> init_module(host(), mod_mam, addin_mam_options(C, Config)), - init_module(host(), mod_mam_rdbms_arch, [pm, simple]), + init_module(host(), mod_mam_rdbms_arch, [pm, rdbms_simple_opts()]), init_module(host(), mod_mam_rdbms_prefs, [pm]), init_module(host(), mod_mam_rdbms_user, [pm]), Config; @@ -815,6 +815,9 @@ init_modules(rdbms_mnesia_cache, C, Config) -> init_module(host(), mod_mam_cache_user, [pm]), Config. +rdbms_simple_opts() -> + [{db_jid_format, mam_jid_rfc}, {db_message_format, mam_message_xml}]. + init_modules_for_muc_light(BackendType, Config) -> dynamic_modules:start(host(), mod_muc_light, [{host, binary_to_list(muc_light_host())}]), Config1 = init_modules(BackendType, muc_all, [{muc_domain, "muclight.@HOST@"} | Config]), @@ -1493,7 +1496,7 @@ muc_querying_for_all_messages_with_jid(Config) -> P = ?config(props, Config), F = fun(Alice, Bob) -> Room = ?config(room, Config), - BWithJID = room_address(Room, nick(Bob)), + BWithJID = room_address(Room, nick(bob)), MucMsgs = ?config(pre_generated_muc_msgs, Config), WithJID = [1 || {_, _, {JID, _, _}, _, _} <- MucMsgs, JID == BWithJID], diff --git a/big_tests/tests/muc_SUITE.erl b/big_tests/tests/muc_SUITE.erl index bb3d1034b5a..578f5f067a6 100644 --- a/big_tests/tests/muc_SUITE.erl +++ b/big_tests/tests/muc_SUITE.erl @@ -379,7 +379,7 @@ init_per_group(G, Config) when G =:= http_auth_no_server; init_per_group(hibernation, Config) -> case mam_helper:backend() of rdbms -> - dynamic_modules:start(domain(), mod_mam_muc_rdbms_arch, [muc, simple]), + dynamic_modules:start(domain(), mod_mam_muc_rdbms_arch, [muc]), dynamic_modules:start(domain(), mod_mam_rdbms_prefs, [muc]), dynamic_modules:start(domain(), mod_mam_rdbms_user, [muc]), dynamic_modules:start(domain(), mod_mam_muc, [{host, "muc.@HOST@"}]); diff --git a/big_tests/tests/muc_helper.erl b/big_tests/tests/muc_helper.erl index cda33261726..df61eaf195c 100644 --- a/big_tests/tests/muc_helper.erl +++ b/big_tests/tests/muc_helper.erl @@ -70,7 +70,62 @@ muc_host() -> start_room(Config, User, Room, Nick, Opts) -> From = generate_rpc_jid(User), create_instant_room(<<"localhost">>, Room, From, Nick, Opts), - [{nick, Nick}, {room, Room} | Config]. + RoomJID = room_address(Room), + [{nick, Nick}, {room, Room}, {room_jid, RoomJID}, {muc_host, muc_host()} | Config]. + +start_fresh_room(Config, User, Nick, Opts) -> + Room = fresh_room_name(), + start_room(Config, User, Room, Nick, Opts). + +enter_room(Config, UsersAndNicks) -> + [Room, RoomJid] = [proplists:get_value(Key, Config) || Key <- [room, room_jid]], + lists:foldl(fun({User, Nick}, Acc) -> + escalus:send(User, stanza_muc_enter_room(Room, Nick)), + wait_for_presence(RoomJid, User, length(Acc)), + foreach_recipient([User | Acc], + fun(Stanza) -> + validate_presence(Stanza, + RoomJid, + Nick) + end), + Subject = escalus:wait_for_stanza(User), + validate_subject_message(Subject, RoomJid), + [User | Acc] + end, + [],UsersAndNicks). + +wait_for_presence(_, _, 0) -> + ok; +wait_for_presence(RoomJid, User, N) -> + Stanza = escalus:wait_for_stanza(User), + validate_presence(Stanza, RoomJid), + wait_for_presence(RoomJid, User, N - 1). + +validate_presence(Stanza, RoomJid) -> + escalus:assert(is_presence, [], Stanza), + [RoomJid, _] = binary:split(exml_query:attr(Stanza, <<"from">>), <<"/">>). + +validate_presence(Stanza, RoomJid, Nick) -> + [RoomJid, Nick] = validate_presence(Stanza, RoomJid). + +validate_subject_message(Stanza, RoomJid) -> + RoomJid = exml_query:attr(Stanza, <<"from">>), + #xmlel{} = exml_query:subelement(Stanza, <<"subject">>). + +verify_message_received(Config, Users, Nick, TextBody) -> + RoomJid = proplists:get_value(room_jid, Config), + foreach_recipient(Users, muc_msg_verify(RoomJid, Nick, TextBody)). + +muc_msg_verify(RoomBareJID, NickName, MsgText) -> + fun(Msg) -> + escalus:assert(is_groupchat_message, [MsgText], Msg), + [RoomBareJID, NickName] = binary:split(exml_query:attr(Msg, <<"from">>), <<"/">>) + end. + +send_to_room(RoomCfg, User, TextBody) -> + RoomJid = proplists:get_value(room_jid, RoomCfg), + Stanza = escalus_stanza:groupchat_to(RoomJid, TextBody), + escalus:send(User, Stanza). generate_rpc_jid({_,User}) -> {username, Username} = lists:keyfind(username, 1, User), diff --git a/big_tests/tests/rest_helper.erl b/big_tests/tests/rest_helper.erl index e5dd7d9987f..4e5222e15c2 100644 --- a/big_tests/tests/rest_helper.erl +++ b/big_tests/tests/rest_helper.erl @@ -274,7 +274,7 @@ to_list(V) when is_list(V) -> V. maybe_enable_mam(rdbms, Host, Config) -> - init_module(Host, mod_mam_rdbms_arch, [muc, pm, simple]), + init_module(Host, mod_mam_rdbms_arch, [muc, pm]), init_module(Host, mod_mam_rdbms_prefs, [muc, pm]), init_module(Host, mod_mam_rdbms_user, [muc, pm]), init_module(Host, mod_mam, []), diff --git a/priv/cassandra.cql b/priv/cassandra.cql index 5a38b83119b..6de16c2b0d3 100644 --- a/priv/cassandra.cql +++ b/priv/cassandra.cql @@ -26,6 +26,10 @@ CREATE TABLE mam_message_offset( CREATE TABLE mam_muc_message( id bigint, room_jid varchar, + // One of: + // - Sender JID (if with_nick is empty) + // - empty + from_jid varchar, nick_name varchar, // One of: // - nick_name @@ -53,4 +57,6 @@ CREATE TABLE mam_config( CREATE INDEX ON mongooseim.mam_message (user_jid); CREATE INDEX ON mongooseim.mam_muc_message (room_jid); +CREATE INDEX ON mongooseim.mam_muc_message (from_jid); + diff --git a/priv/elasticsearch/muc.json b/priv/elasticsearch/muc.json index a7ffac89d18..548759e8c61 100644 --- a/priv/elasticsearch/muc.json +++ b/priv/elasticsearch/muc.json @@ -8,6 +8,9 @@ "room": { "type": "keyword" }, + "from_jid" : { + "type": "keyword" + }, "source_jid": { "type": "keyword" }, diff --git a/rel/files/mongooseim.cfg b/rel/files/mongooseim.cfg index 181099090e4..06d73eb1392 100755 --- a/rel/files/mongooseim.cfg +++ b/rel/files/mongooseim.cfg @@ -664,7 +664,8 @@ {services, [ {service_admin_extra, [{submods, [node, accounts, sessions, vcard, gdpr, - roster, last, private, stanza, stats]}]} + roster, last, private, stanza, stats]}]}, + {service_cache, []} ] }. diff --git a/src/admin_extra/service_admin_extra.erl b/src/admin_extra/service_admin_extra.erl index 5a3040286bc..e07e1f55e17 100644 --- a/src/admin_extra/service_admin_extra.erl +++ b/src/admin_extra/service_admin_extra.erl @@ -29,7 +29,7 @@ -behaviour(mongoose_service). --export([start/1, stop/0]). +-export([start/1, stop/0, deps/0]). -define(SUBMODS, [node, accounts, sessions, vcard, roster, last, private, stanza, stats, gdpr @@ -40,6 +40,8 @@ %%% gen_mod %%% +deps() -> [service_cache]. + start(Opts) -> Submods = gen_mod:get_opt(submods, Opts, ?SUBMODS), lists:foreach(fun(Submod) -> diff --git a/src/mam/mod_mam_meta.erl b/src/mam/mod_mam_meta.erl index 16c9b3cb304..ff1a49e7ba5 100644 --- a/src/mam/mod_mam_meta.erl +++ b/src/mam/mod_mam_meta.erl @@ -102,25 +102,24 @@ handle_nested_opts(Key, RootOpts, Default, Deps) -> -spec parse_opts(Type :: pm | muc, Opts :: proplists:proplist(), deps()) -> deps(). parse_opts(Type, Opts, Deps) -> CoreMod = mam_type_to_core_mod(Type), - - CoreModOpts = - lists:filtermap( - fun(Key) -> - case proplists:lookup(Key, Opts) of - none -> false; - Opt -> {true, Opt} - end - end, valid_core_mod_opts(CoreMod)), - + CoreModOpts = filter_opts(Opts, valid_core_mod_opts(CoreMod)), WithCoreDeps = add_dep(CoreMod, CoreModOpts, Deps), Backend = proplists:get_value(backend, Opts, rdbms), - parse_backend_opts(Backend, Type, Opts, WithCoreDeps). -spec mam_type_to_core_mod(atom()) -> module(). mam_type_to_core_mod(pm) -> mod_mam; mam_type_to_core_mod(muc) -> mod_mam_muc. +filter_opts(Opts, ValidOpts) -> + lists:filtermap( + fun(Key) -> + case proplists:lookup(Key, Opts) of + none -> false; + Opt -> {true, Opt} + end + end, ValidOpts). + -spec valid_core_mod_opts(module()) -> [atom()]. valid_core_mod_opts(mod_mam) -> [ @@ -152,7 +151,8 @@ parse_backend_opts(cassandra, Type, Opts, Deps0) -> muc -> mod_mam_muc_cassandra_arch end, - Deps = add_dep(ModArch, Deps0), + Opts1 = filter_opts(Opts, [db_message_format, pool_name, simple]), + Deps = add_dep(ModArch, Opts1, Deps0), case proplists:get_value(user_prefs_store, Opts, false) of cassandra -> add_dep(mod_mam_cassandra_prefs, [Type], Deps); @@ -161,7 +161,8 @@ parse_backend_opts(cassandra, Type, Opts, Deps0) -> end; parse_backend_opts(riak, Type, Opts, Deps0) -> - Deps = add_dep(mod_mam_riak_timed_arch_yz, [Type], Deps0), + Opts1 = filter_opts(Opts, [db_message_format]), + Deps = add_dep(mod_mam_riak_timed_arch_yz, [Type | Opts1], Deps0), case proplists:get_value(user_prefs_store, Opts, false) of mnesia -> add_dep(mod_mam_mnesia_prefs, [Type], Deps); @@ -181,25 +182,17 @@ parse_backend_opts(rdbms, Type, Opts0, Deps0) -> Deps = add_dep(mod_mam_rdbms_user, [Type], Deps1), lists:foldl( - pa:bind(fun parse_backend_opt/5, Type, ModRDBMSArch, ModAsyncWriter), + pa:bind(fun parse_rdbms_opt/5, Type, ModRDBMSArch, ModAsyncWriter), Deps, Opts); parse_backend_opts(elasticsearch, Type, Opts, Deps0) -> - ExtraOpts = - case proplists:get_value(elasticsearch_index_name, Opts) of - IndexName when is_binary(IndexName) -> - [{index_name, IndexName}]; - _ -> - [] - end, - ModArch = case Type of pm -> mod_mam_elasticsearch_arch; muc -> mod_mam_muc_elasticsearch_arch end, - Deps = add_dep(ModArch, ExtraOpts, Deps0), + Deps = add_dep(ModArch, Deps0), case proplists:get_value(user_prefs_store, Opts, false) of mnesia -> add_dep(mod_mam_mnesia_prefs, [Type], Deps); @@ -219,7 +212,7 @@ add_dep(Dep, Deps) -> -spec add_dep(Dep :: module(), Args :: proplists:proplist(), deps()) -> deps(). add_dep(Dep, Args, Deps) -> PrevArgs = maps:get(Dep, Deps, []), - NewArgs = Args ++ PrevArgs, + NewArgs = lists:usort(Args ++ PrevArgs), maps:put(Dep, NewArgs, Deps). @@ -236,9 +229,9 @@ add_default_rdbms_opts(Opts) -> [{cache_users, true}, {async_writer, true}]). --spec parse_backend_opt(Type :: pm | muc, module(), module(), +-spec parse_rdbms_opt(Type :: pm | muc, module(), module(), Option :: {module(), term()}, deps()) -> deps(). -parse_backend_opt(Type, ModRDBMSArch, ModAsyncWriter, Option, Deps) -> +parse_rdbms_opt(Type, ModRDBMSArch, ModAsyncWriter, Option, Deps) -> case Option of {cache_users, true} -> add_dep(mod_mam_cache_user, [Type], Deps); diff --git a/src/mam/mod_mam_muc.erl b/src/mam/mod_mam_muc.erl index 434265418c3..2bddb2b3246 100644 --- a/src/mam/mod_mam_muc.erl +++ b/src/mam/mod_mam_muc.erl @@ -242,7 +242,7 @@ archive_room_packet(Packet, FromNick, FromJID=#jid{}, RoomJID=#jid{}, Role, Affi MessID = generate_message_id(), Packet1 = replace_x_user_element(FromJID, Role, Affiliation, Packet), Result = archive_message(Host, MessID, ArcID, - RoomJID, SrcJID, SrcJID, incoming, Packet1), + RoomJID, FromJID, SrcJID, incoming, Packet1), %% Packet2 goes to archive, Packet to other users case Result of ok -> diff --git a/src/mam/mod_mam_muc_cassandra_arch.erl b/src/mam/mod_mam_muc_cassandra_arch.erl index 2b9d3b961ee..48fa806bbd2 100644 --- a/src/mam/mod_mam_muc_cassandra_arch.erl +++ b/src/mam/mod_mam_muc_cassandra_arch.erl @@ -52,6 +52,7 @@ -record(mam_muc_message, { id :: non_neg_integer(), room_jid :: binary(), + from_jid :: binary() | undefined, nick_name :: binary(), with_nick :: binary(), message :: binary() | undefined @@ -152,31 +153,33 @@ archive_size(Size, Host, _RoomID, RoomJID) when is_integer(Size) -> insert_query_cql() -> "INSERT INTO mam_muc_message " - "(id, room_jid, nick_name, with_nick, message) " - "VALUES (?, ?, ?, ?, ?)". + "(id, room_jid, from_jid, nick_name, with_nick, message) " + "VALUES (?, ?, ?, ?, ?, ?)". archive_message(Result, Host, MessID, _RoomID, - LocJID, NickName, NickName, Dir, Packet) -> + LocJID, FromJID, NickName, Dir, Packet) -> try - archive_message2(Result, Host, MessID, - LocJID, NickName, NickName, Dir, Packet) + archive_message2(Result, Host, MessID, LocJID, + FromJID, NickName, Dir, Packet) catch _Type:Reason -> {error, Reason} end. archive_message2(_Result, _Host, MessID, LocJID = #jid{}, - _RemJID = #jid{}, + FromJID = #jid{}, _SrcJID = #jid{lresource = BNick}, _Dir, Packet) -> BLocJID = mod_mam_utils:bare_jid(LocJID), + BFromJID = mod_mam_utils:bare_jid(FromJID), BPacket = packet_to_stored_binary(Packet), Messages = [#mam_muc_message{ id = MessID, room_jid = BLocJID, + from_jid = BWithFromJID, nick_name = BNick, message = BPacket, with_nick = BWithNick - } || BWithNick <- [<<>>, BNick]], + } || {BWithNick, BWithFromJID} <- [{<<>>, BFromJID}, {BNick, <<>>}]], PoolName = pool_name(LocJID), write_messages(PoolName, Messages). @@ -188,12 +191,13 @@ write_messages(RoomJID, Messages) -> message_to_params(#mam_muc_message{ id = MessID, room_jid = BLocJID, + from_jid = BFromJID, nick_name = BNick, with_nick = BWithNick, message = BPacket }) -> - #{id => MessID, room_jid => BLocJID, nick_name => BNick, - with_nick => BWithNick, message => BPacket}. + #{id => MessID, room_jid => BLocJID, from_jid => BFromJID, + nick_name => BNick, with_nick => BWithNick, message => BPacket}. %% ---------------------------------------------------------------------- @@ -546,10 +550,9 @@ get_mam_muc_gdpr_data(Username, Host) -> Jid = jid:make({LUser, LServer, <<>>}), BinJid = jid:to_binary(Jid), PoolName = mod_mam_muc_cassandra_arch_params:pool_name(), - FilterMap = #{nick_name => BinJid}, + FilterMap = #{from_jid => BinJid}, Rows = fetch_user_messages(PoolName, Jid, FilterMap), - RemoveDups = [Row || Row = #{with_nick := J, nick_name := J} <- Rows], - Messages = [{Id, exml:to_binary(stored_binary_to_packet(Data))} || #{message := Data, id:= Id} <- RemoveDups], + Messages = [{Id, exml:to_binary(stored_binary_to_packet(Data))} || #{message := Data, id:= Id} <- Rows], {ok, Messages}. @@ -590,7 +593,7 @@ extract_messages(PoolName, RoomJID, _Host, Filter, IMax, true) -> fetch_user_messages(PoolName, UserJID, FilterMap) -> QueryName = fetch_user_messages_query, {ok, Rows} = mongoose_cassandra:cql_read(PoolName, UserJID, ?MODULE, QueryName, FilterMap), - lists:reverse(Rows). + lists:sort(Rows). %% @doc Calculate a zero-based index of the row with UID in the result test. @@ -849,14 +852,11 @@ extract_messages_r_cql(Filter) -> "WHERE room_jid = ? AND with_nick = ? " ++ Filter ++ " ORDER BY id DESC LIMIT ?". -%% Be careful. Super inefficient because of full scan. -%% Cannot even set where clause on "with_nick" field because of error: -%% 'Partition key parts: room_jid must be restricted as other parts are'. Hence needs to change the schema. -%% So... the results are TWICE much bigger (for each message there are two copies) -%% and filtering must be done on Erlang level. fetch_user_messages_cql() -> - "SELECT id, nick_name, with_nick, message FROM mam_muc_message " - "WHERE nick_name = ? ALLOW FILTERING". + %% attempt to order results in the next error: + %% "ORDER BY with 2ndary indexes is not supported." + "SELECT id, message FROM mam_muc_message " + "WHERE from_jid = ?". calc_count_cql(Filter) -> "SELECT COUNT(*) FROM mam_muc_message " @@ -898,7 +898,7 @@ expand_simple_param(Params) -> end, Params). simple_params() -> - [{db_message_format, mam_muc_message_xml}]. + [{db_message_format, mam_message_xml}]. params_helper(Params) -> binary_to_list(iolist_to_binary(io_lib:format( diff --git a/src/mam/mod_mam_muc_elasticsearch_arch.erl b/src/mam/mod_mam_muc_elasticsearch_arch.erl index 3f0fea32ff8..a7e3a1e8a9c 100644 --- a/src/mam/mod_mam_muc_elasticsearch_arch.erl +++ b/src/mam/mod_mam_muc_elasticsearch_arch.erl @@ -31,6 +31,9 @@ -export([remove_archive/4]). -export([archive_size/4]). +%gdpr +-export([get_mam_muc_gdpr_data/2]). + -include("mongoose.hrl"). -include("mongoose_rsm.hrl"). -include("mod_mam.hrl"). @@ -56,12 +59,29 @@ stop(Host) -> %%------------------------------------------------------------------- %% ejabberd_gen_mam_archive callbacks %%------------------------------------------------------------------- +-spec get_mam_muc_gdpr_data(jid:username(), jid:server()) -> + {ok, ejabberd_gen_mam_archive:mam_muc_gdpr_data()}. +get_mam_muc_gdpr_data(User, Host) -> + Source = jid:make(User, Host, <<"">>), + BinSource = mod_mam_utils:bare_jid(Source), + Filter = #{term => #{from_jid => BinSource}}, + Sorting = #{mam_id => #{order => asc}}, + SearchQuery = #{query => #{bool => #{filter => Filter}}, + sort => Sorting}, + case mongoose_elasticsearch:search(?INDEX_NAME, ?TYPE_NAME, SearchQuery) of + {ok, #{<<"hits">> := #{<<"hits">> := Hits}}} -> + Messages = lists:map(fun hit_to_gdpr_mam_message/1, Hits), + {ok, Messages}; + {error, _} -> + {ok, []} + end. -archive_message(_Result, Host, MessageId, _UserId, RoomJid, _SourceJid, SourceJid, _Dir, Packet) -> +archive_message(_Result, Host, MessageId, _UserId, RoomJid, FromJID, SourceJid, _Dir, Packet) -> Room = mod_mam_utils:bare_jid(RoomJid), SourceBinJid = mod_mam_utils:full_jid(SourceJid), + From = mod_mam_utils:bare_jid(FromJID), DocId = make_document_id(Room, MessageId), - Doc = make_document(MessageId, Room, SourceBinJid, Packet), + Doc = make_document(MessageId, Room, SourceBinJid, Packet, From), case mongoose_elasticsearch:insert_document(?INDEX_NAME, ?TYPE_NAME, DocId, Doc) of {ok, _} -> ok; @@ -144,10 +164,11 @@ hooks(Host) -> make_document_id(Room, MessageId) -> <>. --spec make_document(mod_mam:message_id(), binary(), binary(), exml:element()) -> - map(). -make_document(MessageId, Room, SourceBinJid, Packet) -> +-spec make_document(mod_mam:message_id(), binary(), binary(), exml:element(), + binary()) -> map(). +make_document(MessageId, Room, SourceBinJid, Packet, FromJID) -> #{mam_id => MessageId, + from_jid => FromJID, room => Room, source_jid => SourceBinJid, message => exml:to_binary(Packet), @@ -257,6 +278,11 @@ hit_to_mam_message(#{<<"_source">> := JSON}) -> {ok, Stanza} = exml:parse(Packet), {MessageId, jid:from_binary(SourceJid), Stanza}. +hit_to_gdpr_mam_message(#{<<"_source">> := JSON}) -> + MessageId = maps:get(<<"mam_id">>, JSON), + Packet = maps:get(<<"message">>, JSON), + {integer_to_binary(MessageId), Packet}. + %% Usage of RSM affects the `"total"' value returned by ElasticSearch. Per RSM spec, the count %% returned by the query should represent the size of the whole result set, which in case of MAM %% is bound only by the MAM filters. diff --git a/src/mam/mod_mam_rdbms_arch.erl b/src/mam/mod_mam_rdbms_arch.erl index 9d846553409..407c5048453 100644 --- a/src/mam/mod_mam_rdbms_arch.erl +++ b/src/mam/mod_mam_rdbms_arch.erl @@ -20,6 +20,7 @@ -export([archive_size/4, archive_message/9, + archive_message_muc/9, lookup_messages/3, remove_archive/4]). @@ -82,6 +83,8 @@ start(Host, Opts) -> end, case gen_mod:get_module_opt(Host, ?MODULE, muc, false) of true -> + ?ERROR_MSG("muc option is deprecated for mod_mam_rdbms_arch backend, " + "mod_mam_muc_rdbms_arch should be used instead",[]), start_muc(Host, Opts); false -> ok @@ -162,7 +165,7 @@ start_muc(Host, _Opts) -> true -> ok; false -> - ejabberd_hooks:add(mam_muc_archive_message, Host, ?MODULE, archive_message, 50) + ejabberd_hooks:add(mam_muc_archive_message, Host, ?MODULE, archive_message_muc, 50) end, ejabberd_hooks:add(mam_muc_archive_size, Host, ?MODULE, archive_size, 50), ejabberd_hooks:add(mam_muc_lookup_messages, Host, ?MODULE, lookup_messages, 50), @@ -176,7 +179,7 @@ stop_muc(Host) -> true -> ok; false -> - ejabberd_hooks:delete(mam_muc_archive_message, Host, ?MODULE, archive_message, 50) + ejabberd_hooks:delete(mam_muc_archive_message, Host, ?MODULE, archive_message_muc, 50) end, ejabberd_hooks:delete(mam_muc_archive_size, Host, ?MODULE, archive_size, 50), ejabberd_hooks:delete(mam_muc_lookup_messages, Host, ?MODULE, lookup_messages, 50), @@ -208,6 +211,14 @@ index_hint_sql(Host) -> end. +-spec archive_message_muc(_Result, Host :: jid:server(), + MessID :: mod_mam:message_id(), UserID :: mod_mam:archive_id(), + LocJID :: jid:jid(), RemJID :: jid:jid(), + SrcJID :: jid:jid(), Dir :: atom(), Packet :: any()) -> ok. +archive_message_muc(Result, Host, MessID, UserID, LocJID, _RemJID, SrcJID, Dir, Packet) -> + archive_message(Result, Host, MessID, UserID, LocJID, SrcJID, SrcJID, Dir, Packet). + + -spec archive_message(_Result, Host :: jid:server(), MessID :: mod_mam:message_id(), UserID :: mod_mam:archive_id(), LocJID :: jid:jid(), RemJID :: jid:jid(), diff --git a/src/mam/mod_mam_riak_timed_arch_yz.erl b/src/mam/mod_mam_riak_timed_arch_yz.erl index 03c16dde5b7..b2522c03079 100644 --- a/src/mam/mod_mam_riak_timed_arch_yz.erl +++ b/src/mam/mod_mam_riak_timed_arch_yz.erl @@ -132,8 +132,8 @@ archive_message(_Result, Host, MessId, _UserID, LocJID, RemJID, SrcJID, _Dir, Pa {error, Reason} end. -archive_message_muc(_Result, Host, MessId, _UserID, LocJID, RemJID, SrcJID, _Dir, Packet) -> - RemJIDMuc = maybe_muc_jid(RemJID), +archive_message_muc(_Result, Host, MessId, _UserID, LocJID, _FromJID, SrcJID, _Dir, Packet) -> + RemJIDMuc = maybe_muc_jid(SrcJID), try archive_message(Host, MessId, LocJID, RemJIDMuc, SrcJID, Packet, muc) catch _Type:Reason -> diff --git a/src/mongoose_lib.erl b/src/mongoose_lib.erl index 144abb48cfe..f524a2ed0b2 100644 --- a/src/mongoose_lib.erl +++ b/src/mongoose_lib.erl @@ -17,6 +17,11 @@ %% WARNING! For simplicity, this function searches only MongooseIM code dir -spec find_behaviour_implementations(Behaviour :: module()) -> [module()]. find_behaviour_implementations(Behaviour) -> + LookupFN = fun() -> {ok, find_implementations(Behaviour)} end, + {ok, Modules} = service_cache:lookup({behaviour, Behaviour}, LookupFN), + Modules. + +find_implementations(Behaviour) -> {ok, EbinFiles} = file:list_dir(code:lib_dir(mongooseim, ebin)), Mods = [ list_to_atom(filename:rootname(File)) || File <- EbinFiles, filename:extension(File) == ".beam" ], diff --git a/src/service_cache.erl b/src/service_cache.erl new file mode 100644 index 00000000000..ff1b1e325b2 --- /dev/null +++ b/src/service_cache.erl @@ -0,0 +1,33 @@ +%%%------------------------------------------------------------------- +%%% @author denys.gonchar@erlang-solutions.com +%%% @copyright (C) 2019, Erlang Solutions +%%% @doc +%%% +%%% @end +%%% Created : 28. May 2019 17:23 +%%%------------------------------------------------------------------- +-module(service_cache). + +-behaviour(mongoose_service). + +%% API +-export([start/1, stop/0]). +-export([lookup/2]). + +-type lookup_result() :: {ok, Value :: term()} | error. +-type lookup_fn() :: fun(()-> lookup_result()). + +-export_type([lookup_fn/0, lookup_result/0]). + +start(Opts) -> cache_tab:new(?MODULE, Opts). +stop() -> cache_tab:delete(?MODULE). + + +-spec lookup(Key :: term(), lookup_fn()) -> lookup_result(). +lookup(Key, Fun) -> + case mongoose_service:is_loaded(?MODULE) of + true -> + cache_tab:lookup(?MODULE, Key, Fun); + false -> + Fun() + end. \ No newline at end of file diff --git a/test/mam_jid_mini_SUITE.erl b/test/mam_jid_mini_SUITE.erl index 94b1493bb47..a61981ddb67 100644 --- a/test/mam_jid_mini_SUITE.erl +++ b/test/mam_jid_mini_SUITE.erl @@ -16,6 +16,8 @@ init_per_suite(Config) -> {skip,nif_not_loaded} end. +end_per_suite(Config) -> Config. + test_encode_decode_functionality(_Config) -> PossibleDomainNames = [<<"a">>, <<"b">>, <<"c">>, <<"d">>, <<"e">>, <<"f">>], PossibleUserNames = [<<"">> | PossibleDomainNames], diff --git a/test/mod_mam_meta_SUITE.erl b/test/mod_mam_meta_SUITE.erl index 2b4cf3bf0c2..01c6fb32c23 100644 --- a/test/mod_mam_meta_SUITE.erl +++ b/test/mod_mam_meta_SUITE.erl @@ -98,11 +98,17 @@ produces_valid_configurations(_Config) -> handles_riak_config(_Config) -> - Deps = deps([{backend, riak}, {pm, [{user_prefs_store, mnesia}]}, {muc, []}]), + Deps = deps([ + {backend, riak}, + {db_message_format, some_format}, + {pm, [{user_prefs_store, mnesia}]}, + {muc, []} + ]), ?assert(lists:keymember(mod_mam, 1, Deps)), ?assert(lists:keymember(mod_mam_muc, 1, Deps)), check_has_args(mod_mam_riak_timed_arch_yz, [pm, muc], Deps), + check_has_args(mod_mam_riak_timed_arch_yz, [{db_message_format, some_format}], Deps), check_has_args(mod_mam_mnesia_prefs, [pm], Deps), check_has_no_args(mod_mam_mnesia_prefs, [muc], Deps). @@ -110,14 +116,17 @@ handles_riak_config(_Config) -> handles_cassandra_config(_Config) -> Deps = deps([ {backend, cassandra}, - {pm, [{user_prefs_store, cassandra}]}, - {muc, [{user_prefs_store, mnesia}]} + simple, + {pm, [{user_prefs_store, cassandra}, {db_message_format, some_format}]}, + {muc, [{user_prefs_store, mnesia}, {pool_name, some_poolname}]} ]), - ?assert(lists:keymember(mod_mam_cassandra_arch, 1, Deps)), - ?assert(lists:keymember(mod_mam_muc_cassandra_arch, 1, Deps)), check_has_args(mod_mam_mnesia_prefs, [muc], Deps), - check_has_args(mod_mam_cassandra_prefs, [pm], Deps). + check_has_args(mod_mam_cassandra_prefs, [pm], Deps), + check_has_args(mod_mam_cassandra_arch, [{db_message_format, some_format}, {simple, true}], Deps), + check_has_args(mod_mam_muc_cassandra_arch, [{pool_name, some_poolname}, {simple, true}], Deps), + check_has_no_args(mod_mam_cassandra_arch, [{pool_name, some_poolname}], Deps), + check_has_no_args(mod_mam_muc_cassandra_arch, [{db_message_format, some_format}], Deps). example_muc_only_no_pref_good_performance(_Config) -> diff --git a/test/roster_SUITE.erl b/test/roster_SUITE.erl index 27cb2757806..c87dfc36ad5 100644 --- a/test/roster_SUITE.erl +++ b/test/roster_SUITE.erl @@ -30,7 +30,6 @@ all() -> [ ]. init_per_suite(C) -> - init_ets(), ok = mnesia:create_schema([node()]), ok = mnesia:start(), ok = stringprep:start(), @@ -55,6 +54,7 @@ init_per_testcase(_TC, C) -> end_per_testcase(_TC, C) -> mod_roster:remove_user(a(), host()), gen_mod:stop_module(host(), mod_roster), + delete_ets(), meck:unload(gen_iq_handler), C. @@ -158,6 +158,12 @@ assert_state_old(Subscription, Ask) -> init_ets() -> catch ets:new(local_config, [named_table]), + catch ets:new(mongoose_services, [named_table]), + ok. + +delete_ets() -> + catch ets:delete(local_config), + catch ets:delete(mongoose_services), ok. a() -> <<"alice">>.