1: -module(domain_removal_SUITE). 2: 3: -compile([export_all, nowarn_export_all]). 4: 5: -import(distributed_helper, [mim/0, rpc/4, subhost_pattern/1]). 6: -import(domain_helper, [host_type/0, domain_to_host_type/2, domain/0]). 7: -import(config_parser_helper, [mod_config/2]). 8: 9: -include("mam_helper.hrl"). 10: -include_lib("eunit/include/eunit.hrl"). 11: -include_lib("exml/include/exml_stream.hrl"). 12: -include_lib("jid/include/jid.hrl"). 13: -include_lib("common_test/include/ct.hrl"). 14: 15: all() -> 16: [ 17: {group, auth_removal}, 18: {group, cache_removal}, 19: {group, mam_removal}, 20: {group, inbox_removal}, 21: {group, muc_light_removal}, 22: {group, muc_removal}, 23: {group, private_removal}, 24: {group, roster_removal}, 25: {group, offline_removal}, 26: {group, markers_removal}, 27: {group, vcard_removal}, 28: {group, last_removal} 29: ]. 30: 31: groups() -> 32: [ 33: {auth_removal, [], [auth_removal]}, 34: {cache_removal, [], [cache_removal]}, 35: {mam_removal, [], [mam_pm_removal, 36: mam_muc_removal]}, 37: {inbox_removal, [], [inbox_removal]}, 38: {muc_light_removal, [], [muc_light_removal, 39: muc_light_blocking_removal]}, 40: {muc_removal, [], [muc_removal]}, 41: {private_removal, [], [private_removal]}, 42: {roster_removal, [], [roster_removal]}, 43: {offline_removal, [], [offline_removal]}, 44: {markers_removal, [], [markers_removal]}, 45: {vcard_removal, [], [vcard_removal]}, 46: {last_removal, [], [last_removal]} 47: ]. 48: 49: %%%=================================================================== 50: %%% Overall setup/teardown 51: %%%=================================================================== 52: init_per_suite(Config) -> 53: escalus:init_per_suite(Config). 54: 55: end_per_suite(Config) -> 56: escalus_fresh:clean(), 57: escalus:end_per_suite(Config). 58: 59: %%%=================================================================== 60: %%% Group specific setup/teardown 61: %%%=================================================================== 62: init_per_group(Group, Config) -> 63: case mongoose_helper:is_rdbms_enabled(host_type()) of 64: true -> 65: HostTypes = domain_helper:host_types(), 66: Config2 = dynamic_modules:save_modules(HostTypes, Config), 67: [dynamic_modules:ensure_modules(HostType, group_to_modules(Group)) || 68: HostType <- HostTypes], 69: Config2; 70: false -> 71: {skip, require_rdbms} 72: end. 73: 74: end_per_group(_Groupname, Config) -> 75: case mongoose_helper:is_rdbms_enabled(host_type()) of 76: true -> 77: dynamic_modules:restore_modules(Config); 78: false -> 79: ok 80: end, 81: ok. 82: 83: group_to_modules(auth_removal) -> 84: []; 85: group_to_modules(cache_removal) -> 86: [{mod_cache_users, config_parser_helper:default_mod_config(mod_cache_users)}, 87: {mod_mam_meta, mam_helper:config_opts(#{pm => #{}})}]; 88: group_to_modules(mam_removal) -> 89: MucHost = subhost_pattern(muc_light_helper:muc_host_pattern()), 90: [{mod_mam_meta, mam_helper:config_opts(#{pm => #{}, muc => #{host => MucHost}})}, 91: {mod_muc_light, mod_config(mod_muc_light, #{backend => rdbms})}]; 92: group_to_modules(muc_light_removal) -> 93: [{mod_muc_light, mod_config(mod_muc_light, #{backend => rdbms})}]; 94: group_to_modules(muc_removal) -> 95: MucHost = subhost_pattern(muc_helper:muc_host_pattern()), 96: Opts = #{backend => rdbms, host => MucHost}, 97: [{mod_muc, muc_helper:make_opts(Opts)}]; 98: group_to_modules(inbox_removal) -> 99: [{mod_inbox, inbox_helper:inbox_opts()}]; 100: group_to_modules(private_removal) -> 101: [{mod_private, #{iqdisc => one_queue, backend => rdbms}}]; 102: group_to_modules(roster_removal) -> 103: [{mod_roster, mod_config(mod_roster, #{backend => rdbms})}]; 104: group_to_modules(offline_removal) -> 105: [{mod_offline, mod_config(mod_offline, #{backend => rdbms})}]; 106: group_to_modules(markers_removal) -> 107: [{mod_smart_markers, config_parser_helper:default_mod_config(mod_smart_markers)}]; 108: group_to_modules(vcard_removal) -> 109: [{mod_vcard, mod_config(mod_vcard, #{backend => rdbms})}]; 110: group_to_modules(last_removal) -> 111: [{mod_last, mod_config(mod_last, #{backend => rdbms})}]. 112: 113: %%%=================================================================== 114: %%% Testcase specific setup/teardown 115: %%%=================================================================== 116: 117: init_per_testcase(muc_removal, Config) -> 118: muc_helper:load_muc(), 119: mongoose_helper:ensure_muc_clean(), 120: escalus:init_per_testcase(muc_removal, Config); 121: init_per_testcase(roster_removal, ConfigIn) -> 122: Config = roster_helper:set_versioning(true, true, ConfigIn), 123: escalus:init_per_testcase(roster_removal, Config); 124: init_per_testcase(TestCase, Config) -> 125: escalus:init_per_testcase(TestCase, Config). 126: 127: end_per_testcase(muc_removal, Config) -> 128: mongoose_helper:ensure_muc_clean(), 129: muc_helper:unload_muc(), 130: escalus:end_per_testcase(muc_removal, Config); 131: end_per_testcase(TestCase, Config) -> 132: escalus:end_per_testcase(TestCase, Config). 133: 134: %%%=================================================================== 135: %%% Test Cases 136: %%%=================================================================== 137: 138: auth_removal(Config) -> 139: FreshConfig = escalus_fresh:create_users(Config, [{alice, 1}, {alice_bis, 1}]), 140: AliceSpec = escalus_users:get_userspec(FreshConfig, alice), 141: AliceBisSpec = escalus_users:get_userspec(FreshConfig, alice_bis), 142: connect_and_disconnect(AliceSpec), 143: connect_and_disconnect(AliceBisSpec), 144: ?assertMatch([_Alice], rpc(mim(), ejabberd_auth, get_vh_registered_users, [domain()])), 145: run_remove_domain(), 146: ?assertMatch({error, {connection_step_failed, _, _}}, escalus_connection:start(AliceSpec)), 147: connect_and_disconnect(AliceBisSpec), % different domain - not removed 148: ?assertEqual([], rpc(mim(), ejabberd_auth, get_vh_registered_users, [domain()])). 149: 150: cache_removal(Config) -> 151: FreshConfig = escalus_fresh:create_users(Config, [{alice, 1}, {alice_bis, 1}]), 152: F = fun(Alice, AliceBis) -> 153: escalus:send(Alice, escalus_stanza:chat_to(AliceBis, <<"Hi!">>)), 154: escalus:wait_for_stanza(AliceBis), 155: mam_helper:wait_for_archive_size(Alice, 1), 156: mam_helper:wait_for_archive_size(AliceBis, 1) 157: end, 158: escalus:story(FreshConfig, [{alice, 1}, {alice_bis, 1}], F), 159: %% Storing the message in MAM should have populated the cache for both users 160: ?assertEqual({stop, true}, does_cached_user_exist(FreshConfig, alice)), 161: ?assertEqual({stop, true}, does_cached_user_exist(FreshConfig, alice_bis)), 162: run_remove_domain(), 163: %% Cache removed only for Alice's domain 164: ?assertEqual(false, does_cached_user_exist(FreshConfig, alice)), 165: ?assertEqual({stop, true}, does_cached_user_exist(FreshConfig, alice_bis)). 166: 167: mam_pm_removal(Config) -> 168: F = fun(Alice, Bob) -> 169: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 170: escalus:wait_for_stanza(Bob), 171: mam_helper:wait_for_archive_size(Alice, 1), 172: mam_helper:wait_for_archive_size(Bob, 1), 173: run_remove_domain(), 174: mam_helper:wait_for_archive_size(Alice, 0), 175: mam_helper:wait_for_archive_size(Bob, 0) 176: end, 177: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 178: 179: mam_muc_removal(Config0) -> 180: F = fun(Config, Alice) -> 181: Room = muc_helper:fresh_room_name(), 182: MucHost = muc_light_helper:muc_host(), 183: muc_light_helper:create_room(Room, MucHost, alice, 184: [], Config, muc_light_helper:ver(1)), 185: RoomAddr = <<Room/binary, "@", MucHost/binary>>, 186: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, <<"text">>)), 187: escalus:wait_for_stanza(Alice), 188: mam_helper:wait_for_room_archive_size(MucHost, Room, 1), 189: run_remove_domain(), 190: mam_helper:wait_for_room_archive_size(MucHost, Room, 0) 191: end, 192: escalus_fresh:story_with_config(Config0, [{alice, 1}], F). 193: 194: inbox_removal(Config) -> 195: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 196: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 197: escalus:wait_for_stanza(Bob), 198: inbox_helper:get_inbox(Alice, #{count => 1}), 199: inbox_helper:get_inbox(Bob, #{count => 1}), 200: run_remove_domain(), 201: inbox_helper:get_inbox(Alice, #{count => 0, unread_messages => 0, active_conversations => 0}), 202: inbox_helper:get_inbox(Bob, #{count => 0, unread_messages => 0, active_conversations => 0}) 203: end). 204: 205: muc_removal(Config0) -> 206: muc_helper:story_with_room(Config0, [{persistent, true}], [{alice, 1}], fun(Config, Alice) -> 207: AliceJid= jid:from_binary(escalus_client:full_jid(Alice)), 208: {_, Domain} = jid:to_lus(AliceJid), 209: MucHost = muc_helper:muc_host(), 210: % Alice joins room and registers nick 211: EnterRoom = muc_helper:stanza_muc_enter_room(?config(room, Config), <<"alice">>), 212: escalus:send(Alice, EnterRoom), 213: escalus:wait_for_stanzas(Alice, 2), 214: muc_helper:set_nick(Alice, <<"alice2">>), 215: % check muc tables 216: ?assertMatch([_], get_muc_rooms(MucHost)), 217: ?assertMatch([_], get_muc_room_aff(Domain)), 218: ?assertMatch({ok, _}, get_muc_registered(MucHost, AliceJid)), 219: % remove domain and check muc tables 220: run_remove_domain(), 221: ?assertMatch([], get_muc_rooms(MucHost)), 222: ?assertMatch([], get_muc_room_aff(Domain)), 223: ?assertMatch({error, not_registered}, get_muc_registered(MucHost, AliceJid)) 224: end). 225: 226: muc_light_removal(Config0) -> 227: F = fun(Config, Alice) -> 228: %% GIVEN a room 229: Room = muc_helper:fresh_room_name(), 230: MucHost = muc_light_helper:muc_host(), 231: RoomAddr = <<Room/binary, "@", MucHost/binary>>, 232: muc_light_helper:create_room(Room, MucHost, alice, 233: [], Config, muc_light_helper:ver(1)), 234: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, <<"text">>)), 235: escalus:wait_for_stanza(Alice), 236: RoomID = select_room_id(host_type(), Room, MucHost), 237: {selected, [_]} = select_affs_by_room_id(host_type(), RoomID), 238: {selected, [_|_]} = select_config_by_room_id(host_type(), RoomID), 239: {ok, _RoomConfig, _AffUsers, _Version} = get_room_info(host_type(), Room, MucHost), 240: %% WHEN domain hook called 241: run_remove_domain(), 242: %% THEN Room info not available 243: {error, not_exists} = get_room_info(host_type(), Room, MucHost), 244: %% THEN Tables are empty 245: {selected, []} = select_affs_by_room_id(host_type(), RoomID), 246: {selected, []} = select_config_by_room_id(host_type(), RoomID) 247: end, 248: escalus_fresh:story_with_config(Config0, [{alice, 1}], F). 249: 250: muc_light_blocking_removal(Config0) -> 251: F = fun(Config, Alice, Bob) -> 252: %% GIVEN a room 253: Room = muc_helper:fresh_room_name(), 254: MucHost = muc_light_helper:muc_host(), 255: muc_light_helper:create_room(Room, MucHost, alice, 256: [], Config, muc_light_helper:ver(1)), 257: block_muclight_user(Bob, Alice), 258: [_] = get_blocking(host_type(), Bob, MucHost), 259: %% WHEN domain hook called 260: run_remove_domain(), 261: [] = get_blocking(host_type(), Bob, MucHost) 262: end, 263: escalus_fresh:story_with_config(Config0, [{alice, 1}, {bob, 1}], F). 264: 265: private_removal(Config) -> 266: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 267: NS = <<"alice:private:ns">>, 268: Tag = <<"my_element">>, 269: %% Alice stores some data in her private storage 270: IqSet = escalus_stanza:private_set(my_banana(NS)), 271: IqGet = escalus_stanza:private_get(NS, Tag), 272: escalus:send_iq_and_wait_for_result(Alice, IqSet), 273: %% Compare results before and after removal 274: Res1 = escalus_client:send_iq_and_wait_for_result(Alice, IqGet), 275: run_remove_domain(), 276: Res2 = escalus_client:send_iq_and_wait_for_result(Alice, IqGet), 277: escalus:assert(is_private_result, Res1), 278: escalus:assert(is_private_result, Res2), 279: Val1 = get_private_data(Res1, Tag, NS), 280: Val2 = get_private_data(Res2, Tag, NS), 281: ?assert_equal_extra(<<"banana">>, Val1, #{stanza => Res1}), 282: ?assert_equal_extra(<<>>, Val2, #{stanza => Res2}) 283: end). 284: 285: offline_removal(Config) -> 286: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun(FreshConfig, Alice, Bob) -> 287: mongoose_helper:logout_user(FreshConfig, Bob), 288: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"msgtxt">>)), 289: % wait until message is stored 290: BobJid = jid:from_binary(escalus_client:full_jid(Bob)), 291: {LUser, LServer} = jid:to_lus(BobJid), 292: mongoose_helper:wait_until( 293: fun() -> mongoose_helper:total_offline_messages({LUser, LServer}) end, 1), 294: % check messages in DB 295: ?assertMatch({ok, [_]}, rpc(mim(), mod_offline_rdbms, fetch_messages, [host_type(), BobJid])), 296: run_remove_domain(), 297: ?assertMatch({ok, []}, rpc(mim(), mod_offline_rdbms, fetch_messages, [host_type(), BobJid])) 298: end). 299: 300: markers_removal(Config) -> 301: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 302: Body = <<"Hello Bob!">>, 303: MsgId = escalus_stanza:id(), 304: Msg = escalus_stanza:set_id(escalus_stanza:chat_to(Bob, Body), MsgId), 305: escalus:send(Alice, Msg), 306: escalus:wait_for_stanza(Bob), 307: ChatMarker = escalus_stanza:chat_marker(Alice, <<"displayed">>, MsgId), 308: escalus:send(Bob, ChatMarker), 309: escalus:wait_for_stanza(Alice), 310: mongoose_helper:wait_until( 311: fun() -> 1 =< mongoose_helper:generic_count(mod_smart_markers) end, true), 312: % check messages in DB 313: AliceJid = jid:from_binary(escalus_client:full_jid(Alice)), 314: ?assertMatch([_], rpc(mim(), mod_smart_markers_backend, get_chat_markers, 315: [host_type(), AliceJid, undefined, 0])), 316: run_remove_domain(), 317: ?assertMatch([], rpc(mim(), mod_smart_markers_backend, get_chat_markers, 318: [host_type(), AliceJid, undefined, 0])) 319: end). 320: 321: roster_removal(Config) -> 322: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 323: %% add contact 324: Stanza = escalus_stanza:roster_add_contact(Bob, [<<"friends">>], <<"Bobby">>), 325: escalus:send(Alice, Stanza), 326: Received = escalus:wait_for_stanzas(Alice, 2), 327: escalus:assert_many([is_roster_set, is_iq_result], Received), 328: 329: %% check roster 330: BobJid = escalus_client:short_jid(Bob), 331: Received2 = escalus:send_iq_and_wait_for_result(Alice, escalus_stanza:roster_get()), 332: escalus:assert(is_roster_result, Received2), 333: escalus:assert(roster_contains, [BobJid], Received2), 334: escalus:assert(count_roster_items, [1], Received2), 335: ?assertMatch([_], select_from_roster("rosterusers")), 336: ?assertMatch([_], select_from_roster("rostergroups")), 337: ?assertMatch([_], select_from_roster("roster_version")), 338: 339: %% remove domain and check roster 340: run_remove_domain(), 341: Received3 = escalus:send_iq_and_wait_for_result(Alice, escalus_stanza:roster_get()), 342: escalus:assert(is_roster_result, Received3), 343: escalus:assert(count_roster_items, [0], Received3), 344: ?assertMatch([], select_from_roster("rosterusers")), 345: ?assertMatch([], select_from_roster("rostergroups")), 346: ?assertMatch([], select_from_roster("roster_version")) 347: end). 348: 349: vcard_removal(Config) -> 350: escalus:fresh_story(Config, [{alice, 1}], fun(Client) -> 351: DirJID = <<"vjud.", (domain())/binary>>, 352: {LUser, LServer} = jid:to_lus(jid:from_binary(escalus_client:full_jid(Client))), 353: VCardFields = [{<<"FN">>, <<"Old name">>}], 354: FilterFields = [{<<"fn">>, <<"Old name">>}], 355: DbFilterFields = [{<<"fn">>, [<<"Old name">>]}], 356: %create vcard for alice 357: UpdateResult = escalus:send_and_wait(Client, 358: escalus_stanza:vcard_update(VCardFields)), 359: escalus:assert(is_iq_result, UpdateResult), 360: %check before domain removal 361: RequestResult = escalus:send_and_wait(Client, escalus_stanza:vcard_request()), 362: ?assertMatch(<<"Old name">>, get_vcard_fn(RequestResult)), 363: SearchResult = escalus:send_and_wait(Client, 364: search_vcard_fields(DirJID, FilterFields)), 365: ?assertMatch(<<"1">>, get_vcard_search_query_count(SearchResult)), 366: ?assertMatch({ok, _}, rpc(mim(), mod_vcard_rdbms, get_vcard, 367: [host_type(), LUser, LServer])), 368: ?assertMatch([_], rpc(mim(), mod_vcard_rdbms, search, 369: [host_type(), LServer, DbFilterFields])), 370: %check after domain removal 371: run_remove_domain(), 372: RequestResult2 = escalus:send_and_wait(Client, escalus_stanza:vcard_request()), 373: escalus:assert(is_iq_error, RequestResult2), 374: SearchResult2 = escalus:send_and_wait(Client, 375: search_vcard_fields(DirJID, FilterFields)), 376: ?assertMatch(<<"0">>, get_vcard_search_query_count(SearchResult2)), 377: ?assertMatch({error, _}, rpc(mim(), mod_vcard_rdbms, get_vcard, 378: [host_type(), LUser, LServer])), 379: ?assertMatch([], rpc(mim(), mod_vcard_rdbms, search, 380: [host_type(), LServer, DbFilterFields])) 381: end). 382: 383: last_removal(Config0) -> 384: F = fun(Config2, Alice, Bob) -> 385: escalus_story:make_all_clients_friends([Alice, Bob]), 386: 387: %% Bob logs out with a status 388: Status = escalus_stanza:tags([{<<"status">>, <<"I am a banana!">>}]), 389: Presence = escalus_stanza:presence(<<"unavailable">>, Status), 390: escalus_client:send(Bob, Presence), 391: 392: escalus_client:stop(Config2, Bob), 393: timer:sleep(1024), % more than a second 394: 395: PresUn = escalus_client:wait_for_stanza(Alice), 396: escalus:assert(is_presence_with_type, [<<"unavailable">>], PresUn), 397: 398: %% Alice asks for Bob's last availability 399: BobShortJID = escalus_client:short_jid(Bob), 400: GetLast = escalus_stanza:last_activity(BobShortJID), 401: Stanza = escalus_client:send_iq_and_wait_for_result(Alice, GetLast), 402: 403: %% Alice receives Bob's status and last online time > 0 404: escalus:assert(is_last_result, Stanza), 405: true = (1 =< get_last_activity(Stanza)), 406: <<"I am a banana!">> = get_last_status(Stanza), 407: 408: run_remove_domain(), 409: escalus_client:send(Alice, GetLast), 410: Error = escalus_client:wait_for_stanza(Alice), 411: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error) 412: end, 413: escalus:fresh_story_with_config(Config0, [{alice, 1}, {bob, 1}], F). 414: 415: %% Helpers 416: 417: connect_and_disconnect(Spec) -> 418: {ok, Client, _} = escalus_connection:start(Spec), 419: escalus_connection:stop(Client). 420: 421: does_cached_user_exist(Config, User) -> 422: Jid = #jid{lserver = Domain} = jid:from_binary(escalus_users:get_jid(Config, User)), 423: HostType = domain_to_host_type(mim(), Domain), 424: rpc(mim(), mod_cache_users, does_cached_user_exist, [false, HostType, Jid, stored]). 425: 426: search_vcard_fields(DirJID, Filters) -> 427: escalus_stanza:search_iq(DirJID, escalus_stanza:search_fields(Filters)). 428: 429: get_vcard_fn(Element) -> 430: exml_query:path(Element, [{element, <<"vCard">>}, 431: {element, <<"FN">>}, 432: cdata]). 433: 434: get_vcard_search_query_count(Element) -> 435: exml_query:path(Element, [{element, <<"query">>}, 436: {element, <<"set">>}, 437: {element, <<"count">>}, 438: cdata]). 439: 440: get_muc_registered(MucHost, UserJid) -> 441: rpc(mim(), mod_muc_rdbms, get_nick, [host_type(), MucHost, UserJid]). 442: 443: get_muc_rooms(MucHost) -> 444: {ok, Rooms} = rpc(mim(), mod_muc_rdbms, get_rooms, [host_type(), MucHost]), 445: Rooms. 446: 447: get_muc_room_aff(Domain) -> 448: Query = "SELECT * FROM muc_room_aff WHERE lserver = '" ++ binary_to_list(Domain) ++ "'", 449: {selected, Affs} = rpc(mim(), mongoose_rdbms, sql_query, [host_type(), Query]), 450: Affs. 451: 452: select_from_roster(Table) -> 453: Query = "SELECT * FROM " ++ Table ++ " WHERE server='" ++ binary_to_list(domain()) ++ "'", 454: {selected, Res} = rpc(mim(), mongoose_rdbms, sql_query, [host_type(), Query]), 455: Res. 456: 457: run_remove_domain() -> 458: rpc(mim(), mongoose_hooks, remove_domain, [host_type(), domain()]). 459: 460: get_room_info(HostType, RoomU, RoomS) -> 461: rpc(mim(), mod_muc_light_db_backend, get_info, [HostType, {RoomU, RoomS}]). 462: 463: select_room_id(MainHost, RoomU, RoomS) -> 464: {selected, [{DbRoomID}]} = 465: rpc(mim(), mod_muc_light_db_rdbms, select_room_id, [MainHost, RoomU, RoomS]), 466: rpc(mim(), mongoose_rdbms, result_to_integer, [DbRoomID]). 467: 468: select_affs_by_room_id(MainHost, RoomID) -> 469: rpc(mim(), mod_muc_light_db_rdbms, select_affs_by_room_id, [MainHost, RoomID]). 470: 471: select_config_by_room_id(MainHost, RoomID) -> 472: rpc(mim(), mod_muc_light_db_rdbms, select_config_by_room_id, [MainHost, RoomID]). 473: 474: get_blocking(HostType, User, MUCServer) -> 475: Jid = jid:from_binary(escalus_client:short_jid(User)), 476: {LUser, LServer, _} = jid:to_lower(Jid), 477: rpc(mim(), mod_muc_light_db_rdbms, get_blocking, [HostType, {LUser, LServer}, MUCServer]). 478: 479: block_muclight_user(Bob, Alice) -> 480: %% Bob blocks Alice 481: AliceJIDBin = escalus_client:short_jid(Alice), 482: BlocklistChange = [{user, deny, AliceJIDBin}], 483: escalus:send(Bob, muc_light_helper:stanza_blocking_set(BlocklistChange)), 484: escalus:assert(is_iq_result, escalus:wait_for_stanza(Bob)). 485: 486: my_banana(NS) -> 487: #xmlel{ 488: name = <<"my_element">>, 489: attrs = [{<<"xmlns">>, NS}], 490: children = [#xmlcdata{content = <<"banana">>}]}. 491: 492: get_private_data(Elem, Tag, NS) -> 493: Path = [{element, <<"query">>}, {element_with_ns, Tag, NS}, cdata], 494: exml_query:path(Elem, Path). 495: 496: get_last_activity(Stanza) -> 497: S = exml_query:path(Stanza, [{element, <<"query">>}, {attr, <<"seconds">>}]), 498: list_to_integer(binary_to_list(S)). 499: 500: get_last_status(Stanza) -> 501: exml_query:path(Stanza, [{element, <<"query">>}, cdata]).