1: -module(gdpr_SUITE). 2: 3: %% Tests for features related to GDPR compliance. 4: 5: -include_lib("common_test/include/ct.hrl"). 6: -include_lib("escalus/include/escalus.hrl"). 7: -include_lib("exml/include/exml.hrl"). 8: -include("muc_light.hrl"). 9: 10: -export([suite/0, all/0, groups/0]). 11: -export([init_per_suite/1, end_per_suite/1]). 12: -export([init_per_group/2, end_per_group/2]). 13: -export([init_per_testcase/2, end_per_testcase/2]). 14: -export([ 15: retrieve_vcard/1, 16: remove_vcard/1, 17: remove_private/1, 18: remove_multiple_private_xmls/1, 19: dont_remove_other_user_private_xml/1, 20: retrieve_roster/1, 21: retrieve_mam_pm/1, 22: retrieve_mam_muc/1, 23: retrieve_mam_muc_private_msg/1, 24: retrieve_mam_muc_store_pm/1, 25: remove_mam_pm/1, 26: retrieve_mam_muc_light/1, 27: retrieve_mam_pm_and_muc_light_interfere/1, 28: retrieve_mam_pm_and_muc_light_dont_interfere/1, 29: remove_roster/1, 30: retrieve_offline/1, 31: remove_offline/1, 32: retrieve_pubsub_payloads/1, 33: retrieve_created_pubsub_nodes/1, 34: retrieve_all_pubsub_data/1, 35: dont_retrieve_other_user_pubsub_payload/1, 36: retrieve_pubsub_subscriptions/1, 37: retrieve_private_xml/1, 38: dont_retrieve_other_user_private_xml/1, 39: retrieve_multiple_private_xmls/1, 40: retrieve_inbox/1, 41: remove_inbox/1, 42: retrieve_inbox_for_multiple_messages/1, 43: retrieve_inbox_muclight/1, 44: retrieve_inbox_muc/1, 45: remove_inbox_muclight/1, 46: remove_inbox_muc/1, 47: retrieve_logs/1, 48: remove_pubsub_all_data/1, 49: remove_pubsub_dont_remove_node_when_only_publisher/1, 50: remove_pubsub_subscriptions/1, 51: remove_pubsub_dont_remove_flat_pubsub_node/1, 52: remove_pubsub_push_node/1, 53: remove_pubsub_pep_node/1 54: ]). 55: -export([ 56: data_is_not_retrieved_for_missing_user/1 57: ]). 58: 59: -import(mongooseimctl_helper, [mongooseimctl/3]). 60: -import(distributed_helper, [mim/0, subhost_pattern/1, rpc/4]). 61: -import(muc_light_helper, [room_bin_jid/1]). 62: -import(domain_helper, [host_type/0]). 63: -import(config_parser_helper, [default_mod_config/1, mod_config/2]). 64: 65: -define(ROOM, <<"tt1">>). 66: 67: %% ------------------------------------------------------------- 68: %% Common Test stuff 69: %% ------------------------------------------------------------- 70: 71: suite() -> 72: escalus:suite(). 73: 74: all() -> 75: [ 76: {group, retrieve_personal_data}, 77: {group, retrieve_negative}, 78: {group, remove_personal_data} 79: ]. 80: 81: groups() -> 82: %% **DON'T** make any of these groups parallel, because calling mongooseimctl 83: %% in parallel is broken! 84: [ 85: {retrieve_personal_data, [], [ 86: retrieve_vcard, 87: retrieve_roster, 88: retrieve_offline, 89: retrieve_inbox, 90: retrieve_logs, 91: {group, retrieve_personal_data_pubsub}, 92: {group, retrieve_personal_data_private_xml}, 93: {group, retrieve_personal_data_mam}, 94: {group, retrieve_personal_data_inbox} 95: ]}, 96: {retrieve_personal_data_inbox, [],[ 97: retrieve_inbox, 98: retrieve_inbox_for_multiple_messages, 99: retrieve_inbox_muclight, 100: retrieve_inbox_muc 101: ]}, 102: {retrieve_personal_data_pubsub, [], [ 103: retrieve_pubsub_payloads, 104: dont_retrieve_other_user_pubsub_payload, 105: retrieve_pubsub_subscriptions, 106: retrieve_created_pubsub_nodes, 107: retrieve_all_pubsub_data 108: ]}, 109: {retrieve_personal_data_private_xml, [], [ 110: retrieve_private_xml, 111: dont_retrieve_other_user_private_xml, 112: retrieve_multiple_private_xmls 113: ]}, 114: {retrieve_negative, [], [ 115: data_is_not_retrieved_for_missing_user 116: ]}, 117: {retrieve_personal_data_mam, [], [ 118: {group, retrieve_personal_data_mam_rdbms}, 119: {group, retrieve_personal_data_mam_riak}, 120: {group, retrieve_personal_data_mam_cassandra}, 121: {group, retrieve_personal_data_mam_elasticsearch} 122: ]}, 123: {retrieve_personal_data_mam_rdbms, [], all_mam_testcases()}, 124: {retrieve_personal_data_mam_riak, [], all_mam_testcases()}, 125: {retrieve_personal_data_mam_cassandra, [], all_mam_testcases()}, 126: {retrieve_personal_data_mam_elasticsearch, [], all_mam_testcases()}, 127: {remove_personal_data, [], removal_testcases()}, 128: {remove_personal_data_inbox, [], [remove_inbox, remove_inbox_muclight, remove_inbox_muc]}, 129: {remove_personal_data_mam, [], [ 130: {group, remove_personal_data_mam_rdbms}, 131: {group, remove_personal_data_mam_riak}, 132: {group, remove_personal_data_mam_cassandra}, 133: {group, remove_personal_data_mam_elasticsearch} 134: ]}, 135: {remove_personal_data_mam_rdbms, [], mam_removal_testcases()}, 136: {remove_personal_data_mam_riak, [], mam_removal_testcases()}, 137: {remove_personal_data_mam_cassandra, [], mam_removal_testcases()}, 138: {remove_personal_data_mam_elasticsearch, [], mam_removal_testcases()}, 139: {remove_personal_data_pubsub, [], [ 140: remove_pubsub_subscriptions, 141: remove_pubsub_dont_remove_node_when_only_publisher, 142: remove_pubsub_dont_remove_flat_pubsub_node, 143: remove_pubsub_push_node, 144: remove_pubsub_pep_node, 145: remove_pubsub_all_data 146: ]} 147: ]. 148: 149: removal_testcases() -> 150: [ 151: remove_vcard, 152: remove_roster, 153: remove_offline, 154: remove_private, 155: remove_multiple_private_xmls, 156: dont_remove_other_user_private_xml, 157: {group, remove_personal_data_inbox}, 158: {group, remove_personal_data_pubsub}, 159: {group, remove_personal_data_mam} 160: ]. 161: 162: mam_removal_testcases() -> 163: [ 164: remove_mam_pm 165: ]. 166: 167: 168: mam_testcases() -> 169: [ 170: retrieve_mam_pm, 171: retrieve_mam_muc_light, 172: retrieve_mam_pm_and_muc_light_interfere, 173: retrieve_mam_pm_and_muc_light_dont_interfere 174: ]. 175: 176: all_mam_testcases() -> 177: [ 178: retrieve_mam_muc, 179: retrieve_mam_muc_private_msg, 180: retrieve_mam_muc_store_pm 181: | mam_testcases() 182: ]. 183: 184: init_per_suite(Config) -> 185: #{node := MimNode} = distributed_helper:mim(), 186: Config1 = [{{ejabberd_cwd, MimNode}, get_mim_cwd()} | dynamic_modules:save_modules(host_type(), Config)], 187: muc_helper:load_muc(), 188: escalus:init_per_suite(Config1). 189: 190: end_per_suite(Config) -> 191: delete_files(), 192: escalus_fresh:clean(), 193: dynamic_modules:restore_modules(Config), 194: escalus:end_per_suite(Config). 195: 196: init_per_group(GN, Config) when GN =:= remove_personal_data_mam_rdbms; 197: GN =:= retrieve_personal_data_mam_rdbms -> 198: try_backend_for_mam(Config, rdbms); 199: init_per_group(GN, Config) when GN =:= retrieve_personal_data_pubsub; 200: GN =:= remove_personal_data_pubsub -> 201: [{group, GN} | Config]; 202: init_per_group(GN, Config) when GN =:= retrieve_personal_data_mam_riak; 203: GN =:= remove_personal_data_mam_riak -> 204: try_backend_for_mam(Config, riak); 205: init_per_group(GN, Config) when GN =:= retrieve_personal_data_mam_cassandra; 206: GN =:= remove_personal_data_mam_cassandra-> 207: try_backend_for_mam(Config, cassandra); 208: init_per_group(GN, Config) when GN =:= retrieve_personal_data_mam_elasticsearch; 209: GN =:= remove_personal_data_mam_elasticsearch -> 210: try_backend_for_mam(Config, elasticsearch); 211: init_per_group(retrieve_personal_data_inbox = GN, Config) -> 212: init_inbox(GN, Config, muclight); 213: init_per_group(remove_personal_data_inbox = GN, Config) -> 214: init_inbox(GN, Config, muclight); 215: init_per_group(retrieve_personal_data_private_xml, Config) -> 216: private_started(), 217: Config; 218: init_per_group(_GN, Config) -> 219: Config. 220: 221: end_per_group(_GN, Config) -> 222: Config. 223: 224: try_backend_for_mam(Config, Backend) -> 225: case is_backend_enabled(Backend) of 226: true -> [{mam_backend, Backend} | Config]; 227: false -> {skip, backend_is_not_configured} 228: end. 229: 230: is_backend_enabled(rdbms) -> mongoose_helper:is_rdbms_enabled(host_type()); 231: is_backend_enabled(riak) -> mam_helper:is_riak_enabled(host_type()); 232: is_backend_enabled(cassandra) -> mam_helper:is_cassandra_enabled(host_type()); 233: is_backend_enabled(elasticsearch) -> mam_helper:is_elasticsearch_enabled(host_type()). 234: 235: 236: init_per_testcase(retrieve_logs = CN, Config) -> 237: case is_mim2_started() of 238: false -> {skip, not_running_in_distributed}; 239: _ -> escalus:init_per_testcase(CN, Config) 240: end; 241: init_per_testcase(CN, Config) when CN =:= remove_offline; 242: CN =:= retrieve_offline -> 243: offline_started(), 244: escalus:init_per_testcase(CN, Config); 245: init_per_testcase(CN, Config) when 246: CN =:= remove_inbox; 247: CN =:= retrieve_inbox; 248: CN =:= remove_inbox_muclight; 249: CN =:= retrieve_inbox_muclight -> 250: Config1 = init_inbox(CN, Config, muclight), 251: Config1; 252: init_per_testcase(CN, Config) when CN =:= retrieve_inbox_muc; 253: CN =:= remove_inbox_muc -> 254: muc_helper:load_muc(), 255: Config0 = init_inbox(CN, Config, muc), 256: Config0; 257: 258: init_per_testcase(retrieve_vcard = CN, Config) -> 259: case vcard_helper:is_vcard_ldap() of 260: true -> 261: {skip, skipped_for_simplicity_for_now}; % TODO: Fix the case for LDAP as well 262: _ -> 263: escalus:init_per_testcase(CN, Config) 264: end; 265: init_per_testcase(remove_vcard = CN, Config) -> 266: case vcard_helper:is_vcard_ldap() of 267: true -> 268: {skip, skipped_for_simplicity_for_now}; % TODO: Fix the case for LDAP as well 269: _ -> 270: vcard_started(), 271: escalus:init_per_testcase(CN, Config) 272: end; 273: init_per_testcase(CN, Config) when CN =:= remove_private; 274: CN =:= dont_remove_other_user_private_xml; 275: CN =:= remove_multiple_private_xmls -> 276: private_started(), 277: escalus:init_per_testcase(CN, Config); 278: 279: init_per_testcase(CN, Config) when CN =:= retrieve_mam_muc; 280: CN =:= retrieve_mam_muc_private_msg; 281: CN =:= retrieve_mam_muc_store_pm; 282: CN =:= retrieve_mam_muc_light; 283: CN =:= retrieve_mam_pm_and_muc_light_interfere; 284: CN =:= retrieve_mam_pm_and_muc_light_dont_interfere; 285: CN =:= retrieve_mam_pm; 286: CN =:= remove_mam_pm -> 287: case proplists:get_value(mam_backend, Config, skip) of 288: skip -> 289: {skip, no_mam_backend_configured}; 290: Backend -> 291: dynamic_modules:restore_modules(Config), 292: RequiredModules = mam_required_modules(CN, Backend), 293: dynamic_modules:ensure_modules(host_type(), RequiredModules), 294: ct:log("required modules: ~p~n", [RequiredModules]), 295: escalus:init_per_testcase(CN, [{mam_modules, RequiredModules} | Config]) 296: end; 297: init_per_testcase(remove_roster = CN, Config) -> 298: roster_started(), 299: escalus:init_per_testcase(CN, Config); 300: init_per_testcase(CN, Config) -> 301: GN = proplists:get_value(group, Config), 302: IsPubSub = lists:member(GN, [retrieve_personal_data_pubsub, remove_personal_data_pubsub]), 303: case IsPubSub of 304: true -> 305: dynamic_modules:ensure_modules(host_type(), pubsub_required_modules()); 306: _ -> 307: ok 308: end, 309: escalus:init_per_testcase(CN, Config). 310: 311: 312: end_per_testcase(CN, Config) when CN =:= retrieve_mam_muc_light; 313: CN =:= retrieve_mam_pm_and_muc_light_interfere; 314: CN =:= retrieve_mam_pm_and_muc_light_dont_interfere -> 315: muc_light_helper:clear_db(host_type()), 316: escalus:end_per_testcase(CN, Config); 317: %% mod_inbox 318: end_per_testcase(CN, Config) when 319: CN =:= remove_inbox; 320: CN =:= retrieve_inbox; 321: CN =:= remove_inbox_muclight; 322: CN =:= retrieve_inbox_muclight -> 323: muc_light_helper:clear_db(host_type()), 324: escalus:end_per_testcase(CN, Config); 325: end_per_testcase(CN, Config) when CN =:= retrieve_inbox_muc; 326: CN =:= remove_inbox_muc -> 327: muc_helper:unload_muc(), 328: escalus:end_per_testcase(CN, Config); 329: end_per_testcase(CN, Config) -> 330: escalus_fresh:clean(), 331: escalus:end_per_testcase(CN, Config). 332: 333: init_inbox(CN, Config, GroupChatType) -> 334: case (not ct_helper:is_ct_running()) 335: orelse mongoose_helper:is_rdbms_enabled(host_type()) of 336: true -> 337: dynamic_modules:ensure_modules(host_type(), inbox_required_modules(GroupChatType)), 338: escalus:init_per_testcase(CN, Config); 339: false -> 340: {skip, require_rdbms} 341: end. 342: inbox_required_modules(Type) -> 343: GroupChatModules = groupchat_module(Type), 344: InboxOpts = (inbox_helper:inbox_opts())#{groupchat => [Type]}, 345: Inbox = {mod_inbox, InboxOpts}, 346: GroupChatModules ++ [Inbox] . 347: 348: groupchat_module(muc) -> 349: []; 350: groupchat_module(muclight) -> 351: [{mod_muc_light, mod_config(mod_muc_light, 352: #{backend => mongoose_helper:mnesia_or_rdbms_backend(), 353: rooms_in_rosters => true})}]. 354: 355: mam_required_modules(CN, Backend) when CN =:= remove_mam_pm; 356: CN =:= retrieve_mam_pm -> 357: [{mod_mam, mam_helper:config_opts(#{backend => Backend, pm => #{}})}]; 358: mam_required_modules(CN, Backend) when CN =:= retrieve_mam_pm_and_muc_light_dont_interfere; 359: CN =:= retrieve_mam_muc_light -> 360: HostPattern = subhost_pattern(muc_light_helper:muc_host_pattern()), 361: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 362: pm => #{}, 363: muc => #{host => HostPattern}})}, 364: {mod_muc_light, default_mod_config(mod_muc_light)}]; 365: mam_required_modules(retrieve_mam_pm_and_muc_light_interfere, Backend) -> 366: HostPattern = subhost_pattern(muc_light_helper:muc_host_pattern()), 367: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 368: db_message_format => mam_message_xml, 369: pm => #{archive_groupchats => true}, 370: muc => #{host => HostPattern}})}, 371: {mod_muc_light, default_mod_config(mod_muc_light)}]; 372: mam_required_modules(CN, Backend) when CN =:= retrieve_mam_muc_private_msg; 373: CN =:= retrieve_mam_muc -> 374: HostPattern = subhost_pattern(muc_helper:muc_host_pattern()), 375: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 376: pm => #{}, 377: muc => #{host => HostPattern}})}, 378: {mod_muc, muc_helper:make_opts(#{host => HostPattern})}]; 379: mam_required_modules(retrieve_mam_muc_store_pm, Backend) -> 380: HostPattern = subhost_pattern(muc_helper:muc_host_pattern()), 381: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 382: pm => #{archive_groupchats => true}, 383: muc => #{host => HostPattern}})}, 384: {mod_muc, muc_helper:make_opts(#{host => HostPattern})}]. 385: 386: pick_enabled_backend() -> 387: BackendsList = [ 388: {mam_helper:is_riak_enabled(host_type()), riak}, 389: {mongoose_helper:is_rdbms_enabled(host_type()), rdbms} 390: ], 391: proplists:get_value(true, BackendsList, mnesia). 392: 393: roster_required_modules() -> 394: Backend = pick_enabled_backend(), 395: [{mod_roster, roster_backend_opts(Backend)}]. 396: 397: roster_backend_opts(riak) -> 398: RiakDefaults = config_parser_helper:default_config([modules, mod_roster, riak]), 399: mod_config(mod_roster, #{backend => riak, riak => RiakDefaults}); 400: roster_backend_opts(Backend) -> 401: mod_config(mod_roster, #{backend => Backend}). 402: 403: vcard_required_modules() -> 404: Backend = pick_enabled_backend(), 405: [{mod_vcard, mod_config(mod_vcard, vcard_backend_opts(Backend))}]. 406: 407: vcard_backend_opts(riak) -> 408: #{backend => riak, riak => #{bucket_type => <<"vcard">>, 409: search_index => <<"vcard">>}}; 410: vcard_backend_opts(Backend) -> 411: #{backend => Backend}. 412: 413: offline_required_modules() -> 414: [{mod_offline, mod_offline_config(pick_enabled_backend())}]. 415: 416: mod_offline_config(riak) -> 417: config_parser_helper:mod_config(mod_offline, #{backend => riak, riak => #{bucket_type => <<"offline">>}}); 418: mod_offline_config(Backend) -> 419: config_parser_helper:mod_config(mod_offline, #{backend => Backend}). 420: 421: pubsub_required_modules() -> 422: pubsub_required_modules([<<"flat">>, <<"pep">>, <<"push">>]). 423: pubsub_required_modules(Plugins) -> 424: HostPattern = subhost_pattern("pubsub.@HOST@"), 425: PubsubConfig = mod_config(mod_pubsub, #{backend => mongoose_helper:mnesia_or_rdbms_backend(), 426: host => HostPattern, 427: nodetree => nodetree_tree, 428: plugins => Plugins}), 429: [{mod_caps, config_parser_helper:default_mod_config(mod_caps)}, {mod_pubsub, PubsubConfig}]. 430: 431: is_mim2_started() -> 432: #{node := Node} = distributed_helper:mim2(), 433: case net_adm:ping(Node) of 434: pong -> true; 435: _ -> false 436: end. 437: 438: roster_started() -> 439: dynamic_modules:ensure_modules(host_type(), roster_required_modules()). 440: 441: vcard_started() -> 442: dynamic_modules:ensure_modules(host_type(), vcard_required_modules()). 443: 444: offline_started() -> 445: dynamic_modules:ensure_modules(host_type(), offline_required_modules()). 446: 447: private_required_modules() -> 448: [{mod_private, create_private_config(pick_enabled_backend())}]. 449: 450: create_private_config(riak) -> 451: mod_config(mod_private, #{backend => riak, riak => #{bucket_type => <<"private">>}}); 452: create_private_config(Backend) -> 453: mod_config(mod_private, #{backend => Backend}). 454: 455: private_started() -> 456: dynamic_modules:ensure_modules(host_type(), private_required_modules()). 457: 458: %% ------------------------------------------------------------- 459: %% Test cases 460: %% ------------------------------------------------------------- 461: 462: %% ------------------------- Data retrieval - per type verification ------------------------- 463: 464: retrieve_vcard(Config) -> 465: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 466: AliceFields = [{<<"FN">>, <<"Alice">>}, {<<"LN">>, <<"Ecila">>}], 467: AliceSetResultStanza 468: = escalus:send_and_wait(Alice, escalus_stanza:vcard_update(AliceFields)), 469: escalus:assert(is_iq_result, AliceSetResultStanza), 470: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 471: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 472: ExpectedHeader = ["jid", "vcard"], 473: ExpectedItems = [ 474: #{ "jid" => [{contains, AliceU}, 475: {contains, AliceS}], 476: "vcard" => [{contains, "Alice"}, 477: {contains, "Ecila"}] } 478: ], 479: retrieve_and_validate_personal_data( 480: Alice, Config, "vcard", ExpectedHeader, ExpectedItems) 481: end). 482: 483: remove_vcard(Config) -> 484: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 485: AliceFields = [{<<"FN">>, <<"Alice">>}, {<<"LN">>, <<"Ecila">>}], 486: AliceSetResultStanza 487: = escalus:send_and_wait(Alice, escalus_stanza:vcard_update(AliceFields)), 488: escalus:assert(is_iq_result, AliceSetResultStanza), 489: 490: {0, _} = unregister(Alice, Config), 491: 492: assert_personal_data_via_rpc(Alice, [{vcard,["jid","vcard"],[]}]) 493: 494: end). 495: 496: remove_private(Config) -> 497: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 498: %% Add some private data for Alice 499: Element = #xmlel{name = <<"item">>, 500: attrs = [{<<"xmlns">>, <<"alice:private_remove:ns">>}], 501: children = [#xmlcdata{ content = <<"Something to declare">> }]}, 502: SetPrivateResult = escalus:send_and_wait(Alice, 503: escalus_stanza:private_set(Element)), 504: escalus:assert(is_iq_result, SetPrivateResult), 505: 506: %% Verify the data is stored 507: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], 508: [{<<"alice:private_remove:ns">>, 509: <<"<item xmlns='alice:private_remove:ns'>Something to declare</item>">>}]}]), 510: 511: %% Remove Alice 512: {0, _} = unregister(Alice, Config), 513: 514: %% Expect Alice's data to be gone 515: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]) 516: 517: end). 518: 519: dont_remove_other_user_private_xml(Config) -> 520: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 521: %% Add some private data for Alice and Bob 522: AliceNS = <<"alice:private:ns">>, 523: AliceContent = <<"To be or not to be">>, 524: BobNS = <<"bob:private:ns">>, 525: BobContent = <<"This is the winter of our discontent">>, 526: send_and_assert_private_stanza(Alice, AliceNS, AliceContent), 527: send_and_assert_private_stanza(Bob, BobNS, BobContent), 528: 529: %% Remove Alice 530: {0, _} = unregister(Alice, Config), 531: 532: %% Expect Alice's data to be gone 533: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]), 534: 535: %% Verify that Bob's data is left intact 536: ExpectedHeader = ["ns", "xml"], 537: ExpectedItems = [#{ "ns" => binary_to_list(BobNS), 538: "xml" => [{contains, binary_to_list(BobNS)}, 539: {contains, binary_to_list(BobContent)}] } 540: ], 541: retrieve_and_validate_personal_data( 542: Bob, Config, "private", ExpectedHeader, ExpectedItems) 543: 544: end). 545: 546: remove_multiple_private_xmls(Config) -> 547: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 548: %% Add some private data for Alice for multiple keys 549: NSsAndContents = [ 550: {<<"alice:private:ns1">>, <<"Some text">>}, 551: {<<"alice:private:ns2">>, <<"Other text for another key">>}, 552: {<<"alice:private:ns3">>, <<"Even more of text">>} 553: ], 554: lists:foreach( 555: fun({NS, Content}) -> 556: send_and_assert_private_stanza(Alice, NS, Content) 557: end, NSsAndContents), 558: ExpectedHeader = ["ns", "xml"], 559: ExpectedItems = lists:map( 560: fun({NS, Content}) -> 561: #{ "ns" => binary_to_list(NS), 562: "xml" => [{contains, binary_to_list(NS)}, 563: {contains, binary_to_list(Content)}]} 564: end, NSsAndContents), 565: 566: %% Verify the data is stored 567: retrieve_and_validate_personal_data( 568: Alice, Config, "private", ExpectedHeader, ExpectedItems), 569: 570: %% Remove Alice 571: {0, _} = unregister(Alice, Config), 572: 573: %% Expect all of Alice's data to be gone 574: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]) 575: 576: end). 577: 578: retrieve_roster(Config) -> 579: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 580: escalus_story:make_all_clients_friends([Alice, Bob]), 581: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 582: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 583: ExpectedItems = [ 584: #{ "jid" => [{contains, BobU}, {contains, BobS}] } 585: ], 586: retrieve_and_validate_personal_data( 587: Alice, Config, "roster", expected_header(mod_roster), ExpectedItems) 588: end). 589: 590: remove_roster(Config) -> 591: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 592: escalus_story:make_all_clients_friends([Alice, Bob]), 593: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 594: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 595: ExpectedItems = [ 596: #{ "jid" => [{contains, AliceU}, {contains, AliceS}] } 597: ], 598: 599: {0, _} = unregister(Alice, Config), 600: 601: assert_personal_data_via_rpc(Alice, [{roster, expected_header(mod_roster), []}]), 602: retrieve_and_validate_personal_data( 603: Bob, Config, "roster", expected_header(mod_roster), ExpectedItems) 604: 605: end). 606: 607: retrieve_mam_pm(Config) -> 608: F = fun(Alice, Bob) -> 609: Msg1 = <<"1some simple pm message">>, 610: Msg2 = <<"2another simple pm message">>, 611: Msg3 = <<"3third simple pm message">>, 612: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg1)), 613: escalus:send(Bob, escalus_stanza:chat_to(Alice, Msg2)), 614: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg3)), 615: [mam_helper:wait_for_archive_size(User, 3) || User <- [Alice, Bob]], 616: AliceJID = escalus_client:full_jid(Alice), 617: BobJID = escalus_client:full_jid(Bob), 618: 619: ExpectedHeader = ["id", "from", "message"], 620: ExpectedItems = [ 621: #{"message" => [{contains, Msg1}], "from" => [{jid, AliceJID}]}, 622: #{"message" => [{contains, Msg3}], "from" => [{jid, AliceJID}]}, 623: #{"message" => [{contains, Msg2}], "from" => [{jid, BobJID}]} 624: ], 625: 626: retrieve_and_validate_personal_data( 627: Alice, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]), 628: retrieve_and_validate_personal_data( 629: Bob, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]) 630: end, 631: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 632: 633: retrieve_mam_muc(Config) -> 634: F = fun(Alice, Bob, Kate) -> 635: AliceUserCfg = escalus_users:get_user_by_name(alice), 636: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 637: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 638: AllRoomMembers = [Alice, Bob, Kate], 639: 640: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, 641: {Bob, <<"Sid">>}, 642: {Kate, <<"Johnny">>}]), 643: 644: Body1 = <<"1some simple muc message">>, 645: Body2 = <<"2another one">>, 646: Body3 = <<"3third message">>, 647: muc_helper:send_to_room(RoomCfg, Alice, Body1), 648: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), 649: muc_helper:send_to_room(RoomCfg, Alice, Body2), 650: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), 651: muc_helper:send_to_room(RoomCfg, Bob, Body3), 652: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), 653: 654: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 655: 656: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 657: #{"message" => [{contains, binary_to_list(Body2)}]}], 658: 659: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 660: 661: AliceDir = retrieve_all_personal_data(Alice, Config), 662: BobDir = retrieve_all_personal_data(Bob, Config), 663: KateDir = retrieve_all_personal_data(Kate, Config), 664: 665: validate_personal_data( 666: AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 667: validate_personal_data( 668: BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 669: refute_personal_data(KateDir, "mam_muc"), 670: 671: [refute_personal_data(Dir, "mam_pm") || Dir <- [AliceDir, BobDir, KateDir]], 672: 673: muc_helper:destroy_room(RoomCfg) 674: end, 675: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 676: 677: retrieve_mam_muc_private_msg(Config) -> 678: F = fun(Alice, Bob) -> 679: AliceUserCfg = escalus_users:get_user_by_name(alice), 680: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 681: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 682: 683: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, {Bob, <<"Sid">>}]), 684: 685: PMBody = <<"Hi, Bob!">>, 686: {PrivAddrAlice, _} = send_receive_muc_private_message( 687: Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), 688: 689: [mam_helper:wait_for_archive_size(User, 1) || User <- [Alice, Bob]], 690: 691: PMExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(PMBody)}], 692: "from" => [{jid, escalus_client:full_jid(Alice)}]}], 693: PMExpectedItemsBob = [#{"message" => [{contains, binary_to_list(PMBody)}], 694: "from" => [{jid, PrivAddrAlice}]}], 695: 696: AliceDir = retrieve_all_personal_data(Alice, Config), 697: BobDir = retrieve_all_personal_data(Bob, Config), 698: 699: validate_personal_data( 700: AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, []), 701: validate_personal_data( 702: BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, []), 703: 704: refute_personal_data(AliceDir, "mam_muc"), 705: refute_personal_data(BobDir, "mam_muc"), 706: 707: muc_helper:destroy_room(RoomCfg) 708: end, 709: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 710: 711: 712: 713: retrieve_mam_muc_store_pm(Config) -> 714: F = fun(Alice, Bob, Kate) -> 715: AliceUserCfg = escalus_users:get_user_by_name(alice), 716: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 717: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 718: AllRoomMembers = [Alice, Bob, Kate], 719: 720: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, 721: {Bob, <<"Sid">>}, 722: {Kate, <<"Johnny">>}]), 723: 724: Body1 = <<"1some simple muc message">>, 725: Body2 = <<"2another one">>, 726: Body3 = <<"3third message">>, 727: muc_helper:send_to_room(RoomCfg, Alice, Body1), 728: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), 729: muc_helper:send_to_room(RoomCfg, Alice, Body2), 730: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), 731: muc_helper:send_to_room(RoomCfg, Bob, Body3), 732: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), 733: 734: PMBody = <<"4Hi, Bob!">>, 735: {PrivAddrAlice, PrivAddrBob} = send_receive_muc_private_message( 736: Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), 737: 738: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 739: mam_helper:wait_for_archive_size(Kate, 4), 740: [mam_helper:wait_for_archive_size(User, 5) || User <- [Alice, Bob]], 741: 742: AliceDir = retrieve_all_personal_data(Alice, Config), 743: BobDir = retrieve_all_personal_data(Bob, Config), 744: KateDir = retrieve_all_personal_data(Kate, Config), 745: 746: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 747: #{"message" => [{contains, binary_to_list(Body2)}]}], 748: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 749: 750: validate_personal_data( 751: AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 752: validate_personal_data( 753: BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 754: refute_personal_data(KateDir, "mam_muc"), 755: 756: RoomJID = <<Room/binary, "@", Domain/binary>>, 757: MsgFromAliceToRoom = #{"message" => [{contains, "<body>[1,2]"}], 758: "from" => [{jid, PrivAddrAlice}]}, 759: PMExpectedItemsKate = [#{"message" => [{contains, "<body/>"}], 760: "from" => [{jid, RoomJID}]}, 761: MsgFromAliceToRoom, MsgFromAliceToRoom, 762: #{"message" => [{contains, binary_to_list(Body3)}], 763: "from" => [{jid, PrivAddrBob}]} 764: ], 765: PMExpectedItemsAlice = PMExpectedItemsKate ++ 766: [#{"message" => [{contains, binary_to_list(PMBody)}], 767: "from" => [{jid, escalus_client:full_jid(Alice)}]}], 768: MsgFromAlice = #{"message" => [{contains, "<body>[1,2,4]"}], 769: "from" => [{jid, PrivAddrAlice}]}, 770: PMExpectedItemsBob = [#{"message" => [{contains, "<body/>"}], 771: "from" => [{jid, RoomJID}]}, 772: MsgFromAlice, MsgFromAlice, MsgFromAlice, 773: #{"message" => [{contains, binary_to_list(Body3)}], 774: "from" => [{jid, PrivAddrBob}]} 775: ], 776: SortFn = muc_msg_first(RoomJID), 777: validate_personal_data( 778: KateDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsKate, SortFn), 779: validate_personal_data( 780: AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, SortFn), 781: validate_personal_data( 782: BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, SortFn), 783: 784: muc_helper:destroy_room(RoomCfg) 785: end, 786: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 787: 788: remove_mam_pm(Config) -> 789: F = fun(Alice, Bob) -> 790: Msg1 = <<"1remove_mam_pm message">>, 791: Msg2 = <<"2remove_mam_pm message message">>, 792: Msg3 = <<"3remove_mam_pm message message">>, 793: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg1)), 794: escalus:send(Bob, escalus_stanza:chat_to(Alice, Msg2)), 795: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg3)), 796: [mam_helper:wait_for_archive_size(User, 3) || User <- [Alice, Bob]], 797: AliceJID = escalus_client:full_jid(Alice), 798: BobJID = escalus_client:full_jid(Bob), 799: 800: ExpectedHeader = ["id", "from", "message"], 801: ExpectedItems = [ 802: #{"message" => [{contains, Msg1}], "from" => [{jid, AliceJID}]}, 803: #{"message" => [{contains, Msg3}], "from" => [{jid, AliceJID}]}, 804: #{"message" => [{contains, Msg2}], "from" => [{jid, BobJID}]} 805: ], 806: 807: {0, _} = unregister(Alice, Config), 808: 809: assert_personal_data_via_rpc(Alice, [{mam_pm, ExpectedHeader, []}]), 810: 811: retrieve_and_validate_personal_data( 812: Bob, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]) 813: end, 814: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 815: 816: retrieve_mam_muc_light(Config) -> 817: F = fun(Alice, Bob, Kate) -> 818: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, [{Bob, member}, {Kate, member}]), 819: [Room, Domain] = binary:split(RoomJid, <<"@">>), 820: Body1 = <<"1some simple muc message">>, 821: Body2 = <<"2another one">>, 822: Body3 = <<"3third message">>, 823: 824: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, Body1, <<"Id1">>), 825: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 826: M2 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, Body2, <<"Id2">>), 827: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 828: M3 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, Body3, <<"Id3">>), 829: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M3), 830: 831: mam_helper:wait_for_room_archive_size(Domain, Room, 4), 832: 833: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 834: #{"message" => [{contains, binary_to_list(Body2)}]}], 835: 836: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 837: 838: retrieve_and_validate_personal_data( 839: Alice, Config, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 840: retrieve_and_validate_personal_data( 841: Bob, Config, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 842: refute_personal_data(Kate, Config, "mam_muc") 843: end, 844: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 845: 846: retrieve_mam_pm_and_muc_light_dont_interfere(Config) -> 847: F = fun(Alice, Bob, Kate) -> 848: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, 849: [{Bob, member}, {Kate, member}]), 850: [Room, Domain] = binary:split(RoomJid, <<"@">>), 851: BodyMucAlice = <<"some simple muc message from Alice">>, 852: BodyMucBob = <<"some simple muc message from Bob">>, 853: BodyPmAlice = <<"some simple pm message from Alice">>, 854: BodyPmBob = <<"some simple pm message from Bob">>, 855: 856: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, BodyMucAlice, <<"Id1">>), 857: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 858: M2 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, BodyMucBob, <<"Id2">>), 859: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 860: 861: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 862: 863: escalus:send(Alice, escalus_stanza:chat_to(Bob, BodyPmAlice)), 864: escalus:send(Bob, escalus_stanza:chat_to(Alice, BodyPmBob)), 865: 866: [mam_helper:wait_for_archive_size(User, 2) || User <- [Alice, Bob]], 867: 868: false = mongoose_helper:successful_rpc(gen_mod, get_module_opt, 869: [host_type(), mod_mam_pm, archive_groupchats, undefined]), 870: 871: AliceDir = retrieve_all_personal_data(Alice, Config), 872: BobDir = retrieve_all_personal_data(Bob, Config), 873: KateDir = retrieve_all_personal_data(Kate, Config), 874: 875: validate_personal_data( 876: AliceDir, "mam_muc", ["id", "message"], 877: [#{"message" => [{contains, binary_to_list(BodyMucAlice)}]}], []), 878: validate_personal_data( 879: BobDir, "mam_muc", ["id", "message"], 880: [#{"message" => [{contains, binary_to_list(BodyMucBob)}]}], []), 881: 882: PM = [#{"message" => [{contains, BodyPmAlice}], 883: "from" => [{jid, escalus_client:full_jid(Alice)}]}, 884: #{"message" => [{contains, BodyPmBob}], 885: "from" => [{jid, escalus_client:full_jid(Bob)}]}], 886: validate_personal_data(AliceDir, "mam_pm", ["id", "from", "message"], PM, ["from", "message"]), 887: validate_personal_data(BobDir, "mam_pm", ["id", "from", "message"], PM, ["from", "message"]), 888: refute_personal_data(KateDir, "mam_pm"), 889: refute_personal_data(KateDir, "mam_muc") 890: end, 891: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 892: 893: retrieve_mam_pm_and_muc_light_interfere(Config) -> 894: F = fun(Alice, Bob, Kate) -> 895: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, 896: [{Bob, member}, {Kate, member}]), 897: [Room, Domain] = binary:split(RoomJid, <<"@">>), 898: BodyMucAlice = <<"some simple muc message from Alice">>, 899: BodyMucBob = <<"some simple muc message from Bob">>, 900: BodyPmAlice = <<"some simple pm message from Alice">>, 901: BodyPmBob = <<"some simple pm message from Bob">>, 902: 903: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, BodyMucAlice, <<"Id1">>), 904: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 905: M2 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, BodyMucBob, <<"Id2">>), 906: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 907: 908: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 909: 910: escalus:send(Alice, escalus_stanza:chat_to(Bob, BodyPmAlice)), 911: escalus:send(Bob, escalus_stanza:chat_to(Alice, BodyPmBob)), 912: 913: [mam_helper:wait_for_archive_size(User, 5) || User <- [Alice, Bob]], 914: mam_helper:wait_for_archive_size(Kate, 3), 915: 916: true = mongoose_helper:successful_rpc(gen_mod, get_module_opt, 917: [host_type(), mod_mam_pm, archive_groupchats, undefined]), 918: 919: AliceDir = retrieve_all_personal_data(Alice, Config), 920: BobDir = retrieve_all_personal_data(Bob, Config), 921: KateDir = retrieve_all_personal_data(Kate, Config), 922: 923: validate_personal_data( 924: AliceDir, "mam_muc", ["id", "message"], 925: [#{"message" => [{contains, binary_to_list(BodyMucAlice)}]}], []), 926: validate_personal_data( 927: BobDir, "mam_muc", ["id", "message"], 928: [#{"message" => [{contains, binary_to_list(BodyMucBob)}]}], []), 929: 930: AliceRoomJid = <<RoomJid/binary, "/", (escalus_client:short_jid(Alice))/binary>>, 931: BobRoomJid = <<RoomJid/binary, "/", (escalus_client:short_jid(Bob))/binary>>, 932: 933: MucPM = [#{"message" => [{contains, "urn:xmpp:muclight:0#affiliations"}], 934: "from" => [{jid, RoomJid}]}, 935: #{"message" => [{contains, BodyMucAlice}], "from" => [{jid, AliceRoomJid}]}, 936: #{"message" => [{contains, BodyMucBob}], "from" => [{jid, BobRoomJid}]}], 937: AllPM = MucPM ++ [#{"message" => [{contains, BodyPmAlice}], 938: "from" => [{jid, escalus_client:full_jid(Alice)}]}, 939: #{"message" => [{contains, BodyPmBob}], 940: "from" => [{jid, escalus_client:full_jid(Bob)}]}], 941: SortFn = muc_msg_first(RoomJid), 942: validate_personal_data(AliceDir, "mam_pm", ["id", "from", "message"], AllPM, SortFn), 943: validate_personal_data(BobDir, "mam_pm", ["id", "from", "message"], AllPM, SortFn), 944: validate_personal_data(KateDir, "mam_pm", ["id", "from", "message"], MucPM, SortFn), 945: refute_personal_data(KateDir, "mam_muc") 946: end, 947: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 948: 949: retrieve_offline(Config) -> 950: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 951: mongoose_helper:logout_user(Config, Alice), 952: Body1 = <<"1Hey!">>, 953: Body2 = <<"2Here is Johnny!">>, 954: Body3 = <<"3Where is Johnny ?">>, 955: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body1)), 956: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body2)), 957: escalus:send(Kate, escalus_stanza:chat_to(Alice, Body3)), 958: %% Well, jid_to_lower works for any binary :) 959: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 960: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 961: mongoose_helper:wait_until( 962: fun() -> 963: mongoose_helper:successful_rpc(mod_offline_backend, count_offline_messages, 964: [host_type(), AliceU, AliceS, 10]) 965: end, 3), 966: 967: BobJid = escalus_client:full_jid(Bob), 968: AliceJid = escalus_client:short_jid(Alice), 969: KateJid = escalus_client:full_jid(Kate), 970: ExpectedHeader = ["timestamp", "from", "to", "packet"], 971: Expected = [{Body1, BobJid, AliceJid}, {Body2, BobJid, AliceJid}, {Body3, KateJid, AliceJid}], 972: 973: ExpectedItems = lists:map(fun({Body, From ,To}) -> 974: #{ "packet" => [{contains, Body}], 975: "from" => binary_to_list(From), 976: "to" => binary_to_list(To), 977: "timestamp" => [{validate, fun validate_datetime/1}]} 978: end, Expected), 979: 980: retrieve_and_validate_personal_data( 981: Alice, Config, "offline", ExpectedHeader, ExpectedItems, ["packet"]) 982: end). 983: 984: remove_offline(Config) -> 985: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 986: mongoose_helper:logout_user(Config, Alice), 987: Body1 = <<"Hey!">>, 988: Body2 = <<"Here is Johnny!">>, 989: Body3 = <<"Where is Johnny ?">>, 990: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body1)), 991: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body2)), 992: escalus:send(Kate, escalus_stanza:chat_to(Alice, Body3)), 993: %% Well, jid_to_lower works for any binary :) 994: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 995: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 996: mongoose_helper:wait_until( 997: fun() -> 998: mongoose_helper:successful_rpc(mod_offline_backend, count_offline_messages, 999: [host_type(), AliceU, AliceS, 10]) 1000: end, 3), 1001: 1002: {0, _} = unregister(Alice, Config), 1003: 1004: assert_personal_data_via_rpc( 1005: Alice, [{offline, ["timestamp","from", "to", "packet"],[]}]) 1006: end). 1007: 1008: retrieve_pubsub_payloads(Config) -> 1009: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1010: [Node1={_,NodeName1}, Node2={_,NodeName2}] = pubsub_tools:create_node_names(2), 1011: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 1012: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 1013: {BinItem3, StringItem3} = item_content(<<"Item3Data">>), 1014: {BinOther, StringOther} = item_content(<<"OtherItemData">>), 1015: 1016: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, BinItem1}]), 1017: pubsub_tools:publish(Alice, <<"Item2">>, Node1, [{with_payload, BinItem2}]), 1018: pubsub_tools:publish(Alice, <<"Item3">>, Node1, [{with_payload, BinItem3}]), 1019: pubsub_tools:publish(Alice, <<"OtherItem">>, Node2, [{with_payload, BinOther}]), 1020: 1021: ExpectedItems = [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1), 1022: pubsub_payloads_row_map(NodeName1, "Item2", StringItem2), 1023: pubsub_payloads_row_map(NodeName1, "Item3", StringItem3), 1024: pubsub_payloads_row_map(NodeName2, "OtherItem", StringOther)], 1025: 1026: retrieve_and_validate_personal_data(Alice, Config, "pubsub_payloads", 1027: ["node_name", "item_id", "payload"], 1028: ExpectedItems, ["item_id"]) 1029: end). 1030: 1031: dont_retrieve_other_user_pubsub_payload(Config) -> 1032: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1033: [Node1={_,NodeName1}] = pubsub_tools:create_node_names(1), 1034: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1035: 1036: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 1037: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 1038: 1039: AffChange = [{Bob, <<"publish-only">>}], 1040: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1041: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, {true, BinItem1}}]), 1042: pubsub_tools:publish(Bob, <<"Item2">>, Node1, [{with_payload, {true, BinItem2}}]), 1043: 1044: retrieve_and_validate_personal_data( 1045: Alice, Config, "pubsub_payloads", ["node_name", "item_id", "payload"], 1046: [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1)]), 1047: 1048: retrieve_and_validate_personal_data( 1049: Bob, Config, "pubsub_payloads", ["node_name","item_id", "payload"], 1050: [pubsub_payloads_row_map(NodeName1, "Item2", StringItem2)]), 1051: 1052: pubsub_tools:delete_node(Alice, Node1, []) 1053: end). 1054: 1055: retrieve_created_pubsub_nodes(Config) -> 1056: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1057: [Node1={_,NodeName1}, Node2={_,NodeName2}, Node3={_,NodeName3}] = 1058: pubsub_tools:create_node_names(3), 1059: 1060: NodeNS = <<"myns">>, 1061: PepNode = make_pep_node_info(Alice, NodeNS), 1062: AccessModel = {<<"pubsub#access_model">>, <<"authorize">>}, 1063: 1064: pubsub_tools:create_nodes([ 1065: {Alice, Node1, []}, 1066: {Alice, Node2, []}, 1067: {Alice, PepNode, [{config, [AccessModel]}]}, 1068: {Bob, Node3, [{type, <<"push">>}]} 1069: ]), 1070: 1071: ExpectedHeader = ["node_name", "type"], 1072: 1073: retrieve_and_validate_personal_data( 1074: Alice, Config, "pubsub_nodes", ExpectedHeader, 1075: [pubsub_nodes_row_map(NodeNS, "pep"), 1076: pubsub_nodes_row_map(NodeName1, "flat"), 1077: pubsub_nodes_row_map(NodeName2, "flat")]), 1078: 1079: retrieve_and_validate_personal_data( 1080: Bob, Config, "pubsub_nodes", ExpectedHeader, 1081: [pubsub_nodes_row_map(NodeName3, "push")]), 1082: 1083: 1084: Nodes = [{Alice, PepNode}, {Alice, Node1}, {Alice, Node2}, {Bob, Node3}], 1085: [pubsub_tools:delete_node(User, Node, []) || {User, Node} <- Nodes] 1086: end). 1087: 1088: remove_pubsub_subscriptions(Config) -> 1089: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1090: Node = pubsub_tools:pubsub_node(), 1091: pubsub_tools:create_node(Alice, Node, []), 1092: pubsub_tools:subscribe(Bob, Node, []), 1093: 1094: {0, _} = unregister(Bob, Config), 1095: 1096: assert_personal_data_via_rpc(Bob, 1097: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1098: {pubsub_nodes,["node_name","type"],[]}, 1099: {pubsub_subscriptions,["node_name"],[]}]) 1100: end). 1101: 1102: retrieve_pubsub_subscriptions(Config) -> 1103: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1104: Node = {_Domain, NodeName} = pubsub_tools:pubsub_node(), 1105: pubsub_tools:create_node(Alice, Node, []), 1106: pubsub_tools:subscribe(Bob, Node, []), 1107: retrieve_and_validate_personal_data(Bob, Config, "pubsub_subscriptions", ["node_name"], 1108: [pubsub_subscription_row_map(NodeName)]), 1109: 1110: pubsub_tools:delete_node(Alice, Node, []) 1111: end). 1112: 1113: remove_pubsub_dont_remove_flat_pubsub_node(Config) -> 1114: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1115: Node1 = {_,NodeName} = pubsub_tools:pubsub_node_with_num(1), 1116: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1117: 1118: {0, _} = unregister(Alice, Config), 1119: 1120: assert_personal_data_via_rpc(Alice, 1121: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1122: {pubsub_nodes,["node_name","type"],[[NodeName, <<"flat">>]]}, 1123: {pubsub_subscriptions,["node_name"],[]}]) 1124: end). 1125: 1126: remove_pubsub_push_node(Config) -> 1127: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1128: [Node] = pubsub_tools:create_node_names(1), 1129: pubsub_tools:create_nodes([{Alice, Node, [{type, <<"push">>}]}]), 1130: 1131: Content = [ 1132: {<<"message-count">>, <<"1">>}, 1133: {<<"last-message-sender">>, <<"senderId">>}, 1134: {<<"last-message-body">>, <<"message body">>} 1135: ], 1136: Options = [ 1137: {<<"device_id">>, <<"sometoken">>}, 1138: {<<"service">>, <<"apns">>} 1139: ], 1140: 1141: PublishIQ = push_pubsub_SUITE:publish_iq(Bob, Node, Content, Options), 1142: escalus:send(Bob, PublishIQ), 1143: escalus:assert(is_iq_result, escalus:wait_for_stanza(Bob)), 1144: 1145: {0, _} = unregister(Alice, Config), 1146: 1147: assert_personal_data_via_rpc(Alice, [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1148: {pubsub_nodes,["node_name","type"],[]}, 1149: {pubsub_subscriptions,["node_name"],[]}]) 1150: end). 1151: 1152: remove_pubsub_pep_node(Config) -> 1153: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1154: NodeName = <<"myns">>, 1155: PepNode = make_pep_node_info(Alice, NodeName), 1156: 1157: pubsub_tools:create_nodes([ 1158: {Alice, PepNode, []} 1159: ]), 1160: 1161: {0, _} = unregister(Alice, Config), 1162: 1163: assert_personal_data_via_rpc(Alice, [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1164: {pubsub_nodes,["node_name","type"],[]}, 1165: {pubsub_subscriptions,["node_name"],[]}]) 1166: end). 1167: 1168: remove_pubsub_dont_remove_node_when_only_publisher(Config) -> 1169: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1170: Node1 = {_,NodeName} = pubsub_tools:pubsub_node_with_num(1), 1171: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1172: 1173: AffChange = [{Bob, <<"publish-only">>}], 1174: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1175: 1176: {0, _} = unregister(Bob, Config), 1177: 1178: assert_personal_data_via_rpc(Alice, 1179: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1180: {pubsub_nodes,["node_name","type"],[[NodeName, <<"flat">>]]}, 1181: {pubsub_subscriptions,["node_name"],[]}]) 1182: end). 1183: 1184: remove_pubsub_all_data(Config) -> 1185: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1186: [Node1={_,Name1}, Node2={_,Name2}, Node3={_,Name3}, Node4={_,Name4}] 1187: = pubsub_tools:create_node_names(4), 1188: PepNode = make_pep_node_info(Alice, <<"myns">>), 1189: pubsub_tools:create_nodes([ 1190: {Alice, Node1, []}, 1191: {Alice, Node2, []}, 1192: {Alice, PepNode, []}, 1193: {Bob, Node3, []}, 1194: {Bob, Node4, [{type, <<"push">>}]} 1195: ]), 1196: 1197: AffChange = [{Bob, <<"publish-only">>}], 1198: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1199: pubsub_tools:subscribe(Bob, Node2, []), 1200: pubsub_tools:subscribe(Alice, Node3, []), 1201: 1202: {BinItem1, _} = item_content(<<"Item1Data">>), 1203: {BinItem2, _} = item_content(<<"Item2Data">>), 1204: {BinItem3, _} = item_content(<<"Item3Data">>), 1205: {BinItem4, _} = item_content(<<"Item4Data">>), 1206: AliceToNode1 = <<"Alice publishes to Node1, but nobody is subscribed">>, 1207: AliceToNode2 = <<"Alice published to Node2, so Bob receives it">>, 1208: BobToNode1 = <<"Bob publishes to Node1, but nobody is subscribed">>, 1209: BobToNode3 = <<"Bob publishes to Node3, so Alice receives it">>, 1210: 1211: pubsub_tools:publish(Alice, AliceToNode1, Node1, [{with_payload, {true, BinItem1}}]), 1212: 1213: pubsub_tools:publish(Alice, AliceToNode2, Node2, [{with_payload, {true, BinItem2}}]), 1214: pubsub_tools:receive_item_notification(Bob, AliceToNode2, Node2, []), 1215: 1216: pubsub_tools:publish(Bob, BobToNode1, Node1, [{with_payload, {true, BinItem3}}]), 1217: 1218: pubsub_tools:publish(Bob, BobToNode3, Node3, [{with_payload, {true, BinItem4}}]), 1219: pubsub_tools:receive_item_notification(Alice, BobToNode3, Node3, []), 1220: 1221: {0, _} = unregister(Alice, Config), 1222: 1223: [{pubsub_payloads,["node_name","item_id","payload"], AlicePayloads}, 1224: {pubsub_nodes,["node_name","type"], AliceNodes}, 1225: {pubsub_subscriptions, ["node_name"], []}] 1226: = get_personal_data_via_rpc( 1227: Alice, [pubsub_payloads, pubsub_nodes, pubsub_subscriptions]), 1228: XmlBinItem1 = exml:to_binary(BinItem1), 1229: XmlBinItem2 = exml:to_binary(BinItem2), 1230: [[Name1, AliceToNode1, XmlBinItem1], 1231: [Name2, AliceToNode2, XmlBinItem2]] = lists:sort(AlicePayloads), 1232: [[Name1, <<"flat">>], [Name2, <<"flat">>]] = lists:sort(AliceNodes), 1233: 1234: [{pubsub_payloads,["node_name","item_id","payload"], Payloads}, 1235: {pubsub_nodes,["node_name","type"], Nodes}, 1236: {pubsub_subscriptions, ["node_name"], Subs}] 1237: = get_personal_data_via_rpc( 1238: Bob, [pubsub_payloads, pubsub_nodes, pubsub_subscriptions]), 1239: XmlBinItem3 = exml:to_binary(BinItem3), 1240: XmlBinItem4 = exml:to_binary(BinItem4), 1241: [[Name1, BobToNode1, XmlBinItem3], 1242: [Name3, BobToNode3, XmlBinItem4]] = lists:sort(Payloads), 1243: [[Name3, <<"flat">>], [Name4, <<"push">>]] = lists:sort(Nodes), 1244: [[Name2]] = Subs 1245: end). 1246: 1247: retrieve_all_pubsub_data(Config) -> 1248: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1249: [Node1={_,NodeName1}, Node2={_,NodeName2}, Node3={_,NodeName3}] = 1250: pubsub_tools:create_node_names(3), 1251: pubsub_tools:create_nodes([{Alice, Node1, []}, {Alice, Node2, []}, {Bob, Node3, []}]), 1252: 1253: AffChange = [{Bob, <<"publish-only">>}], 1254: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1255: pubsub_tools:subscribe(Bob, Node2, []), 1256: 1257: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 1258: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 1259: {BinItem3, StringItem3} = item_content(<<"Item3Data">>), 1260: 1261: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, {true, BinItem1}}]), 1262: pubsub_tools:publish(Alice, <<"Item2">>, Node2, [{with_payload, {true, BinItem2}}]), 1263: pubsub_tools:receive_item_notification(Bob, <<"Item2">>, Node2, []), 1264: pubsub_tools:publish(Bob, <<"Item3">>, Node1, [{with_payload, {true, BinItem3}}]), 1265: 1266: %% Bob has one subscription, one node created and one payload sent 1267: retrieve_and_validate_personal_data( 1268: Bob, Config, "pubsub_subscriptions", ["node_name"], 1269: [pubsub_subscription_row_map(NodeName2)]), 1270: 1271: retrieve_and_validate_personal_data( 1272: Bob, Config, "pubsub_nodes", ["node_name", "type"], 1273: [pubsub_nodes_row_map(NodeName3, "flat")]), 1274: 1275: retrieve_and_validate_personal_data( 1276: Bob, Config, "pubsub_payloads", ["node_name", "item_id", "payload"], 1277: [pubsub_payloads_row_map(NodeName1, "Item3", StringItem3)]), 1278: 1279: %% Alice has two nodes created and two payloads sent 1280: retrieve_and_validate_personal_data( 1281: Alice, Config, "pubsub_nodes", ["node_name", "type"], 1282: [pubsub_nodes_row_map(NodeName1, "flat"), 1283: pubsub_nodes_row_map(NodeName2, "flat")]), 1284: retrieve_and_validate_personal_data( 1285: Alice, Config, "pubsub_payloads", ["node_name", "item_id","payload"], 1286: [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1), 1287: pubsub_payloads_row_map(NodeName2, "Item2", StringItem2)]), 1288: 1289: dynamic_modules:ensure_modules(host_type(), pubsub_required_modules()), 1290: Nodes = [{Alice, Node1}, {Alice, Node2}, {Bob, Node3}], 1291: [pubsub_tools:delete_node(User, Node, []) || {User, Node} <- Nodes] 1292: end). 1293: 1294: 1295: retrieve_private_xml(Config) -> 1296: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1297: NS = <<"alice:gdpr:ns">>, 1298: Content = <<"dGhlcmUgYmUgZHJhZ29ucw==">>, 1299: send_and_assert_private_stanza(Alice, NS, Content), 1300: ExpectedHeader = ["ns", "xml"], 1301: ExpectedItems = [#{ "ns" => binary_to_list(NS), 1302: "xml" => [{contains, binary_to_list(NS)}, 1303: {contains, binary_to_list(Content)}] } 1304: ], 1305: retrieve_and_validate_personal_data( 1306: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1307: end). 1308: 1309: dont_retrieve_other_user_private_xml(Config) -> 1310: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1311: AliceNS = <<"alice:gdpr:ns">>, 1312: AliceContent = <<"To be or not to be">>, 1313: BobNS = <<"bob:gdpr:ns">>, 1314: BobContent = <<"This is the winter of our discontent">>, 1315: send_and_assert_private_stanza(Alice, AliceNS, AliceContent), 1316: send_and_assert_private_stanza(Bob, BobNS, BobContent), 1317: ExpectedHeader = ["ns", "xml"], 1318: ExpectedItems = [#{ "ns" => binary_to_list(AliceNS), 1319: "xml" => [{contains, binary_to_list(AliceNS)}, 1320: {contains, binary_to_list(AliceContent)}] } 1321: ], 1322: retrieve_and_validate_personal_data( 1323: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1324: end). 1325: 1326: retrieve_multiple_private_xmls(Config) -> 1327: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1328: NSsAndContents = [ 1329: {<<"alice:gdpr:ns1">>, <<"You do not talk about FIGHT CLUB.">>}, 1330: {<<"alice:gdpr:ns2">>, <<"You do not talk about FIGHT CLUB.">>}, 1331: {<<"alice:gdpr:ns3">>, <<"If someone says stop or goes limp," 1332: " taps out the fight is over.">>}, 1333: {<<"alice:gdpr:ns4">>, <<"Only two guys to a fight.">>}, 1334: {<<"alice:gdpr:ns5">>, <<"One fight at a time.">>} 1335: ], 1336: lists:foreach( 1337: fun({NS, Content}) -> 1338: send_and_assert_private_stanza(Alice, NS, Content) 1339: end, NSsAndContents), 1340: ExpectedHeader = ["ns", "xml"], 1341: ExpectedItems = lists:map( 1342: fun({NS, Content}) -> 1343: #{ "ns" => binary_to_list(NS), 1344: "xml" => [{contains, binary_to_list(NS)}, 1345: {contains, binary_to_list(Content)}]} 1346: end, NSsAndContents), 1347: 1348: retrieve_and_validate_personal_data( 1349: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1350: end). 1351: 1352: retrieve_inbox_muclight(Config) -> 1353: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1354: muc_light_helper:given_muc_light_room(?ROOM, Alice, [{Bob, member}]), 1355: Domain = muc_light_helper:muc_host(), 1356: 1357: Body = <<"Are you sure?">>, 1358: Res = muc_light_helper:when_muc_light_message_is_sent(Alice, ?ROOM, Body, <<"9128">>), 1359: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob], Res), 1360: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1361: ExpectedAliceItems = [#{ "jid" => [{contains, <<?ROOM/binary, $@, Domain/binary>>}], 1362: "unread_count" => "0" }], 1363: %% MUC Light affiliations are also stored in inbox 1364: ExpectedBobItems = [#{ "jid" => [{contains, <<?ROOM/binary, $@, Domain/binary>>}], 1365: "unread_count" => "2" }], 1366: 1367: retrieve_and_validate_personal_data( 1368: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1369: retrieve_and_validate_personal_data( 1370: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1371: 1372: StanzaDestroy = escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_DESTROY, []), room_bin_jid(?ROOM)), 1373: escalus:send(Alice, StanzaDestroy), 1374: ok 1375: end). 1376: 1377: retrieve_inbox_muc(Config) -> 1378: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1379: {ok, Room} = given_fresh_muc_room(Alice#client.props, []), 1380: Users = [Alice, Bob], 1381: Msg = <<"Hi Room!">>, 1382: Id = <<"MyID">>, 1383: RoomAddr = muc_helper:room_address(Room), 1384: 1385: inbox_helper:enter_room(Room, Users), 1386: inbox_helper:make_members(Room, Alice, [Bob]), 1387: Stanza = escalus_stanza:set_id( 1388: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1389: escalus:send(Bob, Stanza), 1390: inbox_helper:wait_for_groupchat_msg(Users), 1391: 1392: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1393: 1394: ExpectedBobItems = [#{ 1395: "content" => [{contains, Msg}], 1396: "jid" => [{contains, RoomAddr}], 1397: "unread_count" => "0" }], 1398: 1399: retrieve_and_validate_personal_data( 1400: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1401: ExpectedAliceItems = [#{ 1402: "content" => [{contains, Msg}], 1403: "jid" => [{contains, RoomAddr}], 1404: "unread_count" => "1" }], 1405: 1406: retrieve_and_validate_personal_data( 1407: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1408: ok 1409: end). 1410: 1411: retrieve_inbox(Config) -> 1412: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1413: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 1414: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 1415: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 1416: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 1417: Body = <<"With spam?">>, 1418: send_and_assert_is_chat_message(Bob, Alice, Body), 1419: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1420: ExpectedAliceItems = [#{ "content" => [{contains, Body}], 1421: "jid" => [{contains, BobS}, 1422: {contains, BobU}], 1423: "unread_count" => "1" }], 1424: ExpectedBobItems = [#{ "content" => [{contains, Body}], 1425: "jid" => [{contains, AliceS}, 1426: {contains, AliceU}], 1427: "unread_count" => "0" }], 1428: retrieve_and_validate_personal_data( 1429: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1430: retrieve_and_validate_personal_data( 1431: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems) 1432: end). 1433: 1434: remove_inbox(Config) -> 1435: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1436: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 1437: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 1438: Body = <<"With spam?">>, 1439: send_and_assert_is_chat_message(Bob, Alice, Body), 1440: 1441: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1442: 1443: {0, _} = unregister(Alice, Config), 1444: 1445: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1446: 1447: ExpectedBobItems = [ 1448: #{ "content" => [{contains, Body}], 1449: "jid" => [{contains, AliceS}, 1450: {contains, AliceU}], 1451: "unread_count" => "0" } 1452: ], 1453: retrieve_and_validate_personal_data( 1454: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems) 1455: end). 1456: 1457: remove_inbox_muclight(Config) -> 1458: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1459: Domain = muc_light_helper:muc_host(), 1460: Room = <<"ttt2">>, 1461: muc_light_helper:given_muc_light_room(Room, Alice, [{Bob, member}]), 1462: 1463: Body = <<"Are you sure?">>, 1464: Res = muc_light_helper:when_muc_light_message_is_sent(Alice, Room , Body, <<"9128">>), 1465: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob], Res), 1466: 1467: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1468: 1469: {0, _} = unregister(Alice, Config), 1470: 1471: %% MUC Light affiliations are also stored in inbox 1472: %% 1. Added to the room 1473: %% 2. Message 1474: %% 3. Aff change: Alice -> none, Bob -> owner 1475: %% Writing aff changes to inbox is enabled by default 1476: ExpectedBobItems = [#{ 1477: "jid" => [{contains, <<Room/binary, $@, Domain/binary>>}], 1478: "unread_count" => "3" } 1479: ], 1480: 1481: retrieve_and_validate_personal_data( 1482: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1483: 1484: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1485: 1486: timer:sleep(5000), 1487: StanzaDestroy = escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_DESTROY, []), 1488: room_bin_jid(Room)), 1489: escalus:send(Alice, StanzaDestroy), 1490: ok 1491: end). 1492: 1493: remove_inbox_muc(Config) -> 1494: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1495: {ok, Room} = given_fresh_muc_room(Alice#client.props, []), 1496: 1497: Users = [Alice, Bob], 1498: Msg = <<"Hi Room!">>, 1499: Id = <<"MyID">>, 1500: RoomAddr = muc_helper:room_address(Room), 1501: 1502: inbox_helper:enter_room(Room, Users), 1503: inbox_helper:make_members(Room, Alice, [Bob]), 1504: Stanza = escalus_stanza:set_id( 1505: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1506: escalus:send(Bob, Stanza), 1507: inbox_helper:wait_for_groupchat_msg(Users), 1508: 1509: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1510: 1511: {0, _} = unregister(Alice, Config), 1512: 1513: escalus:wait_for_stanza(Bob), 1514: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1515: 1516: ExpectedBobItems = [#{ 1517: "content" => [{contains, Msg}], 1518: "jid" => [{contains, RoomAddr}], 1519: "unread_count" => "0" }], 1520: 1521: retrieve_and_validate_personal_data( 1522: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1523: ok 1524: end). 1525: 1526: retrieve_inbox_for_multiple_messages(Config) -> 1527: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1528: Bodies = [ <<"Nobody exists on purpose.">>, 1529: <<"Nobody belongs anywhere.">>, 1530: <<"We're all going to die.">>, 1531: <<"Come watch TV.">>], 1532: lists:foreach(fun(Body) -> send_and_assert_is_chat_message(Bob, Alice, Body) end, Bodies), 1533: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 1534: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 1535: 1536: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1537: ExpectedAliceItems = [#{ "content" => [{contains, lists:last(Bodies)}], 1538: "jid" => [{contains, BobS}, 1539: {contains, BobU}], 1540: "unread_count" => integer_to_list(length(Bodies)) }], 1541: retrieve_and_validate_personal_data( 1542: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems) 1543: end). 1544: 1545: retrieve_logs(Config) -> 1546: escalus:fresh_story(Config, [{alice, 1}], 1547: fun(Alice) -> 1548: User = string:to_lower(binary_to_list(escalus_client:username(Alice))), 1549: Domain = string:to_lower(binary_to_list(escalus_client:server(Alice))), 1550: JID = string:to_upper(binary_to_list(escalus_client:short_jid(Alice))), 1551: #{node := MIM2NodeName} = MIM2Node = distributed_helper:mim2(), 1552: mongoose_helper:successful_rpc(net_kernel, connect_node, [MIM2NodeName]), 1553: mongoose_helper:successful_rpc(MIM2Node, error_logger, error_msg, 1554: ["event=disturbance_in_the_force, jid=~s", [JID]]), 1555: Dir = request_and_unzip_personal_data(User, Domain, Config), 1556: Filename = filename:join(Dir, "logs-" ++ atom_to_list(MIM2NodeName) ++ ".txt"), 1557: {ok, Content} = file:read_file(Filename), 1558: {match, _} = re:run(Content, "disturbance_in_the_force") 1559: end). 1560: 1561: %% ------------------------- Data retrieval - Negative case ------------------------- 1562: 1563: data_is_not_retrieved_for_missing_user(Config) -> 1564: {Filename, 1, _} = retrieve_personal_data("non-person", "oblivion", Config), 1565: {error, _} = file:read_file_info(Filename). 1566: 1567: %% ------------------------------------------------------------- 1568: %% Internal functions 1569: %% ------------------------------------------------------------- 1570: 1571: assert_personal_data_via_rpc(Client, ExpectedPersonalDataEntries) -> 1572: ExpectedKeys = [ Key || {Key, _, _} <- ExpectedPersonalDataEntries ], 1573: 1574: %% We use wait_until here, because e.g. the deletion in ElasticSearch 1575: %% sometimes is applied with a delay (i.e. immediately after successful deletion 1576: %% the data retrieval still returned valid entries) 1577: mongoose_helper:wait_until( 1578: fun() -> 1579: get_personal_data_via_rpc(Client, ExpectedKeys) 1580: end, ExpectedPersonalDataEntries). 1581: 1582: get_personal_data_via_rpc(Client, ExpectedKeys) -> 1583: ClientU = escalus_utils:jid_to_lower(escalus_client:username(Client)), 1584: ClientS = escalus_utils:jid_to_lower(escalus_client:server(Client)), 1585: AllPersonalData = mongoose_helper:successful_rpc( 1586: service_admin_extra_gdpr, get_data_from_modules, [ClientU, ClientS]), 1587: %% We don't use lists:filter/2 because this line also ensures order 1588: [ lists:keyfind(Key, 1, AllPersonalData) || Key <- ExpectedKeys ]. 1589: 1590: retrieve_and_validate_personal_data(User, Config, FilePrefix, ExpectedHeader, ExpectedItems) -> 1591: Dir = retrieve_all_personal_data(User, Config), 1592: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, ExpectedHeader). 1593: 1594: retrieve_and_validate_personal_data(User, Config, FilePrefix, ExpectedHeader, ExpectedItems, SortBy) -> 1595: Dir = retrieve_all_personal_data(User, Config), 1596: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, SortBy). 1597: 1598: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, SortBy) -> 1599: PersonalCSV = decode_personal_data(Dir, FilePrefix), 1600: UnsortedMaps = csv_to_maps(ExpectedHeader, PersonalCSV), 1601: PersonalMaps = lists:sort(get_sort_fn(SortBy), UnsortedMaps), 1602: try validate_personal_maps(PersonalMaps, ExpectedItems) of 1603: _ -> ok 1604: catch 1605: C:R:S -> 1606: ct:fail(#{ 1607: class => C, 1608: reason => R, 1609: stacktrace => S, 1610: sorted_by => SortBy, 1611: personal_maps => PersonalMaps, 1612: expected_items => ExpectedItems 1613: }) 1614: end. 1615: 1616: 1617: get_sort_fn(SortBy) when is_list(SortBy) -> 1618: %% if SortBy is [], than original list remains unsorted. 1619: fun(Map1, Map2) -> compare_maps(SortBy, Map1, Map2) end; 1620: get_sort_fn(SortFn) when is_function(SortFn, 2) -> 1621: SortFn. 1622: 1623: compare_maps([], _, _) -> true; 1624: compare_maps([Key | T], Map1, Map2) -> 1625: #{Key:=Val1} = Map1, 1626: #{Key:=Val2} = Map2, 1627: if 1628: Val1 =:= Val2 -> compare_maps(T, Map1, Map2); 1629: Val1 > Val2 -> false; 1630: Val1 < Val2 -> true 1631: end. 1632: 1633: muc_msg_first(MucJid) -> 1634: MucJidNormalized = escalus_utils:jid_to_lower(to_binary(MucJid)), 1635: N = erlang:byte_size(MucJidNormalized), 1636: fun(#{"from" := JID1}, #{"from" := JID2}) -> 1637: Jid1Normalized = escalus_utils:jid_to_lower(to_binary(JID1)), 1638: Jid2Normalized = escalus_utils:jid_to_lower(to_binary(JID2)), 1639: case {Jid1Normalized, Jid2Normalized} of 1640: {<<MucJidNormalized:N/binary, _/binary>>, <<MucJidNormalized:N/binary, _/binary>>} -> 1641: Jid1Normalized =< Jid2Normalized; 1642: {<<MucJidNormalized:N/binary, _/binary>>, _} -> 1643: true; 1644: {_, <<MucJidNormalized:N/binary, _/binary>>} -> 1645: false; 1646: {_, _} -> 1647: Jid1Normalized =< Jid2Normalized 1648: end 1649: end. 1650: 1651: csv_to_maps(ExpectedHeader, [ExpectedHeader | Rows]) -> 1652: lists:foldl(fun(Row, Maps) -> [ csv_row_to_map(ExpectedHeader, Row) | Maps ] end, [], Rows). 1653: 1654: csv_row_to_map(Header, Row) -> 1655: maps:from_list(lists:zip(Header, Row)). 1656: 1657: validate_personal_maps(PersonalMaps, ExpectedItems) -> 1658: validate_sorted_personal_maps(PersonalMaps, ExpectedItems). 1659: 1660: validate_sorted_personal_maps([], []) -> ok; 1661: validate_sorted_personal_maps(UnexpectedRecords, []) -> 1662: erlang:error("Unexpected records left ~p", [UnexpectedRecords]); 1663: validate_sorted_personal_maps([Map | RMaps], [Checks | RChecks]) -> 1664: maps:fold(fun(K, Conditions, _) -> 1665: validate_personal_item(maps:get(K, Map), Conditions) 1666: end, ok, Checks), 1667: validate_sorted_personal_maps(RMaps, RChecks). 1668: 1669: validate_personal_item(_Value, []) -> 1670: ok; 1671: validate_personal_item(ExactValue, ExactValue) -> 1672: ok; 1673: validate_personal_item(Value, [{jid, ExpectedValue} | RConditions]) -> 1674: JID = escalus_utils:jid_to_lower(to_binary(Value)), 1675: JID = escalus_utils:jid_to_lower(to_binary(ExpectedValue)), 1676: validate_personal_item(Value, RConditions); 1677: validate_personal_item(Value, [{contains, String} | RConditions]) -> 1678: {match, _} = re:run(Value, String), 1679: validate_personal_item(Value, RConditions); 1680: validate_personal_item(Value, [{validate, Validator} | RConditions]) when is_function(Validator) -> 1681: true = Validator(Value), 1682: validate_personal_item(Value, RConditions). 1683: 1684: to_binary(List) when is_list(List) -> list_to_binary(List); 1685: to_binary(Binary) when is_binary(Binary) -> Binary. 1686: 1687: decode_personal_data(Dir, FilePrefix) -> 1688: CSVPath = filename:join(Dir, FilePrefix ++ ".csv"), 1689: {ok, Content} = file:read_file(CSVPath), 1690: % We expect non-empty list because it must contain at least header with columns names 1691: [_ | _] = csv:decode_binary(Content). 1692: 1693: refute_personal_data(Client, Config, FilePrefix) -> 1694: Dir = retrieve_all_personal_data(Client, Config), 1695: refute_personal_data(Dir, FilePrefix). 1696: 1697: refute_personal_data(Dir, FilePrefix) -> 1698: CSVPath = filename:join(Dir, FilePrefix ++ ".csv"), 1699: false = filelib:is_regular(CSVPath). 1700: 1701: retrieve_all_personal_data(Client, Config) -> 1702: User = escalus_client:username(Client), 1703: Domain = escalus_client:server(Client), 1704: request_and_unzip_personal_data(User, Domain, Config). 1705: 1706: request_and_unzip_personal_data(User, Domain, Config) -> 1707: {Filename, 0, _} = retrieve_personal_data(User, Domain, Config), 1708: FullPath = get_mim_cwd() ++ "/" ++ Filename, 1709: Dir = make_dir_name(Filename, User), 1710: ct:log("extracting logs ~s", [Dir]), 1711: {ok, _} = zip:extract(FullPath, [{cwd, Dir}]), 1712: Dir. 1713: 1714: make_dir_name(Filename, User) when is_binary(User) -> 1715: make_dir_name(Filename, binary_to_list(User)); 1716: make_dir_name(Filename, User) when is_list(User) -> 1717: Filename ++ "." ++ User ++ ".unzipped". 1718: 1719: retrieve_personal_data(User, Domain, Config) -> 1720: Filename = random_filename(Config), 1721: {CommandOutput, Code} = mongooseimctl("retrieve_personal_data", 1722: [User, Domain, Filename], Config), 1723: {Filename, Code, CommandOutput}. 1724: 1725: unregister(Client, Config) -> 1726: User = escalus_client:username(Client), 1727: Domain = escalus_client:server(Client), 1728: {CommandOutput, Code} = mongooseimctl("unregister", [User, Domain], Config), 1729: {Code, CommandOutput}. 1730: 1731: random_filename(Config) -> 1732: TCName = atom_to_list(?config(tc_name, Config)), 1733: TCName ++ "." ++ integer_to_list(erlang:system_time()) ++ ".zip". 1734: 1735: get_mim_cwd() -> 1736: {ok, Cwd} = rpc(mim(), file, get_cwd, []), 1737: Cwd. 1738: 1739: delete_files() -> 1740: Cwd = get_mim_cwd(), 1741: {ok, Filenames} = rpc(mim(), file, list_dir, [Cwd]), 1742: FilteredFilenames = lists:filter( 1743: fun is_file_to_be_deleted/1, 1744: Filenames), 1745: lists:foreach( 1746: fun(Filename) -> rpc(mim(), file, delete, [Cwd ++ "/" ++ Filename]) end, 1747: FilteredFilenames), 1748: ok. 1749: 1750: is_file_to_be_deleted(Filename) -> 1751: DeletableRegexes = ["\.csv", "\.zip"], 1752: lists:any( 1753: fun(Regex) -> 1754: re:run(Filename, Regex) =/= nomatch 1755: end, 1756: DeletableRegexes). 1757: 1758: pubsub_payloads_row_map(Node, ItemId, Payload) -> 1759: #{"node_name" => binary_to_list(Node), "item_id" => ItemId, "payload" => Payload}. 1760: 1761: pubsub_nodes_row_map(Node, Type) -> 1762: #{"node_name" => binary_to_list(Node), "type" => Type}. 1763: 1764: pubsub_subscription_row_map(Node) -> 1765: #{"node_name" => binary_to_list(Node)}. 1766: 1767: make_pep_node_info(Client, NodeName) -> 1768: {escalus_utils:jid_to_lower(escalus_utils:get_short_jid(Client)), NodeName}. 1769: 1770: item_content(Data) -> 1771: Bin = item_content_xml(Data), 1772: {Bin, binary_to_list(exml:to_binary(Bin))}. 1773: 1774: item_content_xml(Data) -> 1775: #xmlel{name = <<"entry">>, 1776: attrs = [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>}], 1777: children = [#xmlcdata{content = Data}]}. 1778: 1779: send_and_assert_private_stanza(User, NS, Content) -> 1780: XML = #xmlel{ name = <<"fingerprint">>, 1781: attrs = [{<<"xmlns">>, NS}], 1782: children = [#xmlcdata{ content = Content }]}, 1783: PrivateStanza = escalus_stanza:private_set(XML), 1784: escalus_client:send(User, PrivateStanza), 1785: escalus:assert(is_iq_result, [PrivateStanza], escalus_client:wait_for_stanza(User)). 1786: 1787: send_and_assert_is_chat_message(UserFrom, UserTo, Body) -> 1788: escalus:send(UserFrom, escalus_stanza:chat_to(UserTo, Body)), 1789: Msg = escalus:wait_for_stanza(UserTo), 1790: escalus:assert(is_chat_message, [Body], Msg). 1791: 1792: validate_datetime(TimeStr) -> 1793: [Date, Time] = string:tokens(TimeStr, "T"), 1794: validate_date(Date), 1795: validate_time(Time). 1796: 1797: validate_date(Date) -> 1798: [Y, M, D] = string:tokens(Date, "-"), 1799: Date1 = {list_to_integer(Y), list_to_integer(M), list_to_integer(D)}, 1800: calendar:valid_date(Date1). 1801: 1802: validate_time(Time) -> 1803: [T | _] = string:tokens(Time, "Z"), 1804: validate_time1(T). 1805: 1806: 1807: validate_time1(Time) -> 1808: [H, M, S] = string:tokens(Time, ":"), 1809: check_list([{H, 24}, {M, 60}, {S, 60}]). 1810: 1811: check_list(List) -> 1812: lists:all(fun({V, L}) -> I = list_to_integer(V), I >= 0 andalso I < L end, List). 1813: 1814: expected_header(mod_roster) -> ["jid", "name", "subscription", 1815: "ask", "groups", "askmessage", "xs"]. 1816: 1817: given_fresh_muc_room(UserSpec, RoomOpts) -> 1818: Username = proplists:get_value(username, UserSpec), 1819: RoomName = muc_helper:fresh_room_name(Username), 1820: From = muc_helper:generate_rpc_jid({user, UserSpec}), 1821: muc_helper:create_instant_room(RoomName, From, Username, RoomOpts), 1822: {ok, RoomName}. 1823: 1824: send_receive_muc_private_message(Room, Domain, {User1, Nickname1}, {User2, Nickname2}, Text) -> 1825: RoomPrivAddrUser1 = <<Room/binary, "@", Domain/binary, "/", Nickname1/binary>>, 1826: RoomPrivAddrUser2 = <<Room/binary, "@", Domain/binary, "/", Nickname2/binary>>, 1827: Msg = escalus_stanza:chat_to(RoomPrivAddrUser2, Text), 1828: escalus:send(User1, Msg), 1829: PMStanza = escalus:wait_for_stanza(User2), 1830: escalus:assert(is_chat_message_from_to, 1831: [RoomPrivAddrUser1, escalus_client:full_jid(User2), Text], PMStanza), 1832: {RoomPrivAddrUser1, RoomPrivAddrUser2}.