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