1: %%============================================================================== 2: %% Copyright 2012 Erlang Solutions Ltd. 3: %% 4: %% Licensed under the Apache License, Version 2.0 (the "License"); 5: %% you may not use this file except in compliance with the License. 6: %% You may obtain a copy of the License at 7: %% 8: %% http://www.apache.org/licenses/LICENSE-2.0 9: %% 10: %% Unless required by applicable law or agreed to in writing, software 11: %% distributed under the License is distributed on an "AS IS" BASIS, 12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13: %% See the License for the specific language governing permissions and 14: %% limitations under the License. 15: %%============================================================================== 16: -module(mam_SUITE). 17: 18: %% CT callbacks 19: -export([all/0, 20: groups/0, 21: suite/0, 22: init_per_suite/1, 23: end_per_suite/1, 24: init_per_group/2, 25: end_per_group/2, 26: init_per_testcase/2, 27: end_per_testcase/2]). 28: 29: %% Tests 30: -export([no_elements/1, 31: only_stanzaid/1, 32: same_stanza_id/1, 33: muc_no_elements/1, 34: muc_only_stanzaid/1, 35: mam_service_discovery/1, 36: mam_service_discovery_to_client_bare_jid/1, 37: mam_service_discovery_to_different_client_bare_jid_results_in_error/1, 38: muc_service_discovery/1, 39: easy_archive_request/1, 40: easy_archive_request_for_the_receiver/1, 41: message_sent_to_yourself/1, 42: text_search_query_fails_if_disabled/1, 43: pagination_simple_enforced/1, 44: text_search_is_not_available/1, 45: easy_text_search_request/1, 46: long_text_search_request/1, 47: text_search_is_available/1, 48: muc_message_with_stanzaid/1, 49: retract_muc_message/1, 50: retract_muc_message_on_stanza_id/1, 51: retract_wrong_muc_message/1, 52: muc_text_search_request/1, 53: muc_archive_request/1, 54: muc_multiple_devices/1, 55: muc_protected_message/1, 56: muc_deny_protected_room_access/1, 57: muc_allow_access_to_owner/1, 58: muc_sanitize_x_user_in_non_anon_rooms/1, 59: muc_delete_x_user_in_anon_rooms/1, 60: muc_show_x_user_to_moderators_in_anon_rooms/1, 61: muc_show_x_user_for_your_own_messages_in_anon_rooms/1, 62: range_archive_request/1, 63: range_archive_request_not_empty/1, 64: limit_archive_request/1, 65: metadata_archive_request/1, 66: metadata_archive_request_empty/1, 67: metadata_archive_request_one_message/1, 68: muc_metadata_archive_request/1, 69: muc_metadata_archive_request_empty/1, 70: muc_metadata_archive_request_one_message/1, 71: prefs_set_request/1, 72: retrieve_form_fields/1, 73: retrieve_form_fields_extra_features/1, 74: prefs_set_cdata_request/1, 75: query_get_request/1, 76: pagination_first5/1, 77: pagination_last5/1, 78: pagination_offset5/1, 79: pagination_first0/1, 80: pagination_last0/1, 81: pagination_offset5_max0/1, 82: pagination_before10/1, 83: pagination_after10/1, 84: pagination_flipped_page/1, 85: pagination_simple_before10/1, 86: pagination_simple_before3/1, 87: pagination_simple_before6/1, 88: pagination_simple_before1_pagesize0/1, 89: pagination_simple_before2_pagesize0/1, 90: pagination_simple_after5/1, 91: pagination_simple_after10/1, 92: pagination_simple_after12/1, 93: pagination_last_after_id5/1, 94: pagination_last_after_id5_before_id11/1, 95: pagination_empty_rset/1, 96: pagination_first_page_after_id4/1, 97: pagination_last_page_after_id4/1, 98: pagination_border_flipped_page/1, 99: server_returns_item_not_found_for_before_filter_with_nonexistent_id/1, 100: server_returns_item_not_found_for_after_filter_with_nonexistent_id/1, 101: server_returns_item_not_found_for_after_filter_with_invalid_id/1, 102: server_returns_item_not_found_for_ids_filter_with_nonexistent_id/1, 103: muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id/1, 104: %% complete_flag_cases tests 105: before_complete_false_last5/1, 106: before_complete_false_before10/1, 107: before_complete_true_before1/1, 108: before_complete_true_before5/1, 109: before_complete_true_before6/1, 110: after_complete_false_first_page/1, 111: after_complete_false_after2/1, 112: after_complete_false_after9/1, 113: after_complete_true_after10/1, 114: after_complete_true_after11/1, 115: archived/1, 116: message_with_stanzaid/1, 117: retract_message/1, 118: retract_message_on_stanza_id/1, 119: retract_wrong_message/1, 120: ignore_bad_retraction/1, 121: filter_forwarded/1, 122: offline_message/1, 123: nostore_hint/1, 124: querying_for_all_messages_with_jid/1, 125: query_messages_by_ids/1, 126: simple_query_messages_by_ids/1, 127: muc_query_messages_by_ids/1, 128: muc_simple_query_messages_by_ids/1, 129: muc_querying_for_all_messages/1, 130: muc_querying_for_all_messages_with_jid/1, 131: muc_light_service_discovery_stored_in_pm/1, 132: muc_light_easy/1, 133: muc_light_shouldnt_modify_pm_archive/1, 134: muc_light_stored_in_pm_if_allowed_to/1, 135: muc_light_include_groupchat_filter/1, 136: muc_light_no_pm_stored_include_groupchat_filter/1, 137: muc_light_include_groupchat_messages_by_default/1, 138: muc_light_chat_markers_are_archived_if_enabled/1, 139: muc_light_chat_markers_are_not_archived_if_disabled/1, 140: muc_light_failed_to_decode_message_in_database/1, 141: pm_failed_to_decode_message_in_database/1, 142: messages_filtered_when_prefs_default_policy_is_always/1, 143: messages_filtered_when_prefs_default_policy_is_never/1, 144: messages_filtered_when_prefs_default_policy_is_roster/1, 145: run_set_and_get_prefs_cases/1, 146: check_user_exist/1, 147: metric_incremented_on_archive_request/1, 148: metric_incremented_when_store_message/1, 149: metrics_incremented_for_async_pools/1, 150: archive_chat_markers/1, 151: dont_archive_chat_markers/1, 152: save_unicode_messages/1, 153: unicode_messages_can_be_extracted/1, 154: stanza_id_is_appended_to_carbons/1]). 155: 156: -import(distributed_helper, [mim/0, 157: require_rpc_nodes/1, 158: subhost_pattern/1, 159: rpc/4]). 160: 161: -import(muc_helper, 162: [muc_host/0, 163: room_address/1, room_address/2, 164: stanza_muc_enter_room/2, 165: stanza_to_room/2]). 166: 167: -import(mam_helper, 168: [rpc_apply/3, 169: get_prop/2, 170: is_cassandra_enabled/1, 171: is_elasticsearch_enabled/1, 172: is_mam_possible/1, 173: respond_iq/1, 174: print_configuration_not_supported/2, 175: start_alice_room/1, 176: destroy_room/1, 177: send_muc_rsm_messages/1, 178: send_rsm_messages/1, 179: clean_archives/1, 180: mam04_props/0, 181: mam06_props/0, 182: bootstrap_archive/1, 183: muc_bootstrap_archive/1, 184: start_alice_protected_room/1, 185: start_alice_anonymous_room/1, 186: maybe_wait_for_archive/1, 187: stanza_archive_request/2, 188: stanza_text_search_archive_request/3, 189: stanza_include_groupchat_request/3, 190: stanza_fetch_by_id_request/3, 191: stanza_fetch_by_id_request/4, 192: stanza_date_range_archive_request_not_empty/3, 193: wait_archive_respond/1, 194: wait_for_complete_archive_response/3, 195: assert_respond_size/2, 196: assert_respond_query_id/3, 197: parse_result_iq/1, 198: nick_to_jid/2, 199: stanza_filtered_by_jid_request/2, 200: nick/1, 201: respond_messages/1, 202: parse_forwarded_message/1, 203: login_send_presence/2, 204: assert_only_one_of_many_is_equal/2, 205: add_nostore_hint/1, 206: assert_not_stored/2, 207: has_x_user_element/1, 208: stanza_date_range_archive_request/1, 209: make_iso_time/1, 210: stanza_retrieve_form_fields/2, 211: stanza_limit_archive_request/1, 212: rsm_send/3, 213: stanza_page_archive_request/3, 214: stanza_flip_page_archive_request/3, 215: wait_empty_rset/2, 216: wait_message_range/2, 217: wait_message_range/3, 218: wait_message_range/5, 219: message_id/2, 220: get_pre_generated_msgs_ids/2, 221: get_received_msgs_ids/1, 222: stanza_prefs_set_request/4, 223: stanza_prefs_get_request/1, 224: stanza_query_get_request/1, 225: parse_prefs_result_iq/1, 226: mam_ns_binary/0, 227: mam_ns_binary_v04/0, 228: mam_ns_binary_v06/0, 229: mam_ns_binary_extended/0, 230: retract_ns/0, 231: retract_tombstone_ns/0, 232: groupchat_field_ns/0, 233: groupchat_available_ns/0, 234: data_validate_ns/0, 235: make_alice_and_bob_friends/2, 236: run_prefs_case/6, 237: prefs_cases2/0, 238: default_policy/1, 239: get_all_messages/2, 240: parse_messages/1, 241: run_set_and_get_prefs_case/4, 242: muc_light_host/0, 243: host_type/0, 244: config_opts/1, 245: stanza_metadata_request/0 246: ]). 247: 248: -import(muc_light_helper, 249: [given_muc_light_room/3, 250: when_muc_light_message_is_sent/4, 251: then_muc_light_message_is_received_by/2, 252: when_muc_light_affiliations_are_set/3, 253: then_muc_light_affiliations_are_received_by/2, 254: when_archive_query_is_sent/3, 255: then_archive_response_is/3]). 256: 257: -import(domain_helper, [domain/0]). 258: 259: -include("mam_helper.hrl"). 260: -include_lib("common_test/include/ct.hrl"). 261: -include_lib("eunit/include/eunit.hrl"). 262: -include_lib("exml/include/exml_stream.hrl"). 263: 264: %%-------------------------------------------------------------------- 265: %% Suite configuration 266: %%-------------------------------------------------------------------- 267: 268: 269: 270: configurations() -> 271: case ct_helper:is_ct_running() of 272: true -> 273: configurations_for_running_ct(); 274: false -> 275: all_configurations() 276: end. 277: 278: %% Called by test-runner for autocompletion 279: all_configurations() -> 280: cassandra_configs(true) 281: ++ rdbms_configs(true, mnesia) 282: ++ elasticsearch_configs(true). 283: 284: configurations_for_running_ct() -> 285: cassandra_configs(is_cassandra_enabled(host_type())) 286: ++ rdbms_configs(mongoose_helper:is_rdbms_enabled(host_type()), ct_helper:get_internal_database()) 287: ++ elasticsearch_configs(is_elasticsearch_enabled(host_type())). 288: 289: rdbms_configs(true, mnesia) -> 290: [rdbms, 291: rdbms_easy, 292: rdbms_async_pool, 293: rdbms_mnesia, 294: rdbms_async_cache, 295: rdbms_cache, 296: rdbms_mnesia_cache 297: ]; 298: rdbms_configs(true, cets) -> 299: [rdbms, 300: rdbms_easy, 301: rdbms_async_pool, 302: rdbms_async_cache, 303: rdbms_cache 304: ]; 305: rdbms_configs(_, _) -> 306: []. 307: 308: cassandra_configs(true) -> 309: [cassandra]; 310: cassandra_configs(_) -> 311: []. 312: 313: elasticsearch_configs(true) -> 314: [elasticsearch]; 315: elasticsearch_configs(_) -> 316: []. 317: 318: basic_group_names() -> 319: [ 320: mam_all, 321: chat_markers, 322: muc_all, 323: muc_light, 324: prefs_cases, 325: impl_specific, 326: disabled_text_search, 327: disabled_complex_queries, 328: disabled_retraction 329: ]. 330: 331: all() -> 332: Reasons = 333: case ct_helper:is_ct_running() of 334: true -> 335: case is_mam_possible(host_type()) of 336: false -> [require_rdbms]; 337: true -> [] 338: end; 339: false -> 340: [] 341: end, 342: case Reasons of 343: [] -> 344: tests(); 345: [_|_] -> 346: {skip, Reasons} 347: end. 348: 349: tests() -> 350: [{group, full_group(C, G)} 351: || C <- configurations(), G <- basic_group_names(), 352: not is_skipped(C, G)]. 353: 354: groups() -> 355: [{full_group(C, G), Props, Tests} 356: || C <- configurations(), {G, Props, Tests} <- basic_groups(), 357: not is_skipped(C, G)]. 358: 359: is_skipped(_, _) -> 360: false. 361: 362: basic_groups() -> 363: [ 364: {mam_all, [parallel], 365: [{mam_metrics, [], mam_metrics_cases()}, 366: {mam04, [parallel], mam_cases() ++ [retrieve_form_fields] ++ text_search_cases()}, 367: {mam06, [parallel], mam_cases() ++ [retrieve_form_fields_extra_features] 368: ++ stanzaid_cases() ++ retract_cases() 369: ++ metadata_cases() ++ fetch_specific_msgs_cases()}, 370: {nostore, [parallel], nostore_cases()}, 371: {archived, [parallel], archived_cases()}, 372: {configurable_archiveid, [], configurable_archiveid_cases()}, 373: {rsm_all, [], %% not parallel, because we want to limit concurrency 374: [ 375: %% Functions mod_mam_utils:make_fin_element_v03/5 and make_fin_element/5 376: %% are almost the same, so don't need to test all versions of 377: %% MAM protocol with complete_flag_cases. 378: %% 379: %% We need a separate group for complete_flag_cases, 380: %% because there should not be a lot of cases running 381: %% using parallel_story with the same user. 382: %% Otherwise there would be a lot of presences sent between devices. 383: {rsm04, [parallel], rsm_cases()}, 384: {rsm04_comp, [parallel], complete_flag_cases()}, 385: {with_rsm04, [parallel], with_rsm_cases()}]}]}, 386: {muc_all, [parallel], 387: [{muc04, [parallel], muc_cases() ++ muc_text_search_cases()}, 388: {muc06, [parallel], muc_cases() ++ muc_stanzaid_cases() ++ muc_retract_cases() 389: ++ muc_metadata_cases() ++ muc_fetch_specific_msgs_cases()}, 390: {muc_configurable_archiveid, [], muc_configurable_archiveid_cases()}, 391: {muc_rsm_all, [parallel], 392: [{muc_rsm04, [parallel], muc_rsm_cases()}]}]}, 393: {muc_light, [], muc_light_cases()}, 394: {prefs_cases, [parallel], prefs_cases()}, 395: {impl_specific, [], impl_specific()}, 396: {disabled_text_search, [], 397: [{mam04, [], disabled_text_search_cases()}]}, 398: {disabled_complex_queries, [], 399: [{mam04, [], disabled_complex_queries_cases()}]}, 400: {chat_markers, [parallel], 401: [{mam04, [parallel], chat_markers_cases()}]}, 402: {disabled_retraction, [], 403: [{mam06, [parallel], disabled_retract_cases() ++ 404: [mam_service_discovery, 405: mam_service_discovery_to_client_bare_jid, 406: mam_service_discovery_to_different_client_bare_jid_results_in_error]}]}, 407: {muc_disabled_retraction, [], 408: [{muc06, [parallel], disabled_muc_retract_cases() ++ 409: [muc_service_discovery]}]} 410: ]. 411: 412: chat_markers_cases() -> 413: [archive_chat_markers, 414: dont_archive_chat_markers]. 415: 416: mam_metrics_cases() -> 417: [metric_incremented_on_archive_request, 418: metric_incremented_when_store_message]. 419: 420: mam_cases() -> 421: [mam_service_discovery, 422: mam_service_discovery_to_client_bare_jid, 423: mam_service_discovery_to_different_client_bare_jid_results_in_error, 424: easy_archive_request, 425: easy_archive_request_for_the_receiver, 426: message_sent_to_yourself, 427: range_archive_request, 428: range_archive_request_not_empty, 429: limit_archive_request, 430: querying_for_all_messages_with_jid, 431: unicode_messages_can_be_extracted 432: ]. 433: 434: text_search_cases() -> 435: [ 436: easy_text_search_request, 437: long_text_search_request, 438: text_search_is_available, 439: save_unicode_messages 440: ]. 441: 442: disabled_text_search_cases() -> 443: [ 444: text_search_is_not_available, 445: text_search_query_fails_if_disabled 446: ]. 447: 448: disabled_complex_queries_cases() -> 449: [ 450: pagination_simple_enforced 451: ]. 452: 453: metadata_cases() -> 454: [ 455: metadata_archive_request, 456: metadata_archive_request_empty, 457: metadata_archive_request_one_message 458: ]. 459: 460: fetch_specific_msgs_cases() -> 461: [ 462: query_messages_by_ids, 463: simple_query_messages_by_ids, 464: server_returns_item_not_found_for_ids_filter_with_nonexistent_id 465: ]. 466: 467: muc_text_search_cases() -> 468: [ 469: muc_text_search_request 470: ]. 471: 472: archived_cases() -> 473: [archived, 474: filter_forwarded, 475: metrics_incremented_for_async_pools 476: ]. 477: 478: stanzaid_cases() -> 479: [message_with_stanzaid, 480: stanza_id_is_appended_to_carbons]. 481: 482: retract_cases() -> 483: [retract_message, 484: retract_wrong_message, 485: ignore_bad_retraction]. 486: 487: disabled_retract_cases() -> 488: [retract_message]. 489: 490: nostore_cases() -> 491: [offline_message, 492: nostore_hint]. 493: 494: muc_cases() -> 495: [muc_service_discovery, 496: muc_archive_request, 497: muc_multiple_devices, 498: muc_protected_message, 499: muc_deny_protected_room_access, 500: muc_allow_access_to_owner, 501: muc_sanitize_x_user_in_non_anon_rooms, 502: muc_delete_x_user_in_anon_rooms, 503: muc_show_x_user_to_moderators_in_anon_rooms, 504: muc_show_x_user_for_your_own_messages_in_anon_rooms, 505: muc_querying_for_all_messages, 506: muc_querying_for_all_messages_with_jid 507: ]. 508: 509: muc_stanzaid_cases() -> 510: [muc_message_with_stanzaid]. 511: 512: muc_retract_cases() -> 513: [retract_muc_message, 514: retract_muc_message_on_stanza_id, 515: retract_wrong_muc_message]. 516: 517: disabled_muc_retract_cases() -> 518: [retract_muc_message]. 519: 520: muc_configurable_archiveid_cases() -> 521: [ 522: muc_no_elements, 523: muc_only_stanzaid 524: ]. 525: 526: muc_metadata_cases() -> 527: [ 528: muc_metadata_archive_request, 529: muc_metadata_archive_request_empty, 530: muc_metadata_archive_request_one_message 531: ]. 532: 533: muc_fetch_specific_msgs_cases() -> 534: [ 535: muc_query_messages_by_ids, 536: muc_simple_query_messages_by_ids, 537: muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id 538: ]. 539: 540: configurable_archiveid_cases() -> 541: [no_elements, 542: only_stanzaid, 543: same_stanza_id, 544: retract_message_on_stanza_id 545: ]. 546: 547: muc_light_cases() -> 548: [ 549: muc_light_service_discovery_stored_in_pm, 550: muc_light_easy, 551: muc_light_shouldnt_modify_pm_archive, 552: muc_light_stored_in_pm_if_allowed_to, 553: muc_light_include_groupchat_filter, 554: muc_light_no_pm_stored_include_groupchat_filter, 555: muc_light_include_groupchat_messages_by_default, 556: muc_light_chat_markers_are_archived_if_enabled, 557: muc_light_chat_markers_are_not_archived_if_disabled, 558: muc_light_failed_to_decode_message_in_database 559: ]. 560: 561: muc_rsm_cases() -> 562: rsm_cases(). 563: 564: with_rsm_cases() -> 565: rsm_cases(). 566: 567: rsm_cases() -> 568: [pagination_first5, 569: pagination_last5, 570: pagination_offset5, 571: pagination_first0, 572: pagination_last0, 573: pagination_offset5_max0, 574: pagination_before10, 575: pagination_after10, 576: pagination_empty_rset, 577: pagination_flipped_page, 578: %% Border cases 579: pagination_last_after_id5, 580: pagination_last_after_id5_before_id11, 581: pagination_first_page_after_id4, 582: pagination_last_page_after_id4, 583: pagination_border_flipped_page, 584: %% Simple cases 585: pagination_simple_before10, 586: pagination_simple_before3, 587: pagination_simple_before6, 588: pagination_simple_before1_pagesize0, 589: pagination_simple_before2_pagesize0, 590: pagination_simple_after5, 591: pagination_simple_after10, 592: pagination_simple_after12, 593: %% item_not_found response for nonexistent message ID in before/after filters 594: server_returns_item_not_found_for_before_filter_with_nonexistent_id, 595: server_returns_item_not_found_for_after_filter_with_nonexistent_id, 596: server_returns_item_not_found_for_after_filter_with_invalid_id]. 597: 598: complete_flag_cases() -> 599: [before_complete_false_last5, 600: before_complete_false_before10, 601: before_complete_true_before1, 602: before_complete_true_before5, 603: before_complete_true_before6, 604: after_complete_false_first_page, 605: after_complete_false_after2, 606: after_complete_false_after9, 607: after_complete_true_after10, 608: after_complete_true_after11]. 609: 610: prefs_cases() -> 611: [prefs_set_request, 612: prefs_set_cdata_request, 613: query_get_request, 614: messages_filtered_when_prefs_default_policy_is_always, 615: messages_filtered_when_prefs_default_policy_is_never, 616: messages_filtered_when_prefs_default_policy_is_roster, 617: run_set_and_get_prefs_cases]. 618: 619: impl_specific() -> 620: [check_user_exist, 621: pm_failed_to_decode_message_in_database]. 622: 623: suite() -> 624: require_rpc_nodes([mim]) ++ escalus:suite(). 625: 626: init_per_suite(Config) -> 627: muc_helper:load_muc(), 628: mam_helper:prepare_for_suite( 629: increase_limits( 630: delete_users([{escalus_user_db, {module, escalus_ejabberd}} 631: | escalus:init_per_suite(Config)]))). 632: 633: end_per_suite(Config) -> 634: muc_helper:unload_muc(), 635: %% Next function creates a lot of sessions... 636: escalus_fresh:clean(), 637: %% and this function kicks them without waiting... 638: mongoose_helper:kick_everyone(), 639: %% so we don't have sessions anymore and other tests will not fail 640: mongoose_helper:restore_config(Config), 641: escalus:end_per_suite(Config). 642: 643: user_names() -> 644: [alice, bob, kate, carol]. 645: 646: create_users(Config) -> 647: escalus:create_users(Config, escalus:get_users(user_names())). 648: 649: delete_users(Config) -> 650: escalus:delete_users(Config, escalus:get_users(user_names())). 651: 652: increase_limits(Config) -> 653: Config1 = mongoose_helper:backup_and_set_config(Config, increased_limits()), 654: rpc_apply(mongoose_shaper, reset_all_shapers, [host_type()]), 655: Config1. 656: 657: increased_limits() -> 658: #{[shaper, mam_shaper] => #{max_rate => 10000}, 659: [shaper, normal] => #{max_rate => 10000000}, 660: [shaper, fast] => #{max_rate => 10000000}, 661: [{access, host_type()}, max_user_sessions] => [#{acl => all, value => 10000}]}. 662: 663: init_per_group(mam04, Config) -> 664: [{props, mam04_props()}|Config]; 665: init_per_group(mam06, Config) -> 666: [{props, mam06_props()}|Config]; 667: 668: init_per_group(rsm_all, Config) -> 669: Config1 = escalus_fresh:create_users(Config, [{N, 1} || N <- user_names()]), 670: send_rsm_messages(Config1); 671: init_per_group(rsm04, Config) -> 672: [{props, mam04_props()}|Config]; 673: init_per_group(rsm04_comp, Config) -> 674: [{props, mam04_props()}|Config]; 675: init_per_group(with_rsm04, Config) -> 676: [{props, mam04_props()}, {with_rsm, true}|Config]; 677: 678: init_per_group(nostore, Config) -> 679: Config; 680: init_per_group(archived, Config) -> 681: Config; 682: init_per_group(mam_metrics, Config) -> 683: Config; 684: init_per_group(muc04, Config) -> 685: [{props, mam04_props()}, {with_rsm, true}|Config]; 686: init_per_group(muc06, Config) -> 687: [{props, mam06_props()}, {with_rsm, true}|Config]; 688: 689: init_per_group(muc_configurable_archiveid, Config) -> 690: dynamic_modules:save_modules(host_type(), Config); 691: init_per_group(configurable_archiveid, Config) -> 692: dynamic_modules:save_modules(host_type(), Config); 693: 694: init_per_group(muc_rsm_all, Config) -> 695: Config1 = escalus_fresh:create_users(Config, [{N, 1} || N <- user_names()]), 696: Config2 = start_alice_room(Config1), 697: Config3 = send_muc_rsm_messages(Config2), 698: [{muc_rsm, true} | Config3]; 699: init_per_group(muc_rsm04, Config) -> 700: [{props, mam04_props()}|Config]; 701: 702: init_per_group(Group, ConfigIn) -> 703: C = configuration(Group), 704: B = basic_group(Group), 705: {ModulesToStart, Config0} = required_modules_for_group(C, B, ConfigIn), 706: ct:pal("Init per group ~p; configuration ~p; basic group ~p", [Group, C, B]), 707: Config01 = dynamic_modules:save_modules(host_type(), Config0), 708: dynamic_modules:ensure_modules(host_type(), ModulesToStart), 709: Config1 = do_init_per_group(C, Config01), 710: [{basic_group, B}, {configuration, C} | init_state(C, B, Config1)]. 711: 712: do_init_per_group(C, ConfigIn) -> 713: Config0 = create_users(ConfigIn), 714: case C of 715: cassandra -> 716: [{archive_wait, 1500} | Config0]; 717: elasticsearch -> 718: [{archive_wait, 2500} | Config0]; 719: _ -> 720: Config0 721: end. 722: 723: end_per_group(G, Config) when G == rsm_all; G == nostore; 724: G == mam04; G == rsm04; G == with_rsm04; G == muc04; G == muc_rsm04; G == rsm04_comp; 725: G == muc06; G == mam06; 726: G == archived; G == mam_metrics -> 727: Config; 728: end_per_group(muc_configurable_archiveid, Config) -> 729: dynamic_modules:restore_modules(Config), 730: Config; 731: end_per_group(configurable_archiveid, Config) -> 732: dynamic_modules:restore_modules(Config), 733: Config; 734: end_per_group(muc_rsm_all, Config) -> 735: destroy_room(Config); 736: end_per_group(Group, Config) -> 737: C = configuration(Group), 738: B = basic_group(Group), 739: Config0 = end_state(C, B, Config), 740: Config1 = dynamic_modules:restore_modules(Config0), 741: escalus_fresh:clean(), 742: delete_users(Config1). 743: 744: required_modules_for_group(C, muc_light, Config) -> 745: Extra = mam_opts_for_conf(C), 746: MUCHost = subhost_pattern(muc_light_helper:muc_host_pattern()), 747: Opts = config_opts(Extra#{pm => #{}, muc => #{host => MUCHost}}), 748: Config1 = maybe_set_wait(C, [muc, pm], [{mam_meta_opts, Opts} | Config]), 749: Backend = mongoose_helper:mnesia_or_rdbms_backend(), 750: {[{mod_muc_light, config_parser_helper:mod_config(mod_muc_light, #{backend => Backend})}, 751: {mod_mam, Opts}], Config1}; 752: required_modules_for_group(C, BG, Config) when BG =:= muc_all; 753: BG =:= muc_disabled_retraction -> 754: Extra = maps:merge(mam_opts_for_conf(C), mam_opts_for_base_group(BG)), 755: MUCHost = subhost_pattern(muc_domain(Config)), 756: Opts = config_opts(Extra#{muc => #{host => MUCHost}}), 757: Config1 = maybe_set_wait(C, [muc], [{mam_meta_opts, Opts} | Config]), 758: {[{mod_mam, Opts}], Config1}; 759: required_modules_for_group(C, BG, Config) -> 760: Extra = maps:merge(mam_opts_for_conf(C), mam_opts_for_base_group(BG)), 761: Opts = config_opts(Extra#{pm => #{}}), 762: Config1 = maybe_set_wait(C, [pm], [{mam_meta_opts, Opts} | Config]), 763: {[{mod_mam, Opts}], Config1}. 764: 765: maybe_set_wait(C, Types, Config) when C =:= rdbms_async_pool; 766: C =:= rdbms_async_cache -> 767: [{wait_for_parallel_writer, Types} | Config]; 768: maybe_set_wait(_C, _, Config) -> 769: Config. 770: 771: mam_opts_for_conf(elasticsearch) -> 772: #{backend => elasticsearch, 773: user_prefs_store => mnesia}; 774: mam_opts_for_conf(cassandra) -> 775: #{backend => cassandra, 776: user_prefs_store => cassandra}; 777: mam_opts_for_conf(rdbms_easy) -> 778: EasyOpts = #{db_jid_format => mam_jid_rfc, 779: db_message_format => mam_message_xml}, 780: maps:merge(EasyOpts, mam_opts_for_conf(rdbms)); 781: mam_opts_for_conf(rdbms) -> 782: #{user_prefs_store => rdbms, 783: async_writer => #{enabled => false}, 784: cache_users => false}; 785: mam_opts_for_conf(rdbms_async_pool) -> 786: #{user_prefs_store => rdbms, 787: async_writer => #{flush_interval => 1}, 788: cache_users => false}; 789: mam_opts_for_conf(rdbms_mnesia) -> 790: #{user_prefs_store => mnesia, 791: async_writer => #{enabled => false}, 792: cache_users => false}; 793: mam_opts_for_conf(rdbms_cache) -> 794: #{user_prefs_store => rdbms, 795: async_writer => #{enabled => false}}; 796: mam_opts_for_conf(rdbms_async_cache) -> 797: #{user_prefs_store => rdbms, 798: async_writer => #{flush_interval => 1}}; 799: mam_opts_for_conf(rdbms_mnesia_cache) -> 800: #{user_prefs_store => mnesia, 801: async_writer => #{enabled => false}}. 802: 803: muc_domain(Config) -> 804: proplists:get_value(muc_domain, Config, muc_helper:muc_host_pattern()). 805: 806: mam_opts_for_base_group(disabled_text_search) -> 807: #{full_text_search => false}; 808: mam_opts_for_base_group(disabled_complex_queries) -> 809: #{enforce_simple_queries => true}; 810: mam_opts_for_base_group(BG) when BG =:= disabled_retraction; 811: BG =:= muc_disabled_retraction -> 812: #{message_retraction => false}; 813: mam_opts_for_base_group(chat_markers) -> 814: #{archive_chat_markers => true}; 815: mam_opts_for_base_group(_BG) -> 816: #{}. 817: 818: init_state(_, muc_all, Config) -> 819: Config; 820: init_state(C, muc_light, Config) -> 821: clean_archives(Config), 822: init_state(C, muc04, Config); 823: init_state(_C, prefs_cases, Config) -> 824: Config; 825: init_state(_, _, Config) -> 826: clean_archives(Config). 827: 828: end_state(C, muc_light, Config) -> 829: muc_light_helper:clear_db(host_type()), 830: end_state(C, generic, Config); 831: end_state(_, _, Config) -> 832: Config. 833: 834: init_per_testcase(C=metrics_incremented_for_async_pools, Config) -> 835: case ?config(configuration, Config) of 836: rdbms_async_pool -> 837: escalus:init_per_testcase(C, clean_archives(Config)); 838: _ -> 839: {skip, "Not an async-pool test"} 840: end; 841: init_per_testcase(C=metric_incremented_when_store_message, ConfigIn) -> 842: Config = case ?config(configuration, ConfigIn) of 843: rdbms_async_pool -> 844: MongooseMetrics = [ 845: {[global, data, rdbms, default], 846: [{recv_oct, '>'}, {send_oct, '>'}]} 847: ], 848: [{mongoose_metrics, MongooseMetrics} | ConfigIn]; 849: _ -> 850: ConfigIn 851: end, 852: escalus:init_per_testcase(C, clean_archives(Config)); 853: init_per_testcase(C=filter_forwarded, Config) -> 854: escalus:init_per_testcase(C, Config); 855: init_per_testcase(C=querying_for_all_messages_with_jid, Config) -> 856: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 857: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 858: init_per_testcase(C, Config) when C =:= query_messages_by_ids; 859: C =:= simple_query_messages_by_ids; 860: C =:= server_returns_item_not_found_for_ids_filter_with_nonexistent_id -> 861: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 862: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 863: init_per_testcase(C=archived, Config) -> 864: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 865: escalus:init_per_testcase(C, Config1); 866: init_per_testcase(C, Config) when C =:= retract_message; 867: C =:= retract_wrong_message; 868: C =:= ignore_bad_retraction -> 869: skip_if_retraction_not_supported(Config, fun() -> escalus:init_per_testcase(C, Config) end); 870: init_per_testcase(C=retract_message_on_stanza_id, Config) -> 871: Init = fun() -> 872: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 873: escalus:init_per_testcase(C, Config) 874: end, 875: skip_if_retraction_not_supported(Config, Init); 876: init_per_testcase(C=offline_message, Config) -> 877: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 878: escalus:init_per_testcase(C, Config1); 879: init_per_testcase(C=nostore_hint, Config) -> 880: escalus:init_per_testcase(C, Config); 881: init_per_testcase(C, Config) when C =:= muc_query_messages_by_ids; 882: C =:= muc_simple_query_messages_by_ids; 883: C =:= muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id -> 884: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 885: escalus:init_per_testcase(C, muc_bootstrap_archive(start_alice_room(Config1))); 886: init_per_testcase(C=muc_querying_for_all_messages, Config) -> 887: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 888: escalus:init_per_testcase(C, 889: muc_bootstrap_archive(start_alice_room(Config1))); 890: init_per_testcase(C=muc_querying_for_all_messages_with_jid, Config) -> 891: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 892: escalus:init_per_testcase(C, 893: muc_bootstrap_archive(start_alice_room(Config1))); 894: init_per_testcase(C=muc_archive_request, Config) -> 895: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 896: Config2 = %% Check that metric is incremented on MUC flushed 897: case ?config(configuration, Config1) of 898: rdbms_async_pool -> 899: MongooseMetrics = [{['_', 'modMucMamFlushed'], changed}], 900: [{mongoose_metrics, MongooseMetrics} | Config1]; 901: _ -> 902: Config1 903: end, 904: escalus:init_per_testcase(C, start_alice_room(Config2)); 905: init_per_testcase(C=muc_no_elements, Config) -> 906: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 907: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 908: escalus:init_per_testcase(C, start_alice_room(Config1)); 909: init_per_testcase(C=muc_only_stanzaid, Config) -> 910: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 911: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 912: escalus:init_per_testcase(C, start_alice_room(Config1)); 913: init_per_testcase(C=no_elements, Config) -> 914: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 915: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 916: escalus:init_per_testcase(C, start_alice_room(Config1)); 917: init_per_testcase(C=only_stanzaid, Config) -> 918: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 919: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 920: escalus:init_per_testcase(C, start_alice_room(Config1)); 921: init_per_testcase(C=same_stanza_id, Config) -> 922: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 923: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 924: escalus:init_per_testcase(C, start_alice_room(Config1)); 925: init_per_testcase(C=muc_message_with_stanzaid, Config) -> 926: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 927: escalus:init_per_testcase(C, start_alice_room(Config1)); 928: init_per_testcase(C, Config) when C =:= muc_light_failed_to_decode_message_in_database; 929: C =:= pm_failed_to_decode_message_in_database -> 930: case proplists:get_value(configuration, Config) of 931: elasticsearch -> 932: {skip, "elasticsearch does not support encodings"}; 933: _ -> 934: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 935: escalus:init_per_testcase(C, Config) 936: end; 937: init_per_testcase(C, Config) when C =:= retract_muc_message; 938: C =:= retract_muc_message_on_stanza_id; 939: C =:= retract_wrong_muc_message -> 940: Init = fun() -> 941: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 942: escalus:init_per_testcase(C, start_alice_room(Config1)) 943: end, 944: skip_if_retraction_not_supported(Config, Init); 945: init_per_testcase(C=muc_multiple_devices, Config) -> 946: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 947: escalus:init_per_testcase(C, start_alice_room(Config1)); 948: init_per_testcase(C=muc_protected_message, Config) -> 949: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 950: escalus:init_per_testcase(C, start_alice_room(Config1)); 951: init_per_testcase(C=muc_deny_protected_room_access, Config) -> 952: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 953: escalus:init_per_testcase(C, start_alice_protected_room(Config1)); 954: init_per_testcase(C=muc_allow_access_to_owner, Config) -> 955: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 956: escalus:init_per_testcase(C, start_alice_protected_room(Config1)); 957: init_per_testcase(C=muc_sanitize_x_user_in_non_anon_rooms, Config) -> 958: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 959: escalus:init_per_testcase(C, start_alice_room(Config1)); 960: init_per_testcase(C=muc_delete_x_user_in_anon_rooms, Config) -> 961: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 962: escalus:init_per_testcase(C, start_alice_anonymous_room(Config1)); 963: init_per_testcase(C=muc_show_x_user_to_moderators_in_anon_rooms, Config) -> 964: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 965: escalus:init_per_testcase(C, start_alice_anonymous_room(Config1)); 966: init_per_testcase(C=muc_show_x_user_for_your_own_messages_in_anon_rooms, Config) -> 967: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 968: escalus:init_per_testcase(C, start_alice_anonymous_room(Config1)); 969: init_per_testcase(C=pagination_simple_enforced, Config) -> 970: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 971: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 972: init_per_testcase(C=range_archive_request_not_empty, Config) -> 973: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 974: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 975: init_per_testcase(C=limit_archive_request, Config) -> 976: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 977: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 978: init_per_testcase(C=metadata_archive_request, Config) -> 979: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}, {carol, 1}]), 980: escalus:init_per_testcase(C, bootstrap_archive(Config1)); 981: init_per_testcase(C=metadata_archive_request_empty, Config) -> 982: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 983: escalus:init_per_testcase(C, Config1); 984: init_per_testcase(C=metadata_archive_request_one_message, Config) -> 985: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 986: escalus:init_per_testcase(C, Config1); 987: init_per_testcase(C=muc_metadata_archive_request, Config) -> 988: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 989: escalus:init_per_testcase(C, 990: muc_bootstrap_archive(start_alice_room(Config1))); 991: init_per_testcase(C=muc_metadata_archive_request_empty, Config) -> 992: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 993: escalus:init_per_testcase(C, start_alice_room(Config1)); 994: init_per_testcase(C=muc_metadata_archive_request_one_message, Config) -> 995: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 996: escalus:init_per_testcase(C, start_alice_room(Config1)); 997: init_per_testcase(C, Config) when C =:= muc_light_include_groupchat_filter; 998: C =:= muc_light_no_pm_stored_include_groupchat_filter; 999: C =:= muc_light_include_groupchat_messages_by_default -> 1000: Init = 1001: fun() -> 1002: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 1003: escalus:init_per_testcase(C, Config) 1004: end, 1005: skip_if_include_groupchat_not_supported(Config, Init); 1006: init_per_testcase(C=easy_text_search_request, Config) -> 1007: skip_if_cassandra(Config, fun() -> escalus:init_per_testcase(C, Config) end); 1008: init_per_testcase(C=long_text_search_request, Config) -> 1009: skip_if_cassandra(Config, fun() -> escalus:init_per_testcase(C, Config) end); 1010: init_per_testcase(C=save_unicode_messages, Config) -> 1011: skip_if_cassandra(Config, fun() -> escalus:init_per_testcase(C, Config) end); 1012: init_per_testcase(C=muc_text_search_request, Config) -> 1013: Init = 1014: fun() -> 1015: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 1016: escalus:init_per_testcase(C, start_alice_room(Config1)) 1017: end, 1018: 1019: skip_if_cassandra(Config, Init); 1020: init_per_testcase(C = muc_light_service_discovery_stored_in_pm, Config) -> 1021: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 1022: escalus:init_per_testcase(C, Config); 1023: init_per_testcase(C = muc_light_stored_in_pm_if_allowed_to, Config) -> 1024: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 1025: escalus:init_per_testcase(C, Config); 1026: init_per_testcase(C, Config) when C =:= muc_light_easy; 1027: C =:= muc_light_shouldnt_modify_pm_archive; 1028: C =:= muc_light_chat_markers_are_archived_if_enabled; 1029: C =:= muc_light_chat_markers_are_not_archived_if_disabled-> 1030: dynamic_modules:ensure_modules(host_type(), required_modules(C, Config)), 1031: escalus:init_per_testcase(C, Config); 1032: init_per_testcase(C=archive_chat_markers, Config) -> 1033: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 1034: escalus:init_per_testcase(C, Config1); 1035: init_per_testcase(C=dont_archive_chat_markers, Config) -> 1036: Config1 = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 1037: escalus:init_per_testcase(C, Config1); 1038: init_per_testcase(CaseName, Config) -> 1039: escalus:init_per_testcase(CaseName, Config). 1040: 1041: skip_if_include_groupchat_not_supported(Config, Init) -> 1042: case ?config(configuration, Config) of 1043: cassandra -> 1044: {skip, "include_groupchat field is not supported for cassandra backend"}; 1045: _ -> 1046: Init() 1047: end. 1048: 1049: skip_if_retraction_not_supported(Config, Init) -> 1050: ConfList = rdbms_configs(true, ct_helper:get_internal_database()), 1051: case lists:member(?config(configuration, Config), ConfList) of 1052: false -> 1053: {skip, "message retraction not supported"}; 1054: true -> 1055: Init() 1056: end. 1057: 1058: skip_if_cassandra(Config, Init) -> 1059: case ?config(configuration, Config) of 1060: cassandra -> 1061: {skip, "full text search is not implemented for cassandra backend"}; 1062: _ -> 1063: Init() 1064: end. 1065: 1066: end_per_testcase(C=muc_text_search_request, Config) -> 1067: destroy_room(Config), 1068: escalus:end_per_testcase(C, Config); 1069: end_per_testcase(C=muc_archive_request, Config) -> 1070: destroy_room(Config), 1071: escalus:end_per_testcase(C, Config); 1072: end_per_testcase(C=muc_multiple_devices, Config) -> 1073: destroy_room(Config), 1074: escalus:end_per_testcase(C, Config); 1075: end_per_testcase(C=muc_protected_message, Config) -> 1076: destroy_room(Config), 1077: escalus:end_per_testcase(C, Config); 1078: end_per_testcase(C=muc_deny_protected_room_access, Config) -> 1079: destroy_room(Config), 1080: escalus:end_per_testcase(C, Config); 1081: end_per_testcase(C=muc_allow_access_to_owner, Config) -> 1082: destroy_room(Config), 1083: escalus:end_per_testcase(C, Config); 1084: end_per_testcase(C=muc_sanitize_x_user_in_non_anon_rooms, Config) -> 1085: destroy_room(Config), 1086: escalus:end_per_testcase(C, Config); 1087: end_per_testcase(C=muc_delete_x_user_in_anon_rooms, Config) -> 1088: destroy_room(Config), 1089: escalus:end_per_testcase(C, Config); 1090: end_per_testcase(C=muc_show_x_user_to_moderators_in_anon_rooms, Config) -> 1091: destroy_room(Config), 1092: escalus:end_per_testcase(C, Config); 1093: end_per_testcase(C=muc_show_x_user_for_your_own_messages_in_anon_rooms, Config) -> 1094: destroy_room(Config), 1095: escalus:end_per_testcase(C, Config); 1096: end_per_testcase(C, Config) when C =:= muc_query_messages_by_ids; 1097: C =:= muc_simple_query_messages_by_ids; 1098: C =:= muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id -> 1099: destroy_room(Config), 1100: escalus:end_per_testcase(C, Config); 1101: end_per_testcase(C=muc_querying_for_all_messages, Config) -> 1102: destroy_room(Config), 1103: escalus:end_per_testcase(C, Config); 1104: end_per_testcase(C=muc_querying_for_all_messages_with_jid, Config) -> 1105: destroy_room(Config), 1106: escalus:end_per_testcase(C, Config); 1107: end_per_testcase(C=muc_message_with_stanzaid, Config) -> 1108: destroy_room(Config), 1109: escalus:end_per_testcase(C, Config); 1110: end_per_testcase(C, Config) when C =:= retract_muc_message; 1111: C =:= retract_muc_message_on_stanza_id; 1112: C =:= retract_wrong_muc_message -> 1113: destroy_room(Config), 1114: escalus:end_per_testcase(C, Config); 1115: end_per_testcase(C=muc_no_elements, Config) -> 1116: destroy_room(Config), 1117: escalus:end_per_testcase(C, Config); 1118: end_per_testcase(C=muc_only_stanzaid, Config) -> 1119: destroy_room(Config), 1120: escalus:end_per_testcase(C, Config); 1121: end_per_testcase(C=muc_metadata_archive_request, Config) -> 1122: destroy_room(Config), 1123: escalus:end_per_testcase(C, Config); 1124: end_per_testcase(C=muc_metadata_archive_request_empty, Config) -> 1125: destroy_room(Config), 1126: escalus:end_per_testcase(C, Config); 1127: end_per_testcase(C=muc_metadata_archive_request_one_message, Config) -> 1128: destroy_room(Config), 1129: escalus:end_per_testcase(C, Config); 1130: end_per_testcase(CaseName, Config) -> 1131: escalus:end_per_testcase(CaseName, Config). 1132: 1133: %% Module configuration per testcase 1134: 1135: required_modules(CaseName, Config) when CaseName =:= muc_light_service_discovery_stored_in_pm; 1136: CaseName =:= muc_light_stored_in_pm_if_allowed_to; 1137: CaseName =:= muc_light_include_groupchat_messages_by_default; 1138: CaseName =:= muc_light_no_pm_stored_include_groupchat_filter; 1139: CaseName =:= muc_light_include_groupchat_filter -> 1140: Opts = #{pm := PM} = ?config(mam_meta_opts, Config), 1141: NewOpts = Opts#{pm := PM#{archive_groupchats => true}}, 1142: [{mod_mam, NewOpts}]; 1143: required_modules(muc_light_chat_markers_are_archived_if_enabled, Config) -> 1144: Opts = #{muc := MUC} = ?config(mam_meta_opts, Config), 1145: NewOpts = Opts#{muc := MUC#{archive_chat_markers => true}}, 1146: [{mod_mam, NewOpts}]; 1147: required_modules(muc_no_elements, Config) -> 1148: Opts = #{muc := MUC} = ?config(mam_meta_opts, Config), 1149: NewOpts = Opts#{muc := MUC#{no_stanzaid_element => true}}, 1150: [{mod_mam, NewOpts}]; 1151: required_modules(muc_light_failed_to_decode_message_in_database, Config) -> 1152: Opts = #{muc := MUC} = ?config(mam_meta_opts, Config), 1153: NewOpts = Opts#{muc := MUC#{db_message_format => mam_message_eterm}}, 1154: [{mod_mam, NewOpts}]; 1155: required_modules(pm_failed_to_decode_message_in_database, Config) -> 1156: Opts = #{pm := PM} = ?config(mam_meta_opts, Config), 1157: NewOpts = Opts#{pm := PM#{db_message_format => mam_message_eterm}}, 1158: [{mod_mam, NewOpts}]; 1159: required_modules(muc_only_stanzaid, Config) -> 1160: Opts = ?config(mam_meta_opts, Config), 1161: [{mod_mam, Opts}]; 1162: % configurable_archiveid basic group 1163: required_modules(no_elements, Config) -> 1164: Opts = #{pm := PM} = ?config(mam_meta_opts, Config), 1165: NewOpts = Opts#{pm := PM#{no_stanzaid_element => true}}, 1166: [{mod_mam, NewOpts}]; 1167: required_modules(CaseName, Config) when CaseName =:= same_stanza_id; 1168: CaseName =:= retract_message_on_stanza_id -> 1169: Opts = #{pm := PM} = ?config(mam_meta_opts, Config), 1170: NewOpts = Opts#{pm := PM#{same_mam_id_for_peers => true}}, 1171: [{mod_mam, NewOpts}]; 1172: required_modules(_, Config) -> 1173: Opts = ?config(mam_meta_opts, Config), 1174: [{mod_mam, Opts}]. 1175: 1176: pm_with_db_message_format_xml(Config) -> 1177: Opts = #{pm := PM} = ?config(mam_meta_opts, Config), 1178: NewOpts = Opts#{pm := PM#{db_message_format => mam_message_xml}}, 1179: [{mod_mam, NewOpts}]. 1180: 1181: muc_with_db_message_format_xml(Config) -> 1182: Opts = #{muc := MUC} = ?config(mam_meta_opts, Config), 1183: NewOpts = Opts#{muc := MUC#{db_message_format => mam_message_xml}}, 1184: [{mod_mam, NewOpts}]. 1185: 1186: %%-------------------------------------------------------------------- 1187: %% Group name helpers 1188: %%-------------------------------------------------------------------- 1189: 1190: full_group(Conf, Group) -> 1191: list_to_atom(atom_to_list(Conf) ++ "_" ++ atom_to_list(Group)). 1192: 1193: %% @doc Delete suffix. 1194: configuration(Group) -> 1195: match_atom_prefix(Group, make_greedy(configurations())). 1196: 1197: %% @doc Rearrange a list of strings (or atoms), that all prefixes 1198: %% will be tested. 1199: %% 1200: %% Example: 1201: %% `make_greedy(rdbms_mnesia_muc, [rdbms, rdbms_mnesia]) -> rdbms' 1202: %% `make_greedy(rdbms_mnesia_muc, match_longer_first([rdbms, rdbms_mnesia])) -> rdbms_mnesia' 1203: %% @end 1204: make_greedy(List) -> 1205: lists:reverse(lists:usort(List)). 1206: 1207: %% @doc Delete prefix. 1208: basic_group(Group) -> 1209: basic_group(Group, configuration(Group)). 1210: 1211: basic_group(Group, Conf) -> 1212: ConfS = atom_to_list(Conf), 1213: GroupS = atom_to_list(Group), 1214: list_to_atom(delete_delimiter(delete_prefix(ConfS, GroupS))). 1215: 1216: match_atom_prefix(Target, Prefixes) -> 1217: match_atom_prefix1(atom_to_list(Target), Prefixes). 1218: 1219: match_atom_prefix1(TargetS, [PrefixA | Prefixes]) -> 1220: PrefixS = atom_to_list(PrefixA), 1221: case lists:prefix(PrefixS, TargetS) of 1222: true -> PrefixA; 1223: false -> match_atom_prefix1(TargetS, Prefixes) 1224: end. 1225: 1226: delete_prefix([H|Prefix], [H|Target]) -> 1227: delete_prefix(Prefix, Target); 1228: delete_prefix([], Target) -> 1229: Target. 1230: 1231: delete_delimiter("_" ++ Tail) -> 1232: Tail. 1233: 1234: %%-------------------------------------------------------------------- 1235: %% Adhoc tests 1236: %%-------------------------------------------------------------------- 1237: 1238: % @doc Helper function, sends an example message to a user and checks 1239: % if archive id elements are defined or not 1240: send_and_check_archive_elements(Config, Archived, Stanzaid) -> 1241: F = fun(Alice, Bob) -> 1242: %% Archive must be empty. 1243: %% Alice sends "OH, HAI!" to Bob. 1244: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 1245: 1246: %% Bob receives a message. 1247: BobMsg = escalus:wait_for_stanza(Bob), 1248: case exml_query:subelement(BobMsg, <<"archived">>) of 1249: undefined -> 1250: ?assert_equal(Archived, false); 1251: _ -> 1252: ?assert_equal(Archived, true) 1253: end, 1254: case exml_query:subelement(BobMsg, <<"stanza-id">>) of 1255: undefined -> 1256: ?assert_equal(Stanzaid, false); 1257: _ -> 1258: ?assert_equal(Stanzaid, true) 1259: end, 1260: ok 1261: end, 1262: %% Made fresh in init_per_testcase 1263: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 1264: 1265: % @doc Helper function, sends an example message to a room and checks 1266: % if archive id elements are defined or not 1267: muc_send_and_check_archive_elements(Config, Archived, Stanzaid) -> 1268: F = fun(Alice, Bob) -> 1269: Room = ?config(room, Config), 1270: RoomAddr = room_address(Room), 1271: Text = <<"Hi, Bob!">>, 1272: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 1273: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 1274: 1275: %% Bob received presences. 1276: escalus:wait_for_stanzas(Bob, 2), 1277: 1278: %% Bob received the room's subject. 1279: escalus:wait_for_stanzas(Bob, 1), 1280: 1281: %% Alice sends another message to Bob. 1282: %% The message is not archived by the room. 1283: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 1284: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 1285: 1286: %% Alice sends to the chat room. 1287: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 1288: 1289: %% Bob received the message "Hi, Bob!". 1290: %% This message will be archived (by alicesroom@localhost). 1291: %% User's archive is disabled (i.e. bob@localhost). 1292: BobMsg = escalus:wait_for_stanza(Bob), 1293: escalus:assert(is_message, BobMsg), 1294: case exml_query:subelement(BobMsg, <<"archived">>) of 1295: undefined -> 1296: ?assert_equal(Archived, false); 1297: _ -> 1298: ?assert_equal(Archived, true) 1299: end, 1300: case exml_query:subelement(BobMsg, <<"stanza-id">>) of 1301: undefined -> 1302: ?assert_equal(Stanzaid, false); 1303: _ -> 1304: ?assert_equal(Stanzaid, true) 1305: end, 1306: ok 1307: end, 1308: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 1309: 1310: %% Archive id elements should be present when config says so 1311: muc_no_elements(Config) -> 1312: muc_send_and_check_archive_elements(Config, false, false). 1313: 1314: muc_only_stanzaid(Config) -> 1315: muc_send_and_check_archive_elements(Config, false, true). 1316: 1317: no_elements(Config) -> 1318: send_and_check_archive_elements(Config, false, false). 1319: 1320: only_stanzaid(Config) -> 1321: send_and_check_archive_elements(Config, false, true). 1322: 1323: same_stanza_id(Config) -> 1324: P = ?config(props, Config), 1325: F = fun(Alice, Bob) -> 1326: Body = <<"OH, HAI!">>, 1327: Msg = escalus_stanza:chat_to(Bob, Body), 1328: escalus:send(Alice, Msg), 1329: mam_helper:wait_for_archive_size(Alice, 1), 1330: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 1331: Result = wait_archive_respond(Alice), 1332: [AliceCopyOfMessage] = respond_messages(Result), 1333: AliceId = exml_query:path(AliceCopyOfMessage, [{element, <<"result">>}, {attr, <<"id">>}]), 1334: %% ... and Bob receives the message 1335: RecvMsg = escalus:wait_for_stanza(Bob), 1336: BobId = exml_query:path(RecvMsg, [{element, <<"stanza-id">>}, {attr, <<"id">>}]), 1337: ?assert_equal(AliceId, BobId) 1338: end, 1339: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1340: 1341: %% Querying the archive for messages 1342: easy_archive_request(Config) -> 1343: P = ?config(props, Config), 1344: F = fun(Alice, Bob) -> 1345: %% Alice sends "OH, HAI!" to Bob 1346: %% {xmlel,<<"message">>, 1347: %% [{<<"from">>,<<"alice@localhost/res1">>}, 1348: %% {<<"to">>,<<"bob@localhost/res1">>}, 1349: %% {<<"xml:lang">>,<<"en">>}, 1350: %% {<<"type">>,<<"chat">>}], 1351: %% [{xmlel,<<"body">>,[],[{xmlcdata,<<"OH, HAI!">>}]}]} 1352: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 1353: mam_helper:wait_for_archive_size(Alice, 1), 1354: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 1355: Res = wait_archive_respond(Alice), 1356: assert_respond_size(1, Res), 1357: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res)), 1358: ok 1359: end, 1360: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1361: 1362: easy_archive_request_for_the_receiver(Config) -> 1363: P = ?config(props, Config), 1364: F = fun(Alice, Bob) -> 1365: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 1366: BobMsg = escalus:wait_for_stanza(Bob), 1367: escalus:assert(is_message, BobMsg), 1368: mam_helper:wait_for_archive_size(Bob, 1), 1369: escalus:send(Bob, stanza_archive_request(P, <<"q1">>)), 1370: Res = wait_archive_respond(Bob), 1371: assert_respond_size(1, Res), 1372: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res)), 1373: ok 1374: end, 1375: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1376: 1377: message_sent_to_yourself(Config) -> 1378: P = ?config(props, Config), 1379: F = fun(Alice) -> 1380: escalus:send(Alice, escalus_stanza:chat_to(Alice, <<"OH, HAI!">>)), 1381: escalus:wait_for_stanza(Alice), %% Receive that message 1382: mam_helper:wait_for_archive_size(Alice, 1), 1383: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 1384: Res = wait_archive_respond(Alice), 1385: assert_respond_size(1, Res), 1386: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res)), 1387: ok 1388: end, 1389: escalus_fresh:story(Config, [{alice, 1}], F). 1390: 1391: text_search_is_not_available(Config) -> 1392: P = ?config(props, Config), 1393: F = fun(Alice) -> 1394: Namespace = get_prop(mam_ns, P), 1395: escalus:send(Alice, stanza_retrieve_form_fields(<<"q">>, Namespace)), 1396: Res = escalus:wait_for_stanza(Alice), 1397: escalus:assert(is_iq_with_ns, [Namespace], Res), 1398: QueryEl = exml_query:subelement(Res, <<"query">>), 1399: XEl = exml_query:subelement(QueryEl, <<"x">>), 1400: Fields = exml_query:paths(XEl, [{element, <<"field">>}]), 1401: HasFullTextSearch = lists:any(fun(Item) -> 1402: exml_query:attr(Item, <<"var">>) == <<"full-text-search">> 1403: end, Fields), 1404: 1405: ?assert_equal(false, HasFullTextSearch) 1406: end, 1407: escalus_fresh:story(Config, [{alice, 1}], F). 1408: 1409: text_search_query_fails_if_disabled(Config) -> 1410: P = ?config(props, Config), 1411: F = fun(_Alice, Bob) -> 1412: escalus:send(Bob, stanza_text_search_archive_request(P, <<"q1">>, 1413: <<"this IQ is expected to fail">>)), 1414: Res = escalus:wait_for_stanza(Bob), 1415: escalus:assert(is_iq_error, Res) 1416: end, 1417: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1418: 1419: pagination_simple_enforced(Config) -> 1420: P = ?config(props, Config), 1421: F = fun(Alice) -> 1422: Msgs = ?config(pre_generated_msgs, Config), 1423: [_, _, StartMsg, StopMsg | _] = Msgs, 1424: {{StartMsgId, _}, _, _, _, _StartMsgPacket} = StartMsg, 1425: {{StopMsgId, _}, _, _, _, _StopMsgPacket} = StopMsg, 1426: {StartMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StartMsgId]), 1427: {StopMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StopMsgId]), 1428: StartTime = make_iso_time(StartMicro), 1429: StopTime = make_iso_time(StopMicro), 1430: %% Send 1431: %% <iq type='get'> 1432: %% <query xmlns='urn:xmpp:mam:tmp'> 1433: %% <start>StartTime</start> 1434: %% <end>StopTime</end> 1435: %% </query> 1436: %% </iq> 1437: escalus:send(Alice, stanza_date_range_archive_request_not_empty(P, StartTime, StopTime)), 1438: %% Receive two messages and IQ 1439: Result = wait_archive_respond(Alice), 1440: IQ = respond_iq(Result), 1441: [M1, M2|_] = respond_messages(Result), 1442: escalus:assert(is_iq_result, IQ), 1443: SetEl = exml_query:path(IQ, [{element, <<"fin">>}, {element, <<"set">>}]), 1444: ?assert_equal(true, undefined =/= SetEl), 1445: ?assert_equal(undefined, exml_query:path(SetEl, [{element, <<"count">>}])), 1446: ?assert_equal(undefined, exml_query:path(SetEl, [{element, <<"first">>}, {attr, <<"index">>}])), 1447: #forwarded_message{delay_stamp = Stamp1} = parse_forwarded_message(M1), 1448: #forwarded_message{delay_stamp = Stamp2} = parse_forwarded_message(M2), 1449: ?assert_equal(list_to_binary(StartTime), Stamp1), 1450: ?assert_equal(list_to_binary(StopTime), Stamp2) 1451: end, 1452: %% Made fresh in init_per_testcase 1453: escalus:story(Config, [{alice, 1}], F). 1454: 1455: text_search_is_available(Config) -> 1456: P = ?config(props, Config), 1457: F = fun(Alice) -> 1458: Namespace = get_prop(mam_ns, P), 1459: escalus:send(Alice, stanza_retrieve_form_fields(<<"q">>, Namespace)), 1460: Res = escalus:wait_for_stanza(Alice), 1461: escalus:assert(is_iq_with_ns, [Namespace], Res), 1462: QueryEl = exml_query:subelement(Res, <<"query">>), 1463: XEl = exml_query:subelement(QueryEl, <<"x">>), 1464: escalus:assert(has_field_with_type, [<<"{https://erlang-solutions.com/}full-text-search">>, 1465: <<"text-single">>], XEl), 1466: ok 1467: end, 1468: escalus_fresh:story(Config, [{alice, 1}], F). 1469: 1470: easy_text_search_request(Config) -> 1471: P = ?config(props, Config), 1472: F = fun(Alice, Bob) -> 1473: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi there! My cat's name is John">>)), 1474: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"Also my bike broke down so I'm unable ", 1475: "to return him home">>)), 1476: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"Cats are awesome by the way">>)), 1477: mam_helper:wait_for_archive_size(Alice, 3), 1478: maybe_wait_for_archive(Config), %% yz lag 1479: 1480: %% 'Cat' query 1481: escalus:send(Alice, stanza_text_search_archive_request(P, <<"q1">>, <<"cat">>)), 1482: Res1 = wait_archive_respond(Alice), 1483: assert_respond_size(2, Res1), 1484: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res1)), 1485: [Msg1, Msg2] = respond_messages(Res1), 1486: #forwarded_message{message_body = Body1} = parse_forwarded_message(Msg1), 1487: #forwarded_message{message_body = Body2} = parse_forwarded_message(Msg2), 1488: ?assert_equal(<<"Hi there! My cat's name is John">>, Body1), 1489: ?assert_equal(<<"Cats are awesome by the way">>, Body2), 1490: 1491: %% 'Bike' query 1492: escalus:send(Alice, stanza_text_search_archive_request(P, <<"q2">>, <<"bike">>)), 1493: Res2 = wait_archive_respond(Alice), 1494: assert_respond_size(1, Res2), 1495: assert_respond_query_id(P, <<"q2">>, parse_result_iq(Res2)), 1496: [Msg3] = respond_messages(Res2), 1497: #forwarded_message{message_body = Body3} = parse_forwarded_message(Msg3), 1498: ?assert_equal(<<"Also my bike broke down so I'm unable to return him home">>, Body3), 1499: 1500: ok 1501: end, 1502: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1503: 1504: long_text_search_request(Config) -> 1505: P = ?config(props, Config), 1506: F = fun(Alice, Bob) -> 1507: Msgs = text_search_messages(), 1508: 1509: [ escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg)) || Msg <- Msgs ], 1510: 1511: %% Just check that Bob receives the messages. 1512: %% It should help, when the CI server is overloaded. 1513: %% The test should work without this block. 1514: %% But sometimes on the CI server we ending up with not all messages 1515: %% yet archived, which leads to the test failure. 1516: ExpectedLen = length(Msgs), 1517: BobMessages = escalus:wait_for_stanzas(Bob, ExpectedLen, 15000), 1518: ?assert_equal_extra(ExpectedLen, length(BobMessages), 1519: #{bob_messages => BobMessages}), 1520: 1521: mam_helper:wait_for_archive_size(Bob, ExpectedLen), 1522: mam_helper:wait_for_archive_size(Alice, ExpectedLen), 1523: maybe_wait_for_archive(Config), %% yz lag 1524: escalus:send(Alice, stanza_text_search_archive_request(P, <<"q1">>, 1525: <<"Ribs poRk cUlpa">>)), 1526: Res = wait_archive_respond(Alice), 1527: assert_respond_size(3, Res), 1528: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res)), 1529: 1530: [Msg1, Msg2, Msg3] = respond_messages(Res), 1531: #forwarded_message{message_body = Body1} = parse_forwarded_message(Msg1), 1532: #forwarded_message{message_body = Body2} = parse_forwarded_message(Msg2), 1533: #forwarded_message{message_body = Body3} = parse_forwarded_message(Msg3), 1534: 1535: ?assert_equal(lists:nth(2, Msgs), Body1), 1536: ?assert_equal(lists:nth(8, Msgs), Body2), 1537: ?assert_equal(lists:nth(11, Msgs), Body3), 1538: 1539: ok 1540: end, 1541: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1542: 1543: %% Write and read Unicode messages back 1544: unicode_messages_can_be_extracted(Config) -> 1545: P = ?config(props, Config), 1546: F = fun(Alice, Bob) -> 1547: Texts = [<<"Hi! this is an unicode character lol 😂"/utf8>>, 1548: <<"this is another one no 🙅"/utf8>>, 1549: <<"This is the same again lol 😂"/utf8>>], 1550: 1551: [escalus:send(Alice, escalus_stanza:chat_to(Bob, Text)) 1552: || Text <- Texts], 1553: mam_helper:wait_for_archive_size(Alice, length(Texts)), 1554: 1555: %% WHEN Getting all messages 1556: escalus:send(Alice, stanza_archive_request(P, <<"uni-q">>)), 1557: Res = wait_archive_respond(Alice), 1558: assert_respond_size(3, Res), 1559: 1560: assert_respond_query_id(P, <<"uni-q">>, parse_result_iq(Res)), 1561: [Msg1, Msg2, Msg3] = respond_messages(Res), 1562: #forwarded_message{message_body = Body1} = parse_forwarded_message(Msg1), 1563: #forwarded_message{message_body = Body2} = parse_forwarded_message(Msg2), 1564: #forwarded_message{message_body = Body3} = parse_forwarded_message(Msg3), 1565: ?assert_equal(<<"Hi! this is an unicode character lol 😂"/utf8>>, Body1), 1566: ?assert_equal(<<"this is another one no 🙅"/utf8>>, Body2), 1567: ?assert_equal(<<"This is the same again lol 😂"/utf8>>, Body3), 1568: ok 1569: end, 1570: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1571: 1572: %% Depends on search feature 1573: %% Consult with unicode_messages_can_be_extracted, 1574: %% which ensures that unicode messages can be processed 1575: save_unicode_messages(Config) -> 1576: P = ?config(props, Config), 1577: F = fun(Alice, Bob) -> 1578: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi! this is an unicode character lol 😂"/utf8>>)), 1579: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"this is another one no 🙅"/utf8>>)), 1580: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"This is the same again lol 😂"/utf8>>)), 1581: mam_helper:wait_for_archive_size(Alice, 3), 1582: 1583: %% Each stanza_text_search_archive_request should call it regardless of wait_for_archive_size result. 1584: maybe_wait_for_archive(Config), 1585: 1586: %% WHEN Searching for a message with "lol" string 1587: escalus:send(Alice, stanza_text_search_archive_request(P, <<"q1">>, <<"lol"/utf8>>)), 1588: Res1 = wait_archive_respond(Alice), 1589: assert_respond_size(2, Res1), 1590: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res1)), 1591: [Msg1, Msg2] = respond_messages(Res1), 1592: #forwarded_message{message_body = Body1} = parse_forwarded_message(Msg1), 1593: #forwarded_message{message_body = Body2} = parse_forwarded_message(Msg2), 1594: ?assert_equal(<<"Hi! this is an unicode character lol 😂"/utf8>>, Body1), 1595: ?assert_equal(<<"This is the same again lol 😂"/utf8>>, Body2), 1596: 1597: escalus:send(Alice, stanza_text_search_archive_request(P, <<"q2">>, <<"another"/utf8>>)), 1598: Res2 = wait_archive_respond(Alice), 1599: assert_respond_size(1, Res2), 1600: assert_respond_query_id(P, <<"q2">>, parse_result_iq(Res2)), 1601: [Msg3] = respond_messages(Res2), 1602: #forwarded_message{message_body = Body3} = parse_forwarded_message(Msg3), 1603: ?assert_equal(<<"this is another one no 🙅"/utf8>>, Body3), 1604: 1605: ok 1606: end, 1607: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 1608: 1609: stanza_id_is_appended_to_carbons(Config) -> 1610: F = fun(Alice1, Alice2, Bob1, Bob2) -> 1611: Msg = <<"OH, HAI!">>, 1612: mongoose_helper:enable_carbons([Alice1, Alice2, Bob1, Bob2]), 1613: escalus:send(Alice1, escalus_stanza:chat_to(Bob1, Msg)), 1614: mam_helper:wait_for_archive_size(Alice1, 1), 1615: escalus_client:wait_for_stanza(Bob1), 1616: Alice2CC = escalus_client:wait_for_stanza(Alice2), 1617: Bob2CC = escalus_client:wait_for_stanza(Bob2), 1618: 1619: SID = fun(Packet, Direction) -> 1620: exml_query:path(Packet, [{element_with_ns, Direction, <<"urn:xmpp:carbons:2">>}, 1621: {element_with_ns, <<"forwarded">>, <<"urn:xmpp:forward:0">>}, 1622: {element_with_ns, <<"message">>, <<"jabber:client">>}, 1623: {element_with_ns, <<"stanza-id">>, <<"urn:xmpp:sid:0">>}, 1624: {attr, <<"id">>}]) 1625: end, 1626: ?assert_equal(true, undefined =/= SID(Bob2CC, <<"received">>)), 1627: ?assert_equal(true, undefined =/= SID(Alice2CC, <<"sent">>)), 1628: escalus:assert(is_forwarded_sent_message, 1629: [escalus_client:full_jid(Alice1), escalus_client:full_jid(Bob1), Msg], Alice2CC), 1630: escalus:assert(is_forwarded_received_message, 1631: [escalus_client:full_jid(Alice1), escalus_client:full_jid(Bob1), Msg], Bob2CC) 1632: end, 1633: escalus_fresh:story(Config, [{alice, 2}, {bob, 2}], F). 1634: 1635: muc_text_search_request(Config) -> 1636: P = ?config(props, Config), 1637: F = fun(Alice, Bob) -> 1638: Room = ?config(room, Config), 1639: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 1640: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 1641: 1642: %% Bob received presences. 1643: escalus:wait_for_stanzas(Bob, 2), 1644: 1645: %% Bob received the room's subject. 1646: escalus:wait_for_stanzas(Bob, 1), 1647: 1648: Msgs = text_search_messages(), 1649: 1650: lists:foreach( 1651: fun(Msg) -> 1652: Stanza = escalus_stanza:groupchat_to(room_address(Room), Msg), 1653: escalus:send(Alice, Stanza), 1654: escalus:assert(is_message, escalus:wait_for_stanza(Bob)) 1655: end, Msgs), 1656: 1657: maybe_wait_for_archive(Config), 1658: SearchStanza = stanza_text_search_archive_request(P, <<"q1">>, <<"Ribs poRk cUlpa">>), 1659: escalus:send(Bob, stanza_to_room(SearchStanza, Room)), 1660: Res = wait_archive_respond(Bob), 1661: assert_respond_size(3, Res), 1662: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Res)), 1663: 1664: [Msg1, Msg2, Msg3] = respond_messages(Res), 1665: #forwarded_message{message_body = Body1} = parse_forwarded_message(Msg1), 1666: ?assert_equal(lists:nth(2, Msgs), Body1), 1667: #forwarded_message{message_body = Body2} = parse_forwarded_message(Msg2), 1668: ?assert_equal(lists:nth(8, Msgs), Body2), 1669: #forwarded_message{message_body = Body3} = parse_forwarded_message(Msg3), 1670: ?assert_equal(lists:nth(11, Msgs), Body3), 1671: 1672: ok 1673: end, 1674: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 1675: 1676: 1677: querying_for_all_messages_with_jid(Config) -> 1678: P = ?config(props, Config), 1679: F = fun(Alice) -> 1680: Pregenerated = ?config(pre_generated_msgs, Config), 1681: BWithJID = nick_to_jid(bob, Config), 1682: 1683: WithBob = [1 || {_, _, {JID, _, _}, _, _} <- Pregenerated, 1684: escalus_utils:jid_to_lower(JID) == BWithJID], 1685: 1686: CountWithBob = lists:sum(WithBob), 1687: escalus:send(Alice, stanza_filtered_by_jid_request(P, BWithJID)), 1688: assert_respond_size(CountWithBob, wait_archive_respond(Alice)), 1689: ok 1690: end, 1691: escalus:story(Config, [{alice, 1}], F). 1692: 1693: query_messages_by_ids(Config) -> 1694: P = ?config(props, Config), 1695: F = fun(Alice) -> 1696: Msgs = ?config(pre_generated_msgs, Config), 1697: IDs = get_pre_generated_msgs_ids(Msgs, [5, 10]), 1698: 1699: Stanza = stanza_fetch_by_id_request(P, <<"fetch-msgs-by-ids">>, IDs), 1700: escalus:send(Alice, Stanza), 1701: 1702: Result = wait_archive_respond(Alice), 1703: ResultIDs = get_received_msgs_ids(Result), 1704: 1705: assert_respond_size(2, Result), 1706: ?assert_equal(lists:sort(ResultIDs), lists:sort(IDs)), 1707: ok 1708: end, 1709: escalus:story(Config, [{alice, 1}], F). 1710: 1711: simple_query_messages_by_ids(Config) -> 1712: P = ?config(props, Config), 1713: F = fun(Alice) -> 1714: Msgs = ?config(pre_generated_msgs, Config), 1715: [ID1, ID2, ID5] = get_pre_generated_msgs_ids(Msgs, [1, 2, 5]), 1716: 1717: RSM = #rsm_in{max = 10, direction = 'after', id = ID1, simple = true}, 1718: Stanza = stanza_fetch_by_id_request(P, <<"simple-fetch-msgs-by-ids">>, [ID2, ID5], RSM), 1719: escalus:send(Alice, Stanza), 1720: 1721: Result = wait_archive_respond(Alice), 1722: ParsedIQ = parse_result_iq(Result), 1723: ResultIDs = get_received_msgs_ids(Result), 1724: 1725: ?assert_equal(lists:sort(ResultIDs), lists:sort([ID2, ID5])), 1726: ?assert_equal(undefined, ParsedIQ#result_iq.count), 1727: ?assert_equal(undefined, ParsedIQ#result_iq.first_index), 1728: ok 1729: end, 1730: escalus:story(Config, [{alice, 1}], F). 1731: 1732: server_returns_item_not_found_for_ids_filter_with_nonexistent_id(Config) -> 1733: P = ?config(props, Config), 1734: F = fun(Alice) -> 1735: Msgs = ?config(pre_generated_msgs, Config), 1736: IDs = get_pre_generated_msgs_ids(Msgs, [3, 12]), 1737: NonexistentID = <<"AV25E9SCO50K">>, 1738: 1739: Stanza = stanza_fetch_by_id_request(P, <<"ids-not-found">>, IDs ++ [NonexistentID]), 1740: escalus:send(Alice, Stanza), 1741: Result = escalus:wait_for_stanza(Alice), 1742: 1743: escalus:assert(is_iq_error, [Stanza], Result), 1744: escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Result), 1745: ok 1746: end, 1747: escalus:story(Config, [{alice, 1}], F). 1748: 1749: muc_query_messages_by_ids(Config) -> 1750: P = ?config(props, Config), 1751: F = fun(Alice) -> 1752: Room = ?config(room, Config), 1753: Msgs = ?config(pre_generated_muc_msgs, Config), 1754: IDs = get_pre_generated_msgs_ids(Msgs, [5, 10]), 1755: 1756: Stanza = stanza_fetch_by_id_request(P, <<"fetch-muc-msgs-by-ids">>, IDs), 1757: escalus:send(Alice, stanza_to_room(Stanza, Room)), 1758: 1759: Result = wait_archive_respond(Alice), 1760: ResultIDs = get_received_msgs_ids(Result), 1761: 1762: assert_respond_size(2, Result), 1763: ?assert_equal(lists:sort(ResultIDs), lists:sort(IDs)), 1764: ok 1765: end, 1766: escalus:story(Config, [{alice, 1}], F). 1767: 1768: muc_simple_query_messages_by_ids(Config) -> 1769: P = ?config(props, Config), 1770: F = fun(Alice) -> 1771: Room = ?config(room, Config), 1772: Msgs = ?config(pre_generated_muc_msgs, Config), 1773: [ID1, ID2, ID5] = get_pre_generated_msgs_ids(Msgs, [1, 2, 5]), 1774: 1775: RSM = #rsm_in{max = 10, direction = 'after', id = ID1, simple = true}, 1776: Stanza = stanza_fetch_by_id_request(P, <<"muc-simple-fetch-msgs-by-ids">>, [ID2, ID5], RSM), 1777: escalus:send(Alice, stanza_to_room(Stanza, Room)), 1778: 1779: Result = wait_archive_respond(Alice), 1780: ParsedIQ = parse_result_iq(Result), 1781: ResultIDs = get_received_msgs_ids(Result), 1782: 1783: ?assert_equal(lists:sort(ResultIDs), lists:sort([ID2, ID5])), 1784: ?assert_equal(undefined, ParsedIQ#result_iq.count), 1785: ?assert_equal(undefined, ParsedIQ#result_iq.first_index), 1786: ok 1787: end, 1788: escalus:story(Config, [{alice, 1}], F). 1789: 1790: muc_server_returns_item_not_found_for_ids_filter_with_nonexistent_id(Config) -> 1791: P = ?config(props, Config), 1792: F = fun(Alice) -> 1793: Room = ?config(room, Config), 1794: Msgs = ?config(pre_generated_muc_msgs, Config), 1795: IDs = get_pre_generated_msgs_ids(Msgs, [3, 12]), 1796: NonexistentID = <<"AV25E9SCO50K">>, 1797: 1798: Stanza = stanza_fetch_by_id_request(P, <<"muc-ids-not-found">>, IDs ++ [NonexistentID]), 1799: escalus:send(Alice, stanza_to_room(Stanza, Room)), 1800: Result = escalus:wait_for_stanza(Alice), 1801: 1802: escalus:assert(is_iq_error, [Stanza], Result), 1803: escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Result), 1804: ok 1805: end, 1806: escalus:story(Config, [{alice, 1}], F). 1807: 1808: muc_querying_for_all_messages(Config) -> 1809: P = ?config(props, Config), 1810: F = fun(Alice) -> 1811: maybe_wait_for_archive(Config), 1812: 1813: Room = ?config(room, Config), 1814: MucMsgs = ?config(pre_generated_muc_msgs, Config), 1815: 1816: MucArchiveLen = length(MucMsgs), 1817: 1818: IQ = stanza_archive_request(P, <<>>), 1819: escalus:send(Alice, stanza_to_room(IQ, Room)), 1820: maybe_wait_for_archive(Config), 1821: assert_respond_size(MucArchiveLen, wait_archive_respond(Alice)), 1822: 1823: ok 1824: end, 1825: escalus:story(Config, [{alice, 1}], F). 1826: 1827: muc_querying_for_all_messages_with_jid(Config) -> 1828: P = ?config(props, Config), 1829: F = fun(Alice) -> 1830: Room = ?config(room, Config), 1831: BobNick = ?config(bob_nickname, Config), 1832: BWithJID = room_address(Room, BobNick), 1833: 1834: MucMsgs = ?config(pre_generated_muc_msgs, Config), 1835: WithJID = [1 || {_, _, {JID, _, _}, _, _} <- MucMsgs, JID == BWithJID], 1836: Len = lists:sum(WithJID), 1837: 1838: IQ = stanza_filtered_by_jid_request(P, BWithJID), 1839: escalus:send(Alice, stanza_to_room(IQ, Room)), 1840: Result = wait_archive_respond(Alice), 1841: 1842: assert_respond_size(Len, Result), 1843: ok 1844: end, 1845: escalus:story(Config, [{alice, 1}], F). 1846: 1847: muc_light_service_discovery_stored_in_pm(Config) -> 1848: F = fun(Alice) -> 1849: Server = escalus_client:server(Alice), 1850: discover_features(Config, Alice, Server) 1851: end, 1852: escalus:fresh_story(Config, [{alice, 1}], F). 1853: 1854: muc_light_easy(Config) -> 1855: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1856: Room = muc_helper:fresh_room_name(), 1857: given_muc_light_room(Room, Alice, []), 1858: 1859: M1 = when_muc_light_message_is_sent(Alice, Room, 1860: <<"Msg 1">>, <<"Id1">>), 1861: then_muc_light_message_is_received_by([Alice], M1), 1862: 1863: M2 = when_muc_light_message_is_sent(Alice, Room, 1864: <<"Message 2">>, <<"MyID2">>), 1865: then_muc_light_message_is_received_by([Alice], M2), 1866: 1867: Aff = when_muc_light_affiliations_are_set(Alice, Room, [{Bob, member}]), 1868: then_muc_light_affiliations_are_received_by([Alice, Bob], Aff), 1869: 1870: mam_helper:wait_for_room_archive_size(muc_light_host(), Room, 4), 1871: when_archive_query_is_sent(Bob, muc_light_helper:room_bin_jid(Room), Config), 1872: ExpectedResponse = [{create, [{Alice, owner}]}, 1873: {muc_message, Room, Alice, <<"Msg 1">>}, 1874: {muc_message, Room, Alice, <<"Message 2">>}, 1875: {affiliations, [{Bob, member}]}], 1876: then_archive_response_is(Bob, ExpectedResponse, Config) 1877: end). 1878: 1879: muc_light_shouldnt_modify_pm_archive(Config) -> 1880: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1881: Room = muc_helper:fresh_room_name(), 1882: given_muc_light_room(Room, Alice, [{Bob, member}]), 1883: 1884: when_pm_message_is_sent(Alice, Bob, <<"private hi!">>), 1885: then_pm_message_is_received(Bob, <<"private hi!">>), 1886: 1887: maybe_wait_for_archive(Config), 1888: when_archive_query_is_sent(Alice, undefined, Config), 1889: then_archive_response_is(Alice, [{message, Alice, <<"private hi!">>}], Config), 1890: when_archive_query_is_sent(Bob, undefined, Config), 1891: then_archive_response_is(Bob, [{message, Alice, <<"private hi!">>}], Config), 1892: 1893: M1 = when_muc_light_message_is_sent(Alice, Room, 1894: <<"Msg 1">>, <<"Id 1">>), 1895: then_muc_light_message_is_received_by([Alice, Bob], M1), 1896: 1897: maybe_wait_for_archive(Config), 1898: when_archive_query_is_sent(Alice, muc_light_helper:room_bin_jid(Room), Config), 1899: then_archive_response_is(Alice, [{create, [{Alice, owner}, {Bob, member}]}, 1900: {muc_message, Room, Alice, <<"Msg 1">>}], Config), 1901: 1902: when_archive_query_is_sent(Alice, undefined, Config), 1903: then_archive_response_is(Alice, [{message, Alice, <<"private hi!">>}], Config), 1904: when_archive_query_is_sent(Bob, undefined, Config), 1905: then_archive_response_is(Bob, [{message, Alice, <<"private hi!">>}], Config) 1906: end). 1907: 1908: muc_light_stored_in_pm_if_allowed_to(Config) -> 1909: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1910: Room = muc_helper:fresh_room_name(), 1911: given_muc_light_room(Room, Alice, [{Bob, member}]), 1912: 1913: maybe_wait_for_archive(Config), 1914: AliceAffEvent = {affiliations, [{Alice, owner}]}, 1915: when_archive_query_is_sent(Alice, undefined, Config), 1916: then_archive_response_is(Alice, [AliceAffEvent], Config), 1917: BobAffEvent = {affiliations, [{Bob, member}]}, 1918: when_archive_query_is_sent(Bob, undefined, Config), 1919: then_archive_response_is(Bob, [BobAffEvent], Config), 1920: 1921: M1 = when_muc_light_message_is_sent(Alice, Room, <<"Msg 1">>, <<"Id 1">>), 1922: then_muc_light_message_is_received_by([Alice, Bob], M1), 1923: 1924: maybe_wait_for_archive(Config), 1925: MessageEvent = {muc_message, Room, Alice, <<"Msg 1">>}, 1926: when_archive_query_is_sent(Alice, undefined, Config), 1927: then_archive_response_is(Alice, [AliceAffEvent, MessageEvent], Config), 1928: when_archive_query_is_sent(Bob, undefined, Config), 1929: then_archive_response_is(Bob, [BobAffEvent, MessageEvent], Config) 1930: end). 1931: 1932: muc_light_include_groupchat_filter(Config) -> 1933: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1934: P = ?config(props, Config), 1935: Room = muc_helper:fresh_room_name(), 1936: given_muc_light_room(Room, Alice, [{Bob, member}]), 1937: 1938: M1 = when_muc_light_message_is_sent(Alice, Room, <<"Msg 1">>, <<"Id 1">>), 1939: then_muc_light_message_is_received_by([Alice, Bob], M1), 1940: 1941: when_pm_message_is_sent(Alice, Bob, <<"private hi!">>), 1942: then_pm_message_is_received(Bob, <<"private hi!">>), 1943: 1944: maybe_wait_for_archive(Config), 1945: 1946: Stanza = stanza_include_groupchat_request(P, <<"q1">>, <<"false">>), 1947: escalus:send(Alice, Stanza), 1948: Res = wait_archive_respond(Alice), 1949: assert_respond_size(1, Res), 1950: 1951: Stanza2 = stanza_include_groupchat_request(P, <<"q2">>, <<"true">>), 1952: escalus:send(Alice, Stanza2), 1953: Res2 = wait_archive_respond(Alice), 1954: assert_respond_size(3, Res2), 1955: ok 1956: end). 1957: 1958: muc_light_no_pm_stored_include_groupchat_filter(Config) -> 1959: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1960: P = ?config(props, Config), 1961: Room = muc_helper:fresh_room_name(), 1962: given_muc_light_room(Room, Alice, [{Bob, member}]), 1963: 1964: M1 = when_muc_light_message_is_sent(Alice, Room, <<"Msg 1">>, <<"Id 1">>), 1965: then_muc_light_message_is_received_by([Alice, Bob], M1), 1966: 1967: maybe_wait_for_archive(Config), 1968: 1969: Stanza = stanza_include_groupchat_request(P, <<"q1">>, <<"false">>), 1970: escalus:send(Alice, Stanza), 1971: Res = wait_archive_respond(Alice), 1972: assert_respond_size(0, Res), 1973: ok 1974: end). 1975: 1976: muc_light_include_groupchat_messages_by_default(Config) -> 1977: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1978: P = ?config(props, Config), 1979: MsgCount = 4, 1980: Room = muc_helper:fresh_room_name(), 1981: given_muc_light_room(Room, Alice, [{Bob, member}]), 1982: 1983: M1 = when_muc_light_message_is_sent(Alice, Room, <<"Msg 1">>, <<"Id 1">>), 1984: then_muc_light_message_is_received_by([Alice, Bob], M1), 1985: 1986: M2 = when_muc_light_message_is_sent(Alice, Room, <<"Msg 2">>, <<"Id 2">>), 1987: then_muc_light_message_is_received_by([Alice, Bob], M2), 1988: 1989: when_pm_message_is_sent(Alice, Bob, <<"private hi!">>), 1990: then_pm_message_is_received(Bob, <<"private hi!">>), 1991: 1992: maybe_wait_for_archive(Config), 1993: 1994: when_archive_query_is_sent(Alice, undefined, Config), 1995: Res = wait_archive_respond(Alice), 1996: 1997: Stanza = stanza_include_groupchat_request(P, <<"q1">>, <<"true">>), 1998: escalus:send(Alice, Stanza), 1999: Res2 = wait_archive_respond(Alice), 2000: 2001: assert_respond_size(MsgCount, Res), 2002: assert_respond_size(MsgCount, Res2), 2003: ok 2004: end). 2005: 2006: muc_light_chat_markers_are_archived_if_enabled(Config) -> 2007: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2008: Room = muc_helper:fresh_room_name(), 2009: given_muc_light_room(Room, Alice, [{Bob, member}]), 2010: 2011: %% Alice sends 3 chat markers 2012: MessageID = <<"some-fake-id">>, 2013: RoomJID = muc_light_helper:room_bin_jid(Room), 2014: lists:foreach( 2015: fun(Type) -> 2016: Marker1 = escalus_stanza:chat_marker(RoomJID, Type, MessageID), 2017: Marker2 = escalus_stanza:setattr(Marker1, <<"type">>, <<"groupchat">>), 2018: escalus:send(Alice, Marker2), 2019: escalus:wait_for_stanza(Alice), 2020: escalus:wait_for_stanza(Bob) 2021: end, [<<"received">>, <<"displayed">>, <<"acknowledged">>]), 2022: 2023: maybe_wait_for_archive(Config), 2024: when_archive_query_is_sent(Bob, muc_light_helper:room_bin_jid(Room), Config), 2025: ExpectedResponse = [ 2026: {create, [{Alice, owner}, {Bob, member}]}, 2027: {chat_marker, <<"received">>}, 2028: {chat_marker, <<"displayed">>}, 2029: {chat_marker, <<"acknowledged">>} 2030: ], 2031: then_archive_response_is(Bob, ExpectedResponse, Config) 2032: end). 2033: 2034: muc_light_chat_markers_are_not_archived_if_disabled(Config) -> 2035: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2036: Room = muc_helper:fresh_room_name(), 2037: given_muc_light_room(Room, Alice, [{Bob, member}]), 2038: 2039: %% Alice sends 3 chat markers 2040: MessageID = <<"some-fake-id">>, 2041: RoomJID = muc_light_helper:room_bin_jid(Room), 2042: lists:foreach( 2043: fun(Type) -> 2044: Marker1 = escalus_stanza:chat_marker(RoomJID, Type, MessageID), 2045: Marker2 = escalus_stanza:setattr(Marker1, <<"type">>, <<"groupchat">>), 2046: escalus:send(Alice, Marker2), 2047: escalus:wait_for_stanza(Alice), 2048: escalus:wait_for_stanza(Bob) 2049: end, [<<"received">>, <<"displayed">>, <<"acknowledged">>]), 2050: 2051: maybe_wait_for_archive(Config), 2052: when_archive_query_is_sent(Bob, muc_light_helper:room_bin_jid(Room), Config), 2053: ExpectedResponse = [{create, [{Alice, owner}, {Bob, member}]}], 2054: then_archive_response_is(Bob, ExpectedResponse, Config) 2055: end). 2056: 2057: muc_light_failed_to_decode_message_in_database(Config) -> 2058: escalus:story(Config, [{alice, 1}], fun(Alice) -> 2059: Room = muc_helper:fresh_room_name(), 2060: given_muc_light_room(Room, Alice, []), 2061: M1 = when_muc_light_message_is_sent(Alice, Room, 2062: <<"Msg 1">>, <<"Id1">>), 2063: then_muc_light_message_is_received_by([Alice], M1), 2064: mam_helper:wait_for_room_archive_size(muc_light_host(), Room, 2), 2065: NewMods = muc_with_db_message_format_xml(Config), 2066: %% Change the encoding format for messages in the database 2067: dynamic_modules:ensure_modules(host_type(), NewMods), 2068: when_archive_query_is_sent(Alice, muc_light_helper:room_bin_jid(Room), Config), 2069: [ArcMsg | _] = respond_messages(assert_respond_size(2, wait_archive_respond(Alice))), 2070: assert_failed_to_decode_message(ArcMsg) 2071: end). 2072: 2073: pm_failed_to_decode_message_in_database(Config) -> 2074: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2075: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi">>)), 2076: mam_helper:wait_for_archive_size(Alice, 1), 2077: NewMods = pm_with_db_message_format_xml(Config), 2078: %% Change the encoding format for messages in the database 2079: dynamic_modules:ensure_modules(host_type(), NewMods), 2080: when_archive_query_is_sent(Alice, undefined, Config), 2081: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Alice))), 2082: assert_failed_to_decode_message(ArcMsg) 2083: end). 2084: 2085: retrieve_form_fields(ConfigIn) -> 2086: escalus_fresh:story(ConfigIn, [{alice, 1}], fun(Alice) -> 2087: P = ?config(props, ConfigIn), 2088: Namespace = get_prop(mam_ns, P), 2089: escalus:send(Alice, stanza_retrieve_form_fields(<<"q">>, Namespace)), 2090: Res = escalus:wait_for_stanza(Alice), 2091: escalus:assert(is_iq_with_ns, [Namespace], Res) 2092: end). 2093: 2094: retrieve_form_fields_extra_features(ConfigIn) -> 2095: escalus_fresh:story(ConfigIn, [{alice, 1}], fun(Alice) -> 2096: P = ?config(props, ConfigIn), 2097: Namespace = get_prop(mam_ns, P), 2098: escalus:send(Alice, stanza_retrieve_form_fields(<<"q">>, Namespace)), 2099: Res = escalus:wait_for_stanza(Alice), 2100: escalus:assert(is_iq_with_ns, [Namespace], Res), 2101: QueryEl = exml_query:subelement(Res, <<"query">>), 2102: XEl = exml_query:subelement(QueryEl, <<"x">>), 2103: IDsEl = exml_query:subelement_with_attr(XEl, <<"var">>, <<"ids">>), 2104: ValidateEl = exml_query:path(IDsEl, [{element_with_ns, <<"validate">>, data_validate_ns()}, 2105: {element, <<"open">>}]), 2106: escalus:assert(has_field_with_type, [<<"before-id">>, <<"text-single">>], XEl), 2107: escalus:assert(has_field_with_type, [<<"after-id">>, <<"text-single">>], XEl), 2108: escalus:assert(has_field_with_type, [<<"include-groupchat">>, <<"boolean">>], XEl), 2109: ?assertNotEqual(ValidateEl, undefined) 2110: end). 2111: 2112: archived(Config) -> 2113: P = ?config(props, Config), 2114: F = fun(Alice, Bob) -> 2115: %% Archive must be empty. 2116: %% Alice sends "OH, HAI!" to Bob. 2117: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2118: 2119: %% Bob receives a message. 2120: Msg = escalus:wait_for_stanza(Bob), 2121: try 2122: StanzaId = exml_query:subelement(Msg, <<"stanza-id">>), 2123: %% JID of the archive (i.e. where the client would send queries to) 2124: By = exml_query:attr(StanzaId, <<"by">>), 2125: %% Attribute giving the message's UID within the archive. 2126: Id = exml_query:attr(StanzaId, <<"id">>), 2127: 2128: ?assert_equal(By, escalus_client:short_jid(Bob)), 2129: 2130: %% Bob calls archive. 2131: maybe_wait_for_archive(Config), 2132: escalus:send(Bob, stanza_archive_request(P, <<"q1">>)), 2133: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Bob))), 2134: #forwarded_message{result_id=ArcId} = parse_forwarded_message(ArcMsg), 2135: ?assert_equal(Id, ArcId), 2136: ok 2137: catch Class:Reason:StackTrace -> 2138: ct:pal("Msg ~p", [Msg]), 2139: erlang:raise(Class, Reason, StackTrace) 2140: end 2141: end, 2142: %% Made fresh in init_per_testcase 2143: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2144: 2145: 2146: message_with_stanzaid(Config) -> 2147: F = fun(Alice, Bob) -> 2148: %% Archive must be empty. 2149: %% Alice sends "OH, HAI!" to Bob. 2150: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2151: 2152: %% Bob receives a message. 2153: Msg = escalus:wait_for_stanza(Bob), 2154: 2155: ArcStanzaid = exml_query:subelement(Msg, <<"stanza-id">>), 2156: 2157: %% stanza-id has a namespace 'urn:xmpp:sid:0' 2158: <<"urn:xmpp:sid:0">> = exml_query:attr(ArcStanzaid, <<"xmlns">>), 2159: ok 2160: end, 2161: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2162: 2163: retract_message_on_stanza_id(Config) -> 2164: test_retract_message([{retract_on, stanza_id} | Config]). 2165: 2166: retract_wrong_message(Config) -> 2167: test_retract_message([{retract_on, {origin_id, <<"wrong-id">>}} | Config]). 2168: 2169: ignore_bad_retraction(Config) -> 2170: test_retract_message([{retract_on, none} | Config]). 2171: 2172: retract_message(Config) -> 2173: test_retract_message([{retract_on, {origin_id, origin_id()}} | Config]). 2174: 2175: test_retract_message(Config) -> 2176: P = ?config(props, Config), 2177: F = fun(Alice, Bob) -> 2178: %% GIVEN Alice sends a message with 'origin-id' to Bob 2179: Body = <<"OH, HAI!">>, 2180: OriginIdElement = origin_id_element(origin_id()), 2181: Msg = #xmlel{children = Children} = escalus_stanza:chat_to(Bob, Body), 2182: escalus:send(Alice, Msg#xmlel{children = Children ++ [OriginIdElement]}), 2183: 2184: mam_helper:wait_for_archive_size(Alice, 1), 2185: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 2186: Result = wait_archive_respond(Alice), 2187: [AliceCopyOfMessage] = respond_messages(Result), 2188: 2189: %% ... and Bob receives the message 2190: RecvMsg = escalus:wait_for_stanza(Bob), 2191: ?assert_equal(OriginIdElement, exml_query:subelement(RecvMsg, <<"origin-id">>)), 2192: 2193: %% WHEN Alice retracts the message 2194: ApplyToElement = apply_to_element(Config, AliceCopyOfMessage), 2195: RetractMsg = retraction_message(<<"chat">>, escalus_utils:get_jid(Bob), ApplyToElement), 2196: escalus:send(Alice, RetractMsg), 2197: 2198: %% THEN Bob receives the message with 'retract' ... 2199: RecvRetract = escalus:wait_for_stanza(Bob), 2200: ?assert_equal(ApplyToElement, exml_query:subelement(RecvRetract, <<"apply-to">>)), 2201: 2202: maybe_wait_for_archive(Config), 2203: 2204: %% ... and Alice and Bob have both messages in their archives 2205: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 2206: check_archive_after_retraction(Config, Alice, ApplyToElement, Body), 2207: escalus:send(Bob, stanza_archive_request(P, <<"q2">>)), 2208: check_archive_after_retraction(Config, Bob, ApplyToElement, Body), 2209: 2210: ok 2211: end, 2212: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 2213: 2214: filter_forwarded(Config) -> 2215: P = ?config(props, Config), 2216: F = fun(Alice, Bob) -> 2217: %% Alice sends "OH, HAI!" to Bob. 2218: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2219: 2220: %% Bob receives a message. 2221: escalus:wait_for_stanza(Bob), 2222: mam_helper:wait_for_archive_size(Bob, 1), 2223: escalus:send(Bob, stanza_archive_request(P, <<"q1">>)), 2224: assert_respond_size(1, wait_archive_respond(Bob)), 2225: 2226: %% Check, that previous forwarded message was not archived. 2227: escalus:send(Bob, stanza_archive_request(P, <<"q2">>)), 2228: assert_respond_size(1, wait_archive_respond(Bob)), 2229: ok 2230: end, 2231: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 2232: 2233: %% Ensure, that a offline message does not stored twice when delivered. 2234: offline_message(Config) -> 2235: Msg = <<"Is there anybody here?">>, 2236: P = ?config(props, Config), 2237: F = fun(Alice) -> 2238: %% Alice sends a message to Bob while bob is offline. 2239: escalus:send(Alice, 2240: escalus_stanza:chat_to(escalus_users:get_jid(Config, bob), Msg)), 2241: maybe_wait_for_archive(Config), 2242: ok 2243: end, 2244: escalus:story(Config, [{alice, 1}], F), 2245: 2246: %% Bob logs in 2247: Bob = login_send_presence(Config, bob), 2248: 2249: %% If mod_offline is enabled, then an offline message 2250: %% will be delivered automatically. 2251: 2252: %% He receives his initial presence and the message. 2253: escalus:wait_for_stanzas(Bob, 2, 1000), 2254: 2255: %% Bob checks his archive. 2256: escalus:send(Bob, stanza_archive_request(P, <<"q1">>)), 2257: ArcMsgs = respond_messages(wait_archive_respond(Bob)), 2258: assert_only_one_of_many_is_equal(ArcMsgs, Msg), 2259: 2260: escalus_client:stop(Config, Bob). 2261: 2262: nostore_hint(Config) -> 2263: Msg = <<"So secret">>, 2264: P = ?config(props, Config), 2265: F = fun(Alice, Bob) -> 2266: %% Alice sends a message to Bob with a hint. 2267: escalus:send(Alice, 2268: add_nostore_hint(escalus_stanza:chat_to(Bob, Msg))), 2269: maybe_wait_for_archive(Config), 2270: escalus:wait_for_stanzas(Bob, 1, 1000), 2271: 2272: %% Bob checks his archive. 2273: escalus:send(Bob, stanza_archive_request(P, <<"q1">>)), 2274: ArcMsgs = respond_messages(wait_archive_respond(Bob)), 2275: assert_not_stored(ArcMsgs, Msg), 2276: ok 2277: end, 2278: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 2279: 2280: muc_message_with_stanzaid(Config) -> 2281: F = fun(Alice, Bob) -> 2282: Room = ?config(room, Config), 2283: RoomAddr = room_address(Room), 2284: Text = <<"Hi, Bob!">>, 2285: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2286: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2287: 2288: %% Bob received presences. 2289: escalus:wait_for_stanzas(Bob, 2), 2290: 2291: %% Bob received the room's subject. 2292: escalus:wait_for_stanzas(Bob, 1), 2293: 2294: %% Alice sends another message to Bob. 2295: %% The message is not archived by the room. 2296: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2297: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 2298: 2299: %% Alice sends to the chat room. 2300: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 2301: 2302: %% Bob received the message "Hi, Bob!". 2303: %% This message will be archived (by alicesroom@localhost). 2304: %% User's archive is disabled (i.e. bob@localhost). 2305: BobMsg = escalus:wait_for_stanza(Bob), 2306: escalus:assert(is_message, BobMsg), 2307: ArcStanzaid = exml_query:subelement(BobMsg, <<"stanza-id">>), 2308: 2309: %% stanza-id has a namespace 'urn:xmpp:sid:0' 2310: Xmlns = exml_query:attr(ArcStanzaid, <<"xmlns">>), 2311: ?assert_equal(Xmlns, <<"urn:xmpp:sid:0">>), 2312: ok 2313: end, 2314: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2315: 2316: retract_muc_message_on_stanza_id(Config) -> 2317: test_retract_muc_message([{retract_on, stanza_id} | Config]). 2318: 2319: retract_wrong_muc_message(Config) -> 2320: test_retract_muc_message([{retract_on, {origin_id, <<"wrong-id">>}} | Config]). 2321: 2322: retract_muc_message(Config) -> 2323: test_retract_muc_message([{retract_on, {origin_id, origin_id()}} | Config]). 2324: 2325: test_retract_muc_message(Config) -> 2326: P = ?config(props, Config), 2327: F = fun(Alice, Bob) -> 2328: Room = ?config(room, Config), 2329: RoomAddr = room_address(Room), 2330: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2331: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2332: %% Bob received presences. 2333: escalus:wait_for_stanzas(Bob, 2), 2334: %% Bob received the room's subject. 2335: escalus:wait_for_stanzas(Bob, 1), 2336: %% Alice receives all the messages Bob did as well 2337: escalus:wait_for_stanzas(Alice, 3), 2338: 2339: %% GIVEN Alice sends a message with 'origin-id' to the chat room ... 2340: Body = <<"Hi, Bob!">>, 2341: OriginIdElement = origin_id_element(origin_id()), 2342: Msg = #xmlel{children = Children} = escalus_stanza:groupchat_to(RoomAddr, Body), 2343: escalus:send(Alice, Msg#xmlel{children = Children ++ [OriginIdElement]}), 2344: 2345: AliceCopyOfMessage = escalus:wait_for_stanza(Alice), 2346: 2347: %% ... and Bob receives the message 2348: RecvMsg = escalus:wait_for_stanza(Bob), 2349: ?assert_equal(OriginIdElement, exml_query:subelement(RecvMsg, <<"origin-id">>)), 2350: 2351: %% WHEN Alice retracts the message 2352: ApplyToElement = apply_to_element(Config, AliceCopyOfMessage), 2353: RetractMsg = retraction_message(<<"groupchat">>, RoomAddr, ApplyToElement), 2354: escalus:send(Alice, RetractMsg), 2355: 2356: %% THEN Bob receives the message with 'retract' ... 2357: RecvRetract = escalus:wait_for_stanza(Bob), 2358: ?assert_equal(ApplyToElement, exml_query:subelement(RecvRetract, <<"apply-to">>)), 2359: 2360: maybe_wait_for_archive(Config), 2361: 2362: %% ... and finds both messages in the room archive 2363: escalus:send(Bob, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2364: check_archive_after_retraction(Config, Bob, ApplyToElement, Body), 2365: 2366: ok 2367: end, 2368: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2369: 2370: muc_archive_request(Config) -> 2371: P = ?config(props, Config), 2372: F = fun(Alice, Bob) -> 2373: Room = ?config(room, Config), 2374: RoomAddr = room_address(Room), 2375: Text = <<"Hi, Bob!">>, 2376: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2377: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2378: 2379: %% Bob received presences. 2380: escalus:wait_for_stanzas(Bob, 2), 2381: 2382: %% Bob received the room's subject. 2383: escalus:wait_for_stanzas(Bob, 1), 2384: 2385: %% Alice sends another message to Bob. 2386: %% The message is not archived by the room. 2387: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2388: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 2389: 2390: %% Alice sends to the chat room. 2391: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 2392: 2393: %% Bob received the message "Hi, Bob!". 2394: %% This message will be archived (by alicesroom@localhost). 2395: %% User's archive is disabled (i.e. bob@localhost). 2396: BobMsg = escalus:wait_for_stanza(Bob), 2397: escalus:assert(is_message, BobMsg), 2398: Arc = exml_query:subelement(BobMsg, <<"stanza-id">>), 2399: %% JID of the archive (i.e. where the client would send queries to) 2400: By = exml_query:attr(Arc, <<"by">>), 2401: %% Attribute giving the message's UID within the archive. 2402: Id = exml_query:attr(Arc, <<"id">>), 2403: 2404: maybe_wait_for_archive(Config), 2405: 2406: %% Bob requests the room's archive. 2407: escalus:send(Bob, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2408: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Bob))), 2409: #forwarded_message{result_id=ArcId, message_body=ArcMsgBody, 2410: message_to=MsgTo, message_from=MsgFrom} = 2411: parse_forwarded_message(ArcMsg), 2412: %% XEP: the 'to' of the forwarded stanza MUST be empty 2413: %% However, Smack crashes if it is present, so it is removed 2414: ?assert_equal_extra(undefined, MsgTo, message_to), 2415: 2416: %% XEP: the 'from' MUST be the occupant JID of the sender of the archived message 2417: ?assert_equal_extra(escalus_utils:jid_to_lower(room_address(Room, nick(Alice))), 2418: escalus_utils:jid_to_lower(MsgFrom), message_from), 2419: 2420: ?assert_equal(Text, ArcMsgBody), 2421: ?assert_equal(ArcId, Id), 2422: ?assert_equal(escalus_utils:jid_to_lower(RoomAddr), By), 2423: ?assert_equal_extra(true, has_x_user_element(ArcMsg), 2424: [{forwarded_message, ArcMsg}]), 2425: ok 2426: end, 2427: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2428: 2429: muc_multiple_devices(Config) -> 2430: P = ?config(props, Config), 2431: F = fun(Alice1, Alice2, Bob) -> 2432: Room = ?config(room, Config), 2433: RoomAddr = room_address(Room), 2434: Text = <<"Hi, Bob!">>, 2435: %% You should use an unique nick for each device. 2436: escalus:send(Alice1, stanza_muc_enter_room(Room, <<"alice_1">>)), 2437: escalus:send(Alice2, stanza_muc_enter_room(Room, <<"alice_2">>)), 2438: escalus:send(Bob, stanza_muc_enter_room(Room, <<"bob">>)), 2439: 2440: %% Alice received presences. 2441: escalus:wait_for_stanzas(Alice1, 3), 2442: escalus:wait_for_stanzas(Alice2, 3), 2443: 2444: %% Bob received presences. 2445: escalus:wait_for_stanzas(Bob, 3), 2446: 2447: %% Bob received the room's subject. 2448: escalus:wait_for_stanzas(Bob, 1), 2449: 2450: %% Alice received the room's subject. 2451: escalus:wait_for_stanzas(Alice1, 1), 2452: escalus:wait_for_stanzas(Alice2, 1), 2453: 2454: %% Alice sends to the chat room. 2455: escalus:send(Alice1, escalus_stanza:groupchat_to(RoomAddr, Text)), 2456: 2457: %% Alice receives her own message. 2458: Alice1Msg = escalus:wait_for_stanza(Alice1), 2459: escalus:assert(is_message, Alice1Msg), 2460: 2461: Alice2Msg = escalus:wait_for_stanza(Alice2), 2462: escalus:assert(is_message, Alice2Msg), 2463: 2464: Alice1Arc = exml_query:subelement(Alice1Msg, <<"stanza-id">>), 2465: Alice2Arc = exml_query:subelement(Alice2Msg, <<"stanza-id">>), 2466: ?assert_equal(Alice1Arc, Alice2Arc), 2467: 2468: %% Bob received the message "Hi, Bob!". 2469: %% This message will be archived (by alicesroom@localhost). 2470: %% User's archive is disabled (i.e. bob@localhost). 2471: BobMsg = escalus:wait_for_stanza(Bob), 2472: escalus:assert(is_message, BobMsg), 2473: Arc = exml_query:subelement(BobMsg, <<"stanza-id">>), 2474: %% JID of the archive (i.e. where the client would send queries to) 2475: By = exml_query:attr(Arc, <<"by">>), 2476: %% Attribute giving the message's UID within the archive. 2477: Id = exml_query:attr(Arc, <<"id">>), 2478: 2479: ?assert_equal(Alice1Arc, Arc), 2480: 2481: %% Bob requests the room's archive. 2482: 2483: maybe_wait_for_archive(Config), 2484: 2485: escalus:send(Bob, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2486: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Bob))), 2487: #forwarded_message{result_id=ArcId, message_body=ArcMsgBody} = 2488: parse_forwarded_message(ArcMsg), 2489: ?assert_equal(Text, ArcMsgBody), 2490: ?assert_equal(ArcId, Id), 2491: ?assert_equal(escalus_utils:jid_to_lower(RoomAddr), By), 2492: ok 2493: end, 2494: escalus:story(Config, [{alice, 2}, {bob, 1}], F). 2495: 2496: muc_protected_message(Config) -> 2497: P = ?config(props, Config), 2498: F = fun(Alice, Bob) -> 2499: Room = ?config(room, Config), 2500: Text = <<"Hi, Bob!">>, 2501: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2502: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2503: 2504: %% Bob received presences. 2505: escalus:wait_for_stanzas(Bob, 2), 2506: 2507: %% Bob received the room's subject. 2508: escalus:wait_for_stanzas(Bob, 1), 2509: 2510: %% Alice sends to Bob, using his occupant JID. 2511: %% This message will not be put into room's history. 2512: Msg = escalus_stanza:chat_to(room_address(Room, nick(Bob)), Text), 2513: escalus:send(Alice, Msg), 2514: 2515: %% Bob received the message "Hi, Bob!". 2516: BobMsg = escalus:wait_for_stanza(Bob), 2517: escalus:assert(is_message, BobMsg), 2518: 2519: BobArchiveAddr = escalus_client:short_jid(Bob), 2520: ArchivedBy = [exml_query:attr(Arc, <<"by">>) 2521: || Arc <- BobMsg#xmlel.children, 2522: Arc#xmlel.name =:= <<"archived">>, 2523: BobArchiveAddr =/= exml_query:attr(Arc, <<"by">>)], 2524: ?assert_equal([], ArchivedBy), 2525: 2526: %% Bob requests the room's archive. 2527: escalus:send(Bob, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2528: assert_respond_size(0, wait_archive_respond(Bob)), 2529: ok 2530: end, 2531: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2532: 2533: muc_deny_protected_room_access(Config) -> 2534: P = ?config(props, Config), 2535: F = fun(Alice, Bob) -> 2536: Room = ?config(room, Config), 2537: RoomAddr = room_address(Room), 2538: Text = <<"Hi, Bob!">>, 2539: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2540: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2541: 2542: %% mod_muc returns error presence. 2543: Err1 = escalus:wait_for_stanza(Bob), 2544: escalus_assert:is_error(Err1, <<"auth">>, <<"not-authorized">>), 2545: 2546: %% Alice sends to the chat room. 2547: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 2548: 2549: %% Bob requests the room's archive. 2550: escalus:send(Bob, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2551: Err2 = escalus:wait_for_stanza(Bob), 2552: %% mod_mam_muc returns error iq. 2553: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Err2), 2554: ok 2555: end, 2556: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2557: 2558: %% @doc Allow access to non-in-room users who able to connect 2559: muc_allow_access_to_owner(Config) -> 2560: P = ?config(props, Config), 2561: F = fun(Alice, _Bob) -> 2562: Room = ?config(room, Config), 2563: _RoomAddr = room_address(Room), 2564: 2565: %% Alice (not in room) requests the room's archive. 2566: escalus:send(Alice, stanza_to_room(stanza_archive_request(P, <<"q1">>), Room)), 2567: %% mod_mam_muc returns result. 2568: assert_respond_size(0, wait_archive_respond(Alice)), 2569: ok 2570: end, 2571: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2572: 2573: muc_sanitize_x_user_in_non_anon_rooms(Config) -> 2574: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2575: {Room, _} = enter_room(Config, [Alice, Bob]), 2576: Text = <<"Hi all!">>, 2577: SpoofJid = <<"spoof@test.com">>, 2578: 2579: %% Bob received presences. 2580: escalus:wait_for_stanzas(Bob, 2), 2581: 2582: %% Bob received the room's subject. 2583: escalus:wait_for_stanzas(Bob, 1), 2584: 2585: %% Alice received presences. 2586: escalus:wait_for_stanzas(Alice, 2), 2587: 2588: %% Alice received the room's subject. 2589: escalus:wait_for_stanzas(Alice, 1), 2590: 2591: X = #xmlel{name = <<"x">>, 2592: attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}], 2593: children = [#xmlel{name = <<"item">>, 2594: attrs = [{<<"affiliation">>, <<"owner">>}, 2595: {<<"jid">>, SpoofJid}, 2596: {<<"role">>, <<"moderator">>}]}]}, 2597: Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content = Text}]}, 2598: Stanza = #xmlel{name = <<"message">>, attrs = [{<<"type">>, <<"groupchat">>}], 2599: children = [Body, X]}, 2600: 2601: %% Bob sends to the chat room. 2602: escalus:send(Bob, stanza_to_room(Stanza, Room)), 2603: 2604: %% Alice receives the message. 2605: escalus:assert(is_message, escalus:wait_for_stanza(Alice)), 2606: 2607: maybe_wait_for_archive(Config), 2608: Props = ?config(props, Config), 2609: 2610: %% Alice requests the room's archive. 2611: escalus:send(Alice, stanza_to_room(stanza_archive_request(Props, <<"q1">>), Room)), 2612: 2613: %% mod_mam_muc returns result. 2614: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Alice))), 2615: Item = exml_query:path(ArcMsg, [{element, <<"result">>}, 2616: {element, <<"forwarded">>}, 2617: {element, <<"message">>}, 2618: {element, <<"x">>}, 2619: {element, <<"item">>}]), 2620: 2621: Jid = exml_query:attr(Item, <<"jid">>), 2622: ?assertNotEqual(Jid, SpoofJid), 2623: ok 2624: end). 2625: 2626: muc_delete_x_user_in_anon_rooms(Config) -> 2627: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2628: {Room, RoomAddr} = enter_room(Config, [Alice, Bob]), 2629: Text = <<"Hi all!">>, 2630: 2631: %% Bob received presences. 2632: escalus:wait_for_stanzas(Bob, 2), 2633: 2634: %% Bob received the room's subject. 2635: escalus:wait_for_stanzas(Bob, 1), 2636: 2637: %% Alice sends to the chat room. 2638: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 2639: 2640: %% Bob receives the message. 2641: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 2642: 2643: maybe_wait_for_archive(Config), 2644: Props = ?config(props, Config), 2645: 2646: %% Bob requests the room's archive. 2647: escalus:send(Bob, stanza_to_room(stanza_archive_request(Props, <<"q1">>), Room)), 2648: 2649: %% mod_mam_muc returns result. 2650: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Bob))), 2651: 2652: ?assert_equal_extra(false, has_x_user_element(ArcMsg), 2653: [{forwarded_message, ArcMsg}]), 2654: ok 2655: end). 2656: 2657: muc_show_x_user_to_moderators_in_anon_rooms(Config) -> 2658: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2659: {Room, RoomAddr} = enter_room(Config, [Alice, Bob]), 2660: Text = <<"What a lovely day!">>, 2661: 2662: %% Alice received presences. 2663: escalus:wait_for_stanzas(Alice, 2), 2664: 2665: %% Alice received the room's subject. 2666: escalus:wait_for_stanzas(Alice, 1), 2667: 2668: %% Bob sends to the chat room. 2669: escalus:send(Bob, escalus_stanza:groupchat_to(RoomAddr, Text)), 2670: 2671: %% Alice receives the message. 2672: escalus:assert(is_message, escalus:wait_for_stanza(Alice)), 2673: 2674: maybe_wait_for_archive(Config), 2675: Props = ?config(props, Config), 2676: 2677: %% Alice requests the room's archive. 2678: escalus:send(Alice, stanza_to_room(stanza_archive_request(Props, <<"q1">>), Room)), 2679: 2680: %% mod_mam_muc returns result. 2681: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Alice))), 2682: 2683: ?assert_equal_extra(true, has_x_user_element(ArcMsg), 2684: [{forwarded_message, ArcMsg}]), 2685: ok 2686: end). 2687: 2688: muc_show_x_user_for_your_own_messages_in_anon_rooms(Config) -> 2689: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 2690: {Room, RoomAddr} = enter_room(Config, [Alice, Bob]), 2691: Text = <<"How are you?">>, 2692: 2693: %% Bob received presences. 2694: escalus:wait_for_stanzas(Bob, 2), 2695: 2696: %% Bob received the room's subject. 2697: escalus:wait_for_stanzas(Bob, 1), 2698: 2699: %% Bob sends to the chat room. 2700: escalus:send(Bob, escalus_stanza:groupchat_to(RoomAddr, Text)), 2701: 2702: %% Bob receives the message. 2703: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 2704: 2705: maybe_wait_for_archive(Config), 2706: Props = ?config(props, Config), 2707: 2708: %% Bob requests the room's archive. 2709: escalus:send(Bob, stanza_to_room(stanza_archive_request(Props, <<"q1">>), Room)), 2710: 2711: %% mod_mam_muc returns result. 2712: [ArcMsg] = respond_messages(assert_respond_size(1, wait_archive_respond(Bob))), 2713: 2714: ?assert_equal_extra(true, has_x_user_element(ArcMsg), 2715: [{forwarded_message, ArcMsg}]), 2716: ok 2717: end). 2718: 2719: %% @doc Querying the archive for all messages in a certain timespan. 2720: range_archive_request(Config) -> 2721: P = ?config(props, Config), 2722: F = fun(Alice) -> 2723: %% Send 2724: %% <iq type='get'> 2725: %% <query xmlns='urn:xmpp:mam:tmp'> 2726: %% <start>2010-06-07T00:00:00Z</start> 2727: %% <end>2010-07-07T13:23:54Z</end> 2728: %% </query> 2729: %% </iq> 2730: escalus:send(Alice, stanza_date_range_archive_request(P)), 2731: IQ = escalus:wait_for_stanza(Alice, 5000), 2732: escalus:assert(is_iq_result, IQ), 2733: ok 2734: end, 2735: escalus_fresh:story(Config, [{alice, 1}], F). 2736: 2737: range_archive_request_not_empty(Config) -> 2738: P = ?config(props, Config), 2739: F = fun(Alice) -> 2740: Msgs = ?config(pre_generated_msgs, Config), 2741: [_, _, StartMsg, StopMsg | _] = Msgs, 2742: {{StartMsgId, _}, _, _, _, _StartMsgPacket} = StartMsg, 2743: {{StopMsgId, _}, _, _, _, _StopMsgPacket} = StopMsg, 2744: {StartMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StartMsgId]), 2745: {StopMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StopMsgId]), 2746: StartTime = make_iso_time(StartMicro), 2747: StopTime = make_iso_time(StopMicro), 2748: %% Send 2749: %% <iq type='get'> 2750: %% <query xmlns='urn:xmpp:mam:tmp'> 2751: %% <start>StartTime</start> 2752: %% <end>StopTime</end> 2753: %% </query> 2754: %% </iq> 2755: escalus:send(Alice, stanza_date_range_archive_request_not_empty(P, StartTime, StopTime)), 2756: %% Receive two messages and IQ 2757: Result = wait_archive_respond(Alice), 2758: IQ = respond_iq(Result), 2759: [M1, M2|_] = respond_messages(Result), 2760: escalus:assert(is_iq_result, IQ), 2761: #forwarded_message{delay_stamp=Stamp1} = parse_forwarded_message(M1), 2762: #forwarded_message{delay_stamp=Stamp2} = parse_forwarded_message(M2), 2763: ?assert_equal(list_to_binary(StartTime), Stamp1), 2764: ?assert_equal(list_to_binary(StopTime), Stamp2), 2765: ok 2766: end, 2767: %% Made fresh in init_per_testcase 2768: escalus:story(Config, [{alice, 1}], F). 2769: 2770: %% @doc A query using Result Set Management. 2771: %% See also `#rsm_in.max'. 2772: limit_archive_request(Config) -> 2773: P = ?config(props, Config), 2774: F = fun(Alice) -> 2775: %% Send 2776: %% <iq type='get' id='q29302'> 2777: %% <query xmlns='urn:xmpp:mam:tmp'> 2778: %% <start>2010-08-07T00:00:00Z</start> 2779: %% <set xmlns='http://jabber.org/protocol/rsm'> 2780: %% <limit>10</limit> 2781: %% </set> 2782: %% </query> 2783: %% </iq> 2784: escalus:send(Alice, stanza_limit_archive_request(P)), 2785: Result = wait_archive_respond(Alice), 2786: Msgs = respond_messages(Result), 2787: IQ = respond_iq(Result), 2788: escalus:assert(is_iq_result, IQ), 2789: 10 = length(Msgs), 2790: ok 2791: end, 2792: %% Made fresh in init_per_testcase 2793: escalus:story(Config, [{alice, 1}], F). 2794: 2795: metadata_archive_request(Config) -> 2796: F = fun(Alice) -> 2797: Msgs = ?config(pre_generated_msgs, Config), 2798: 2799: {{StartMsgId, _}, _, _, _, _} = hd(Msgs), 2800: {{EndMsgId, _}, _, _, _, _} = lists:last(Msgs), 2801: {StartMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StartMsgId]), 2802: {EndMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [EndMsgId]), 2803: 2804: StartTime = list_to_binary(make_iso_time(StartMicro)), 2805: EndTime = list_to_binary(make_iso_time(EndMicro)), 2806: StartId = rpc_apply(mod_mam_utils, mess_id_to_external_binary, [StartMsgId]), 2807: EndId = rpc_apply(mod_mam_utils, mess_id_to_external_binary, [EndMsgId]), 2808: 2809: Stanza = stanza_metadata_request(), 2810: escalus:send(Alice, Stanza), 2811: IQ = escalus:wait_for_stanza(Alice), 2812: 2813: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2814: ?assertEqual(StartId, exml_query:attr(Start, <<"id">>)), 2815: ?assertEqual(StartTime, exml_query:attr(Start, <<"timestamp">>)), 2816: 2817: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2818: ?assertEqual(EndId, exml_query:attr(End, <<"id">>)), 2819: ?assertEqual(EndTime, exml_query:attr(End, <<"timestamp">>)), 2820: ok 2821: end, 2822: escalus:story(Config, [{alice, 1}], F). 2823: 2824: metadata_archive_request_empty(Config) -> 2825: F = fun(Alice) -> 2826: Stanza = stanza_metadata_request(), 2827: escalus:send(Alice, Stanza), 2828: IQ = escalus:wait_for_stanza(Alice), 2829: 2830: Metadata = exml_query:path(IQ, [{element, <<"metadata">>}]), 2831: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2832: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2833: 2834: ?assertNotEqual(Metadata, undefined), 2835: ?assertEqual(Start, undefined), 2836: ?assertEqual(End, undefined), 2837: ok 2838: end, 2839: escalus:story(Config, [{alice, 1}], F). 2840: 2841: metadata_archive_request_one_message(Config) -> 2842: F = fun(Alice, Bob) -> 2843: escalus:send(Alice, escalus_stanza:chat_to(Bob, <<"OH, HAI!">>)), 2844: escalus:wait_for_stanza(Bob), 2845: 2846: mam_helper:wait_for_archive_size(Alice, 1), 2847: maybe_wait_for_archive(Config), 2848: 2849: Stanza = stanza_metadata_request(), 2850: escalus:send(Alice, Stanza), 2851: IQ = escalus:wait_for_stanza(Alice), 2852: 2853: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2854: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2855: ?assertEqual(exml_query:attr(Start, <<"id">>), exml_query:attr(End, <<"id">>)), 2856: ?assertEqual(exml_query:attr(Start, <<"timestamp">>), 2857: exml_query:attr(End, <<"timestamp">>)), 2858: ok 2859: end, 2860: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2861: 2862: muc_metadata_archive_request(Config) -> 2863: F = fun(Alice) -> 2864: Room = ?config(room, Config), 2865: MucMsgs = ?config(pre_generated_muc_msgs, Config), 2866: 2867: {{StartMsgId, _}, _, _, _, _} = hd(MucMsgs), 2868: {{EndMsgId, _}, _, _, _, _} = lists:last(MucMsgs), 2869: {StartMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [StartMsgId]), 2870: {EndMicro, _} = rpc_apply(mod_mam_utils, decode_compact_uuid, [EndMsgId]), 2871: 2872: StartTime = list_to_binary(make_iso_time(StartMicro)), 2873: EndTime = list_to_binary(make_iso_time(EndMicro)), 2874: StartId = rpc_apply(mod_mam_utils, mess_id_to_external_binary, [StartMsgId]), 2875: EndId = rpc_apply(mod_mam_utils, mess_id_to_external_binary, [EndMsgId]), 2876: 2877: Stanza = stanza_metadata_request(), 2878: escalus:send(Alice, stanza_to_room(Stanza, Room)), 2879: IQ = escalus:wait_for_stanza(Alice), 2880: 2881: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2882: ?assertEqual(StartId, exml_query:attr(Start, <<"id">>)), 2883: ?assertEqual(StartTime, exml_query:attr(Start, <<"timestamp">>)), 2884: 2885: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2886: ?assertEqual(EndId, exml_query:attr(End, <<"id">>)), 2887: ?assertEqual(EndTime, exml_query:attr(End, <<"timestamp">>)), 2888: ok 2889: end, 2890: escalus:story(Config, [{alice, 1}], F). 2891: 2892: muc_metadata_archive_request_empty(Config) -> 2893: F = fun(Alice) -> 2894: Room = ?config(room, Config), 2895: Stanza = stanza_metadata_request(), 2896: escalus:send(Alice, stanza_to_room(Stanza, Room)), 2897: IQ = escalus:wait_for_stanza(Alice), 2898: 2899: Metadata = exml_query:path(IQ, [{element, <<"metadata">>}]), 2900: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2901: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2902: 2903: ?assertNotEqual(Metadata, undefined), 2904: ?assertEqual(Start, undefined), 2905: ?assertEqual(End, undefined), 2906: ok 2907: end, 2908: escalus:story(Config, [{alice, 1}], F). 2909: 2910: muc_metadata_archive_request_one_message(Config) -> 2911: F = fun(Alice, Bob) -> 2912: Room = ?config(room, Config), 2913: RoomAddr = room_address(Room), 2914: Text = <<"OH, HAI!">>, 2915: escalus:send(Alice, stanza_muc_enter_room(Room, nick(Alice))), 2916: escalus:send(Bob, stanza_muc_enter_room(Room, nick(Bob))), 2917: 2918: %% Bob received presences. 2919: escalus:wait_for_stanzas(Bob, 2), 2920: 2921: %% Bob received the room's subject. 2922: escalus:wait_for_stanzas(Bob, 1), 2923: 2924: %% Alice received presences. 2925: escalus:wait_for_stanzas(Alice, 2), 2926: 2927: %% Alice received the room's subject. 2928: escalus:wait_for_stanzas(Alice, 1), 2929: 2930: escalus:send(Alice, escalus_stanza:groupchat_to(RoomAddr, Text)), 2931: escalus:wait_for_stanza(Alice), 2932: escalus:wait_for_stanza(Bob), 2933: 2934: mam_helper:wait_for_room_archive_size(muc_host(), Room, 1), 2935: maybe_wait_for_archive(Config), 2936: 2937: Stanza = stanza_metadata_request(), 2938: escalus:send(Alice, stanza_to_room(Stanza, Room)), 2939: IQ = escalus:wait_for_stanza(Alice), 2940: 2941: Start = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"start">>}]), 2942: End = exml_query:path(IQ, [{element, <<"metadata">>}, {element, <<"end">>}]), 2943: ?assertEqual(exml_query:attr(Start, <<"id">>), exml_query:attr(End, <<"id">>)), 2944: ?assertEqual(exml_query:attr(Start, <<"timestamp">>), 2945: exml_query:attr(End, <<"timestamp">>)), 2946: ok 2947: end, 2948: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2949: 2950: archive_chat_markers(Config) -> 2951: P = ?config(props, Config), 2952: F = fun(Alice, Bob) -> 2953: %% Alice sends markable message to Bob 2954: Message = escalus_stanza:markable( 2955: escalus_stanza:chat_to(Bob, <<"Hello, Bob!">>) 2956: ), 2957: MessageID = escalus_stanza:id(), 2958: escalus:send(Alice, escalus_stanza:set_id(Message, MessageID)), 2959: escalus:wait_for_stanza(Bob), 2960: 2961: %% Bob sends 3 chat markers 2962: Marker1 = escalus_stanza:chat_marker(Alice, <<"received">>, 2963: MessageID), 2964: Marker2 = escalus_stanza:chat_marker(Alice, <<"displayed">>, 2965: MessageID), 2966: Marker3 = escalus_stanza:chat_marker(Alice, <<"acknowledged">>, 2967: MessageID), 2968: escalus:send(Bob, Marker1), 2969: escalus:send(Bob, Marker2), 2970: escalus:send(Bob, Marker3), 2971: escalus:wait_for_stanzas(Alice, 3), 2972: 2973: %% Alice queries MAM 2974: maybe_wait_for_archive(Config), 2975: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 2976: Result = wait_archive_respond(Alice), 2977: 2978: %% archived message + 3 markers 2979: assert_respond_size(1 + 3, Result), 2980: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Result)) 2981: end, 2982: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 2983: 2984: dont_archive_chat_markers(Config) -> 2985: P = ?config(props, Config), 2986: F = fun(Alice, Bob) -> 2987: %% Alice sends markable message to Bob 2988: Message = escalus_stanza:markable( 2989: escalus_stanza:chat_to(Bob, <<"Hello, Bob!">>) 2990: ), 2991: MessageID = escalus_stanza:id(), 2992: escalus:send(Alice, escalus_stanza:set_id(Message, MessageID)), 2993: escalus:wait_for_stanza(Bob), 2994: 2995: %% Bob sends 3 chat markers which also contain non-archivable elements 2996: Marker = #xmlel{children = Children} = 2997: escalus_stanza:chat_marker(Alice, <<"received">>, MessageID), 2998: ResultEl = #xmlel{name = <<"result">>}, 2999: DelayEl = #xmlel{name = <<"delay">>}, 3000: NoStoreEl = mam_helper:hint_elem(no_store), 3001: 3002: escalus:send(Bob, Marker#xmlel{children = [ResultEl|Children]}), 3003: escalus:send(Bob, Marker#xmlel{children = [DelayEl|Children]}), 3004: escalus:send(Bob, Marker#xmlel{children = [NoStoreEl|Children]}), 3005: escalus:wait_for_stanzas(Alice, 3), 3006: 3007: %% Alice queries MAM 3008: maybe_wait_for_archive(Config), 3009: escalus:send(Alice, stanza_archive_request(P, <<"q1">>)), 3010: Result = wait_archive_respond(Alice), 3011: 3012: %% archived message (no archived markers) 3013: assert_respond_size(1, Result), 3014: assert_respond_query_id(P, <<"q1">>, parse_result_iq(Result)) 3015: end, 3016: escalus:story(Config, [{alice, 1}, {bob, 1}], F). 3017: 3018: pagination_empty_rset(Config) -> 3019: P = ?config(props, Config), 3020: F = fun(Alice) -> 3021: %% Get the first page of size 5. 3022: RSM = #rsm_in{max=0}, 3023: 3024: rsm_send(Config, Alice, 3025: stanza_page_archive_request(P, <<"empty_rset">>, RSM)), 3026: wait_empty_rset(Alice, 15) 3027: end, 3028: parallel_story(Config, [{alice, 1}], F). 3029: 3030: pagination_first5(Config) -> 3031: P = ?config(props, Config), 3032: F = fun(Alice) -> 3033: %% Get the first page of size 5. 3034: RSM = #rsm_in{max=5}, 3035: rsm_send(Config, Alice, 3036: stanza_page_archive_request(P, <<"first5">>, RSM)), 3037: wait_message_range(Alice, 1, 5), 3038: ok 3039: end, 3040: parallel_story(Config, [{alice, 1}], F). 3041: 3042: pagination_first0(Config) -> 3043: P = ?config(props, Config), 3044: F = fun(Alice) -> 3045: %% Get the first page of size 0. 3046: RSM = #rsm_in{max=0}, 3047: rsm_send(Config, Alice, 3048: stanza_page_archive_request(P, <<"first5">>, RSM)), 3049: wait_empty_rset(Alice, 15), 3050: ok 3051: end, 3052: parallel_story(Config, [{alice, 1}], F). 3053: 3054: pagination_last5(Config) -> 3055: P = ?config(props, Config), 3056: F = fun(Alice) -> 3057: %% Get the last page of size 5. 3058: RSM = #rsm_in{max=5, direction=before}, 3059: rsm_send(Config, Alice, 3060: stanza_page_archive_request(P, <<"last5">>, RSM)), 3061: wait_message_range(Alice, 11, 15), 3062: ok 3063: end, 3064: parallel_story(Config, [{alice, 1}], F). 3065: 3066: pagination_last0(Config) -> 3067: P = ?config(props, Config), 3068: F = fun(Alice) -> 3069: %% Get the last page of size 0. 3070: RSM = #rsm_in{max=0, direction=before}, 3071: rsm_send(Config, Alice, 3072: stanza_page_archive_request(P, <<"last0">>, RSM)), 3073: wait_empty_rset(Alice, 15), 3074: ok 3075: end, 3076: parallel_story(Config, [{alice, 1}], F). 3077: 3078: pagination_offset5(Config) -> 3079: P = ?config(props, Config), 3080: F = fun(Alice) -> 3081: %% Skip 5 messages, get 5 messages. 3082: RSM = #rsm_in{max=5, index=5}, 3083: rsm_send(Config, Alice, 3084: stanza_page_archive_request(P, <<"offset5">>, RSM)), 3085: wait_message_range(Alice, 6, 10), 3086: ok 3087: end, 3088: parallel_story(Config, [{alice, 1}], F). 3089: 3090: pagination_offset5_max0(Config) -> 3091: P = ?config(props, Config), 3092: F = fun(Alice) -> 3093: %% Skip 5 messages, get 0 messages. 3094: RSM = #rsm_in{max=0, index=5}, 3095: rsm_send(Config, Alice, 3096: stanza_page_archive_request(P, <<"offset0_max5">>, RSM)), 3097: wait_empty_rset(Alice, 15), 3098: ok 3099: end, 3100: parallel_story(Config, [{alice, 1}], F). 3101: 3102: pagination_before10(Config) -> 3103: P = ?config(props, Config), 3104: F = fun(Alice) -> 3105: RSM = #rsm_in{max=5, direction=before, id=message_id(10, Config)}, 3106: rsm_send(Config, Alice, 3107: stanza_page_archive_request(P, <<"before10">>, RSM)), 3108: wait_message_range(Alice, 5, 9), 3109: ok 3110: end, 3111: parallel_story(Config, [{alice, 1}], F). 3112: 3113: pagination_flipped_page(Config) -> 3114: P = ?config(props, Config), 3115: F = fun(Alice) -> 3116: %% Get the first page of size 5. 3117: RSM = #rsm_in{max=5}, 3118: rsm_send(Config, Alice, 3119: stanza_flip_page_archive_request(P, <<"first5">>, RSM)), 3120: wait_message_range(Alice, 5, 1), 3121: ok 3122: end, 3123: parallel_story(Config, [{alice, 1}], F). 3124: 3125: pagination_simple_before10(Config) -> 3126: RSM = #rsm_in{max = 5, direction = before, id = message_id(10, Config), simple = true}, 3127: pagination_test(before10, RSM, simple_range(5, 9, false), Config). 3128: 3129: pagination_simple_before3(Config) -> 3130: RSM = #rsm_in{max = 5, direction = before, id = message_id(3, Config), simple = true}, 3131: pagination_test(before3, RSM, simple_range(1, 2, true), Config). 3132: 3133: pagination_simple_before6(Config) -> 3134: RSM = #rsm_in{max = 5, direction = before, id = message_id(6, Config), simple = true}, 3135: pagination_test(before6, RSM, simple_range(1, 5, true), Config). 3136: 3137: pagination_simple_before1_pagesize0(Config) -> 3138: %% No messages forwarded, but is_complete is set 3139: RSM = #rsm_in{max = 0, direction = before, id = message_id(1, Config), simple = true}, 3140: pagination_test(before1, RSM, simple_range(undefined, undefined, true), Config). 3141: 3142: pagination_simple_before2_pagesize0(Config) -> 3143: RSM = #rsm_in{max = 0, direction = before, id = message_id(2, Config), simple = true}, 3144: pagination_test(before2, RSM, simple_range(undefined, undefined, false), Config). 3145: 3146: pagination_simple_after5(Config) -> 3147: RSM = #rsm_in{max = 3, direction = 'after', id = message_id(5, Config), simple = true}, 3148: pagination_test(after5, RSM, simple_range(6, 8, false), Config). 3149: 3150: pagination_simple_after10(Config) -> 3151: RSM = #rsm_in{max = 5, direction = 'after', id = message_id(10, Config), simple = true}, 3152: pagination_test(after10, RSM, simple_range(11, 15, true), Config). 3153: 3154: pagination_simple_after12(Config) -> 3155: RSM = #rsm_in{max = 5, direction = 'after', id = message_id(12, Config), simple = true}, 3156: pagination_test(after12, RSM, simple_range(13, 15, true), Config). 3157: 3158: pagination_after10(Config) -> 3159: P = ?config(props, Config), 3160: F = fun(Alice) -> 3161: %% Get the last page of size 5. 3162: RSM = #rsm_in{max=5, direction='after', id=message_id(10, Config)}, 3163: rsm_send(Config, Alice, 3164: stanza_page_archive_request(P, <<"after10">>, RSM)), 3165: wait_message_range(Alice, 11, 15), 3166: ok 3167: end, 3168: parallel_story(Config, [{alice, 1}], F). 3169: 3170: %% Select first page of recent messages after last known id. 3171: %% Paginating from newest messages to oldest ones. 3172: pagination_last_after_id5(Config) -> 3173: P = ?config(props, Config), 3174: F = fun(Alice) -> 3175: %% Get the last page of size 5 after 5-th message. 3176: RSM = #rsm_in{max=5, direction='before', 3177: after_id=message_id(5, Config)}, 3178: rsm_send(Config, Alice, 3179: stanza_page_archive_request(P, <<"last_after_id5">>, RSM)), 3180: %% wait_message_range(Client, TotalCount, Offset, FromN, ToN), 3181: wait_message_range(Alice, 10, 5, 11, 15), 3182: ok 3183: end, 3184: parallel_story(Config, [{alice, 1}], F). 3185: 3186: %% Select second page of recent messages after last known id. 3187: pagination_last_after_id5_before_id11(Config) -> 3188: P = ?config(props, Config), 3189: F = fun(Alice) -> 3190: RSM = #rsm_in{max=5, direction='before', 3191: after_id=message_id(5, Config), 3192: before_id=message_id(11, Config)}, 3193: rsm_send(Config, Alice, 3194: stanza_page_archive_request(P, <<"last_after_id5_before_id11">>, RSM)), 3195: %% wait_message_range(Client, TotalCount, Offset, FromN, ToN), 3196: wait_message_range(Alice, 5, 0, 6, 10), 3197: ok 3198: end, 3199: parallel_story(Config, [{alice, 1}], F). 3200: 3201: pagination_first_page_after_id4(Config) -> 3202: P = ?config(props, Config), 3203: F = fun(Alice) -> 3204: % Default direction is after 3205: RSM = #rsm_in{max = 5, after_id = message_id(4, Config)}, 3206: rsm_send(Config, Alice, 3207: stanza_page_archive_request(P, <<"first_page_after_id4">>, RSM)), 3208: %% Gets 5, 6, 7, 8, 9 3209: %% Total Count is 11: i.e. 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 3210: %% Messages 1, 2, 3, 4 are ignored in the result 3211: %% wait_message_range(Client, TotalCount, Offset, FromN, ToN), 3212: wait_message_range(Alice, 11, 0, 5, 9), 3213: ok 3214: end, 3215: parallel_story(Config, [{alice, 1}], F). 3216: 3217: pagination_last_page_after_id4(Config) -> 3218: P = ?config(props, Config), 3219: F = fun(Alice) -> 3220: RSM = #rsm_in{max = 5, after_id = message_id(4, Config), direction=before}, 3221: rsm_send(Config, Alice, 3222: stanza_page_archive_request(P, <<"last_page_after_id4">>, RSM)), 3223: %% Gets 11, 12, 13, 14, 15 3224: %% Total Count is 11: i.e. 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 3225: %% Messages 1, 2, 3, 4 are ignored in the result 3226: %% wait_message_range(Client, TotalCount, Offset, FromN, ToN), 3227: wait_message_range(Alice, 11, 6, 11, 15), 3228: ok 3229: end, 3230: parallel_story(Config, [{alice, 1}], F). 3231: 3232: pagination_border_flipped_page(Config) -> 3233: P = ?config(props, Config), 3234: F = fun(Alice) -> 3235: RSM = #rsm_in{max=5, direction='before', 3236: after_id=message_id(5, Config), 3237: before_id=message_id(11, Config)}, 3238: rsm_send(Config, Alice, 3239: stanza_flip_page_archive_request(P, <<"border_flipped_page">>, RSM)), 3240: %% wait_message_range(Client, TotalCount, Offset, FromN, ToN), 3241: wait_message_range(Alice, 5, 0, 10, 6), 3242: ok 3243: end, 3244: parallel_story(Config, [{alice, 1}], F). 3245: 3246: server_returns_item_not_found_for_before_filter_with_nonexistent_id(Config) -> 3247: NonexistentID = <<"AV25E9SCO50K">>, 3248: RSM = #rsm_in{max = 5, direction = 'before', id = NonexistentID}, 3249: StanzaID = <<"before-nonexistent-id">>, 3250: Condition = [<<"cancel">>, <<"item-not-found">>], 3251: server_returns_item_not_found_for_nonexistent_id(Config, RSM, StanzaID, Condition). 3252: 3253: server_returns_item_not_found_for_after_filter_with_nonexistent_id(Config) -> 3254: NonexistentID = <<"AV25E9SCO50K">>, 3255: RSM = #rsm_in{max = 5, direction = 'after', id = NonexistentID}, 3256: StanzaID = <<"after-nonexistent-id">>, 3257: Condition = [<<"cancel">>, <<"item-not-found">>], 3258: server_returns_item_not_found_for_nonexistent_id(Config, RSM, StanzaID, Condition). 3259: 3260: server_returns_item_not_found_for_after_filter_with_invalid_id(Config) -> 3261: NonexistentID = <<"bef3a242-99ce-402a-9ffc-2f3c20da92d4">>, 3262: RSM = #rsm_in{max = 5, direction = 'after', from_id = NonexistentID}, 3263: StanzaID = <<"AV25E9SCO50K">>, 3264: Condition = [<<"modify">>, <<"not-acceptable">>], 3265: server_returns_item_not_found_for_nonexistent_id(Config, RSM, StanzaID, Condition). 3266: 3267: server_returns_item_not_found_for_nonexistent_id(Config, RSM, StanzaID, Condition) -> 3268: P = ?config(props, Config), 3269: F = fun(Alice) -> 3270: IQ = stanza_page_archive_request(P, StanzaID, RSM), 3271: rsm_send(Config, Alice, IQ), 3272: Res = escalus:wait_for_stanza(Alice), 3273: escalus:assert(is_iq_error, [IQ], Res), 3274: escalus:assert(is_error, Condition, Res), 3275: ok 3276: end, 3277: parallel_story(Config, [{alice, 1}], F). 3278: 3279: 3280: %% Test cases for "complete" attribute 3281: %% Complete attribute is used for pagination, telling when to stop paginating. 3282: %% see complete_flag_cases with the whole list of the cases. 3283: %% ----------------------------------------------- 3284: 3285: %% Get last page with most recent messages 3286: %% rsm_id.id is undefined 3287: %% GIVEN 15 archived messages 3288: %% WHEN direction=before, page_size=5 3289: %% THEN complete=false 3290: before_complete_false_last5(Config) -> 3291: P = ?config(props, Config), 3292: F = fun(Alice) -> 3293: %% Get the last page of size 5. 3294: %% Get messages: 11,12,13,14,15 3295: RSM = #rsm_in{max=5, direction=before}, 3296: rsm_send(Config, Alice, 3297: stanza_page_archive_request(P, <<"last5">>, RSM)), 3298: wait_for_complete_archive_response(P, Alice, <<"false">>) 3299: end, 3300: parallel_story(Config, [{alice, 1}], F). 3301: 3302: %% Gets some page in the midle of the result set 3303: %% GIVEN 15 archived messages 3304: %% WHEN direction=before, rsm_id=10, page_size=5 3305: %% THEN complete=false 3306: before_complete_false_before10(Config) -> 3307: P = ?config(props, Config), 3308: F = fun(Alice) -> 3309: %% Get messages: 5,6,7,8,9 3310: RSM = #rsm_in{max=5, direction=before, id=message_id(10, Config)}, 3311: rsm_send(Config, Alice, 3312: stanza_page_archive_request(P, <<"before10">>, RSM)), 3313: wait_for_complete_archive_response(P, Alice, <<"false">>) 3314: end, 3315: parallel_story(Config, [{alice, 1}], F). 3316: 3317: %% Reaches the end of result set 3318: %% No messages are returned. 3319: %% GIVEN 15 archived messages 3320: %% WHEN direction=before, rsm_id=1, page_size=5 3321: %% THEN complete=true 3322: before_complete_true_before1(Config) -> 3323: P = ?config(props, Config), 3324: F = fun(Alice) -> 3325: %% Get no messages 3326: RSM = #rsm_in{max=5, direction=before, id=message_id(1, Config)}, 3327: rsm_send(Config, Alice, 3328: stanza_page_archive_request(P, <<"before1">>, RSM)), 3329: wait_for_complete_archive_response(P, Alice, <<"true">>) 3330: end, 3331: parallel_story(Config, [{alice, 1}], F). 3332: 3333: %% Reaches the end of result set 3334: %% Less than maximum number of messages are returned. 3335: %% GIVEN 15 archived messages 3336: %% WHEN direction=before, rsm_id=5, page_size=5 3337: %% THEN complete=true 3338: before_complete_true_before5(Config) -> 3339: P = ?config(props, Config), 3340: F = fun(Alice) -> 3341: %% Get messages: 1,2,3,4 3342: RSM = #rsm_in{max=5, direction=before, id=message_id(5, Config)}, 3343: rsm_send(Config, Alice, 3344: stanza_page_archive_request(P, <<"before5">>, RSM)), 3345: wait_for_complete_archive_response(P, Alice, <<"true">>) 3346: end, 3347: parallel_story(Config, [{alice, 1}], F). 3348: 3349: %% Reaches the end of result set 3350: %% A special case when exactly maximum number of messages are returned. 3351: %% GIVEN 15 archived messages 3352: %% WHEN direction=before, rsm_id=6, page_size=5 3353: %% THEN complete=true 3354: before_complete_true_before6(Config) -> 3355: P = ?config(props, Config), 3356: F = fun(Alice) -> 3357: %% Get messages: 1,2,3,4,5 3358: RSM = #rsm_in{max=5, direction=before, id=message_id(6, Config)}, 3359: rsm_send(Config, Alice, 3360: stanza_page_archive_request(P, <<"before6">>, RSM)), 3361: wait_for_complete_archive_response(P, Alice, <<"true">>) 3362: end, 3363: parallel_story(Config, [{alice, 1}], F). 3364: 3365: %% First page is not complete, because max is smaller than archive size. 3366: %% rsm_id.id is undefined 3367: %% GIVEN 15 archived messages 3368: %% WHEN direction=after, rsm_id=6, page_size=5 3369: %% THEN complete=false 3370: after_complete_false_first_page(Config) -> 3371: P = ?config(props, Config), 3372: F = fun(Alice) -> 3373: %% Get messages: 1,2,3,4,5 3374: RSM = #rsm_in{max=5, direction='after'}, 3375: rsm_send(Config, Alice, 3376: stanza_page_archive_request(P, <<"firstpage">>, RSM)), 3377: wait_for_complete_archive_response(P, Alice, <<"false">>) 3378: end, 3379: parallel_story(Config, [{alice, 1}], F). 3380: 3381: %% There are still 8-15 messages to paginate after this request. 3382: %% GIVEN 15 archived messages 3383: %% WHEN direction=after, rsm_id=2, page_size=5 3384: %% THEN complete=false 3385: after_complete_false_after2(Config) -> 3386: P = ?config(props, Config), 3387: F = fun(Alice) -> 3388: %% Get messages: 3,4,5,6,7 3389: RSM = #rsm_in{max=5, direction='after', id=message_id(2, Config)}, 3390: rsm_send(Config, Alice, 3391: stanza_page_archive_request(P, <<"after2">>, RSM)), 3392: wait_for_complete_archive_response(P, Alice, <<"false">>) 3393: end, 3394: parallel_story(Config, [{alice, 1}], F). 3395: 3396: %% There is still one message to paginate after this request. 3397: %% GIVEN 15 archived messages 3398: %% WHEN direction=after, rsm_id=9, page_size=5 3399: %% THEN complete=false 3400: after_complete_false_after9(Config) -> 3401: P = ?config(props, Config), 3402: F = fun(Alice) -> 3403: %% Get messages: 10,11,12,13,14 3404: RSM = #rsm_in{max=5, direction='after', id=message_id(9, Config)}, 3405: rsm_send(Config, Alice, 3406: stanza_page_archive_request(P, <<"after9">>, RSM)), 3407: wait_for_complete_archive_response(P, Alice, <<"false">>) 3408: end, 3409: parallel_story(Config, [{alice, 1}], F). 3410: 3411: %% There are no messages to paginate after this request. 3412: %% Special case, when exactly page_size messages are returned. 3413: %% GIVEN 15 archived messages 3414: %% WHEN direction=after, rsm_id=10, page_size=5 3415: %% THEN complete=true 3416: after_complete_true_after10(Config) -> 3417: P = ?config(props, Config), 3418: F = fun(Alice) -> 3419: %% Get the last page of size 5. 3420: %% Get messages: 11,12,13,14,15 3421: RSM = #rsm_in{max=5, direction='after', id=message_id(10, Config)}, 3422: rsm_send(Config, Alice, 3423: stanza_page_archive_request(P, <<"after10">>, RSM)), 3424: wait_for_complete_archive_response(P, Alice, <<"true">>) 3425: end, 3426: parallel_story(Config, [{alice, 1}], F). 3427: 3428: %% There are no messages to paginate after this request. 3429: %% Less than page_size are returned. 3430: %% GIVEN 15 archived messages 3431: %% WHEN direction=after, rsm_id=10, page_size=5 3432: %% THEN complete=true 3433: after_complete_true_after11(Config) -> 3434: P = ?config(props, Config), 3435: F = fun(Alice) -> 3436: %% Get the last page of size 5. 3437: %% Get messages: 12,13,14,15 3438: RSM = #rsm_in{max=5, direction='after', id=message_id(11, Config)}, 3439: rsm_send(Config, Alice, 3440: stanza_page_archive_request(P, <<"after11">>, RSM)), 3441: wait_for_complete_archive_response(P, Alice, <<"true">>) 3442: end, 3443: parallel_story(Config, [{alice, 1}], F). 3444: 3445: 3446: %% Test cases for preferences IQs 3447: %% ------------------------------------------------------------------ 3448: 3449: prefs_set_request(Config) -> 3450: F = fun(Alice) -> 3451: %% Send 3452: %% 3453: %% <iq type='set' id='juliet2'> 3454: %% <prefs xmlns='urn:xmpp:mam:tmp' default="roster"> 3455: %% <always> 3456: %% <jid>romeo@montague.net</jid> 3457: %% </always> 3458: %% <never> 3459: %% <jid>montague@montague.net</jid> 3460: %% </never> 3461: %% </prefs> 3462: %% </iq> 3463: escalus:send(Alice, stanza_prefs_set_request(<<"roster">>, 3464: [<<"romeo@montague.net">>], 3465: [<<"montague@montague.net">>], 3466: mam_ns_binary())), 3467: ReplySet = escalus:wait_for_stanza(Alice), 3468: 3469: escalus:send(Alice, stanza_prefs_get_request(mam_ns_binary())), 3470: ReplyGet = escalus:wait_for_stanza(Alice), 3471: 3472: ResultIQ1 = parse_prefs_result_iq(ReplySet), 3473: ResultIQ2 = parse_prefs_result_iq(ReplyGet), 3474: ?assert_equal(ResultIQ1, ResultIQ2), 3475: ok 3476: end, 3477: escalus:story(Config, [{alice, 1}], F). 3478: 3479: query_get_request(Config) -> 3480: F = fun(Alice) -> 3481: QueryXmlns = mam_ns_binary_v04(), 3482: escalus:send(Alice, stanza_query_get_request(QueryXmlns)), 3483: ReplyFields = escalus:wait_for_stanza(Alice), 3484: ResponseXmlns = exml_query:path(ReplyFields, 3485: [{element, <<"query">>}, 3486: {element, <<"x">>}, 3487: {element, <<"field">>}, 3488: {element, <<"value">>}, 3489: cdata]), 3490: ?assert_equal(QueryXmlns, ResponseXmlns) 3491: end, 3492: escalus_fresh:story(Config, [{alice, 1}], F). 3493: 3494: %% Test reproducing https://github.com/esl/MongooseIM/issues/263 3495: %% The idea is this: in a "perfect" world jid elements are put together 3496: %% without whitespaces. In the real world it is not true. 3497: %% Put "\n" between two jid elements. 3498: prefs_set_cdata_request(Config) -> 3499: F = fun(Alice) -> 3500: %% Send 3501: %% 3502: %% <iq type='set' id='juliet2'> 3503: %% <prefs xmlns='urn:xmpp:mam:tmp' default="roster"> 3504: %% <always> 3505: %% <jid>romeo@montague.net</jid> 3506: %% <jid>montague@montague.net</jid> 3507: %% </always> 3508: %% </prefs> 3509: %% </iq> 3510: escalus:send(Alice, stanza_prefs_set_request(<<"roster">>, 3511: [<<"romeo@montague.net">>, 3512: {xmlcdata, <<"\n">>}, %% Put as it is 3513: <<"montague@montague.net">>], [], 3514: mam_ns_binary_v04())), 3515: ReplySet = escalus:wait_for_stanza(Alice), 3516: 3517: escalus:send(Alice, stanza_prefs_get_request(mam_ns_binary_v04())), 3518: ReplyGet = escalus:wait_for_stanza(Alice), 3519: 3520: ResultIQ1 = parse_prefs_result_iq(ReplySet), 3521: ResultIQ2 = parse_prefs_result_iq(ReplyGet), 3522: ?assert_equal(ResultIQ1, ResultIQ2), 3523: ok 3524: end, 3525: escalus_fresh:story(Config, [{alice, 1}], F). 3526: 3527: mam_service_discovery(Config) -> 3528: F = fun(Alice) -> 3529: Server = escalus_client:server(Alice), 3530: discover_features(Config, Alice, Server) 3531: end, 3532: escalus_fresh:story(Config, [{alice, 1}], F). 3533: 3534: mam_service_discovery_to_client_bare_jid(Config) -> 3535: F = fun(Alice) -> 3536: Address = inbox_helper:to_bare_lower(Alice), 3537: discover_features(Config, Alice, Address) 3538: end, 3539: escalus_fresh:story(Config, [{alice, 1}], F). 3540: 3541: mam_service_discovery_to_different_client_bare_jid_results_in_error(Config) -> 3542: F = fun(Alice, Bob) -> 3543: Address = inbox_helper:to_bare_lower(Bob), 3544: escalus:send(Alice, escalus_stanza:disco_info(Address)), 3545: Stanza = escalus:wait_for_stanza(Alice), 3546: escalus:assert(is_error, [<<"cancel">>, <<"service-unavailable">>], Stanza) 3547: end, 3548: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 3549: 3550: %% Check, that MUC is supported. 3551: muc_service_discovery(Config) -> 3552: F = fun(Alice) -> 3553: Domain = domain(), 3554: Server = escalus_client:server(Alice), 3555: escalus:send(Alice, escalus_stanza:service_discovery(Server)), 3556: Stanza = escalus:wait_for_stanza(Alice), 3557: escalus:assert(has_service, [muc_host()], Stanza), 3558: escalus:assert(is_stanza_from, [Domain], Stanza), 3559: 3560: discover_features(Config, Alice, muc_host()) 3561: end, 3562: escalus:fresh_story(Config, [{alice, 1}], F). 3563: 3564: discover_features(Config, Client, Service) -> 3565: escalus:send(Client, escalus_stanza:disco_info(Service)), 3566: Stanza = escalus:wait_for_stanza(Client), 3567: escalus:assert(is_iq_result, Stanza), 3568: escalus:assert(has_feature, [mam_ns_binary_v04()], Stanza), 3569: escalus:assert(has_feature, [mam_ns_binary_v06()], Stanza), 3570: escalus:assert(has_feature, [mam_ns_binary_extended()], Stanza), 3571: escalus:assert(has_feature, [retract_ns()], Stanza), 3572: check_include_groupchat_features(Stanza, 3573: ?config(configuration, Config), 3574: ?config(basic_group, Config)), 3575: ?assert_equal(message_retraction_is_enabled(Config), 3576: escalus_pred:has_feature(retract_tombstone_ns(), Stanza)). 3577: 3578: metric_incremented_on_archive_request(ConfigIn) -> 3579: P = ?config(props, ConfigIn), 3580: F = fun(Alice) -> 3581: escalus:send(Alice, stanza_archive_request(P, <<"metric_q1">>)), 3582: Res = wait_archive_respond(Alice), 3583: assert_respond_size(0, Res), 3584: assert_respond_query_id(P, <<"metric_q1">>, parse_result_iq(Res)), 3585: ok 3586: end, 3587: HostType = domain_helper:host_type(mim), 3588: HostTypePrefix = domain_helper:make_metrics_prefix(HostType), 3589: MongooseMetrics = [{[HostTypePrefix, backends, mod_mam_pm, lookup], changed}], 3590: Config = [{mongoose_metrics, MongooseMetrics} | ConfigIn], 3591: escalus_fresh:story(Config, [{alice, 1}], F). 3592: 3593: metrics_incremented_for_async_pools(Config) -> 3594: OldValue = get_mongoose_async_metrics(), 3595: archived(Config), 3596: Validator = fun(NewValue) -> OldValue =/= NewValue end, 3597: mongoose_helper:wait_until( 3598: fun get_mongoose_async_metrics/0, 3599: Validator, #{name => ?FUNCTION_NAME}). 3600: 3601: get_mongoose_async_metrics() -> 3602: HostType = domain_helper:host_type(mim), 3603: HostTypePrefix = domain_helper:make_metrics_prefix(HostType), 3604: #{batch_flushes => get_mongoose_async_metrics(HostTypePrefix, batch_flushes), 3605: timed_flushes => get_mongoose_async_metrics(HostTypePrefix, timed_flushes)}. 3606: 3607: get_mongoose_async_metrics(HostTypePrefix, MetricName) -> 3608: Metric = [HostTypePrefix, mongoose_async_pools, pm_mam, MetricName], 3609: {ok, Value} = rpc(mim(), mongoose_metrics, get_metric_value, [Metric]), 3610: {value, Count} = lists:keyfind(value, 1, Value), 3611: Count. 3612: 3613: metric_incremented_when_store_message(Config) -> 3614: archived(Config). 3615: 3616: messages_filtered_when_prefs_default_policy_is_always(Config) -> 3617: run_prefs_cases(always, Config). 3618: 3619: messages_filtered_when_prefs_default_policy_is_never(Config) -> 3620: run_prefs_cases(never, Config). 3621: 3622: messages_filtered_when_prefs_default_policy_is_roster(Config) -> 3623: run_prefs_cases(roster, Config). 3624: 3625: 3626: -spec enter_room(Config :: proplists:proplist(), [User :: term()]) -> 3627: {Room :: binary(), RoomAddr :: binary()}. 3628: enter_room(Config, Users) -> 3629: Room = ?config(room, Config), 3630: RoomAddr = room_address(Room), 3631: [escalus:send(User, stanza_muc_enter_room(Room, nick(User))) || User <- Users], 3632: {Room, RoomAddr}. 3633: 3634: %% First write all messages, than read and check 3635: run_prefs_cases(DefaultPolicy, ConfigIn) -> 3636: P = ?config(props, ConfigIn), 3637: F = fun(Config, Alice, Bob, Kate) -> 3638: make_alice_and_bob_friends(Alice, Bob), 3639: %% Just send messages for each prefs configuration 3640: Namespace = mam_ns_binary_v04(), 3641: Funs = [run_prefs_case(Case, Namespace, Alice, Bob, Kate, Config) 3642: || Case <- prefs_cases2(), 3643: default_policy(Case) =:= DefaultPolicy], 3644: 3645: maybe_wait_for_archive(Config), 3646: 3647: %% Get ALL messages using several queries if required 3648: Stanzas = get_all_messages(P, Alice), 3649: ParsedMessages = parse_messages(Stanzas), 3650: Bodies = [B || #forwarded_message{message_body=B} <- ParsedMessages], 3651: 3652: %% Check messages, print out all failed cases 3653: Fails = lists:append([Fun(Bodies) || Fun <- Funs]), 3654: %% If fails consult with ct:pal/2 why 3655: ?assert_equal([], Fails) 3656: end, 3657: escalus_fresh:story_with_config(ConfigIn, [{alice, 1}, {bob, 1}, {kate, 1}], F). 3658: 3659: %% The same as prefs_set_request case but for different configurations 3660: run_set_and_get_prefs_cases(ConfigIn) -> 3661: F = fun(Config, Alice, _Bob, _Kate) -> 3662: Namespace = mam_ns_binary_v04(), 3663: [run_set_and_get_prefs_case(Case, Namespace, Alice, Config) || Case <- prefs_cases2()] 3664: end, 3665: escalus_fresh:story_with_config(ConfigIn, [{alice, 1}, {bob, 1}, {kate, 1}], F). 3666: 3667: %% MAM's implementation specific test 3668: check_user_exist(Config) -> 3669: %% when 3670: [{_, AdminSpec}] = escalus_users:get_users([admin]), 3671: [AdminU, AdminS, AdminP] = escalus_users:get_usp(Config, AdminSpec), 3672: JID = mongoose_helper:make_jid(AdminU, AdminS), 3673: ok = rpc(mim(), ejabberd_auth, try_register, [JID, AdminP]), 3674: %% admin user already registered 3675: {ok, HostType} = rpc(mim(), mongoose_domain_core, get_host_type, [AdminS]), 3676: true = rpc(mim(), ejabberd_auth, does_user_exist, 3677: [HostType, JID, stored]), 3678: false = rpc(mim(), ejabberd_auth, does_user_exist, 3679: [HostType, mongoose_helper:make_jid(<<"fake-user">>, AdminS), stored]), 3680: false = rpc(mim(), ejabberd_auth, does_user_exist, 3681: [HostType, mongoose_helper:make_jid(AdminU, <<"fake-domain">>), stored]), 3682: %% cleanup 3683: ok = rpc(mim(), ejabberd_auth, remove_user, [JID]). 3684: 3685: %% This function supports only one device, one user. 3686: %% We don't send initial presence to avoid presence broadcasts between resources 3687: %% of the same user from different stories. 3688: %% It is limited comparing to escalus story, but reduces CPU usage, because we don't 3689: %% need to send any presences. 3690: parallel_story(Config, [{_, 1}] = ResourceCounts, F) -> 3691: Config1 = override_for_parallel(Config), 3692: escalus:story(Config1, ResourceCounts, F). 3693: 3694: override_for_parallel(Config) -> 3695: Overrides = [ 3696: {start_ready_clients, start_ready_clients()} 3697: ], 3698: [{escalus_overrides, Overrides} | Config]. 3699: 3700: start_ready_clients() -> 3701: fun(Config, [{UserSpec, BaseResource}]) -> 3702: Suffix = list_to_binary(pid_to_list(self()) -- "<>"), 3703: Resource = <<BaseResource/binary, Suffix/binary>>, 3704: {ok, Client} = escalus_client:start(Config, UserSpec, Resource), 3705: [Client] 3706: end. 3707: 3708: text_search_messages() -> 3709: [ 3710: <<"Tongue chicken jowl hamburger duis exercitation.">>, 3711: <<"Ribs eu aliquip pork veniam dolor jowl id laborum in frankfurter culpa ribs.">>, 3712: <<"Fatback ut labore pariatur, eiusmod esse dolore turducken jowl exercitation ", 3713: "shankle shoulder.">>, 3714: <<"Kevin ribeye short ribs, nostrud short loin quis voluptate cow. Do brisket eu ", 3715: "sunt tail ullamco cow in bacon burgdoggen.">>, 3716: <<"Occaecat in voluptate incididunt aliqua dolor bacon salami anim picanha pork ", 3717: "reprehenderit pancetta tail.">>, 3718: <<"Nisi shank doner dolore officia ribeye. Proident shankle tenderloin consequat ", 3719: "bresaola quis tongue ut sirloin pork chop pariatur fatback ex cupidatat venison.">>, 3720: <<"Brisket in pastrami dolore cupidatat. Est corned beef ad ribeye ball tip aliqua ", 3721: "cupidatat andouille cillum et consequat leberkas.">>, 3722: <<"Qui mollit short ribs, capicola bresaola pork meatloaf kielbasa und culpa.">>, 3723: <<"Meatloaf esse jowl do ham hock consequat. Duis laboris ribeye ullamco, sed elit ", 3724: "porchetta sirloin.">>, 3725: <<"In boudin ad et salami exercitation sausage flank strip steak ball tip dolore ", 3726: "pig officia.">>, 3727: <<"Spare ribs landjaeger pork belly, chuck aliquip turducken beef culpa nostrud.">> 3728: ]. 3729: 3730: %% --------- MUC Light stories helpers ---------- 3731: 3732: when_pm_message_is_sent(Sender, Receiver, Body) -> 3733: escalus:send(Sender, escalus_stanza:chat_to(Receiver, Body)). 3734: 3735: then_pm_message_is_received(Receiver, Body) -> 3736: escalus:assert(is_chat_message, [Body], escalus:wait_for_stanza(Receiver)). 3737: 3738: %% Message retraction helpers 3739: 3740: check_archive_after_retraction(Config, Client, ApplyToElement, Body) -> 3741: case message_should_be_retracted(Config) of 3742: true -> expect_tombstone_and_retraction_message(Client, ApplyToElement); 3743: false -> expect_original_and_retraction_message(Client, ApplyToElement, Body); 3744: ignore -> expect_only_original_message(Client, Body) 3745: end. 3746: 3747: message_should_be_retracted(Config) -> 3748: message_retraction_is_enabled(Config) andalso retraction_requested(Config). 3749: 3750: retraction_requested(Config) -> 3751: OriginId = origin_id(), 3752: case lists:keyfind(retract_on, 1, Config) of 3753: {retract_on, none} -> ignore; 3754: {retract_on, stanza_id} -> true; 3755: {retract_on, {origin_id, OriginId}} -> true; 3756: _ -> false 3757: end. 3758: 3759: message_retraction_is_enabled(Config) -> 3760: BasicGroup = ?config(basic_group, Config), 3761: BasicGroup =/= disabled_retraction andalso BasicGroup =/= muc_disabled_retraction. 3762: 3763: check_include_groupchat_features(Stanza, cassandra, _BasicGroup) -> 3764: ?assertNot(escalus_pred:has_feature(groupchat_field_ns(), Stanza)), 3765: ?assertNot(escalus_pred:has_feature(groupchat_available_ns(), Stanza)); 3766: check_include_groupchat_features(Stanza, _Configuration, muc_light) -> 3767: escalus:assert(has_feature, [groupchat_field_ns()], Stanza), 3768: escalus:assert(has_feature, [groupchat_available_ns()], Stanza); 3769: check_include_groupchat_features(Stanza, _Configuration, muc_all) -> 3770: ?assertNot(escalus_pred:has_feature(groupchat_field_ns(), Stanza)), 3771: ?assertNot(escalus_pred:has_feature(groupchat_available_ns(), Stanza)); 3772: check_include_groupchat_features(Stanza, _Configuration, _BasicGroup) -> 3773: escalus:assert(has_feature, [groupchat_field_ns()], Stanza), 3774: ?assertNot(escalus_pred:has_feature(groupchat_available_ns(), Stanza)). 3775: 3776: expect_tombstone_and_retraction_message(Client, ApplyToElement) -> 3777: [ArcMsg1, ArcMsg2] = respond_messages(assert_respond_size(2, wait_archive_respond(Client))), 3778: #forwarded_message{message_body = undefined, 3779: message_children = [#xmlel{name = <<"retracted">>}]} = parse_forwarded_message(ArcMsg1), 3780: #forwarded_message{message_body = undefined, 3781: message_children = [ApplyToElement]} = parse_forwarded_message(ArcMsg2). 3782: 3783: expect_original_and_retraction_message(Client, ApplyToElement, Body) -> 3784: [ArcMsg1, ArcMsg2] = respond_messages(assert_respond_size(2, wait_archive_respond(Client))), 3785: #forwarded_message{message_body = Body} = parse_forwarded_message(ArcMsg1), 3786: #forwarded_message{message_body = undefined, 3787: message_children = [ApplyToElement]} = parse_forwarded_message(ArcMsg2). 3788: 3789: expect_only_original_message(Client, Body) -> 3790: [ArcMsg1] = respond_messages(assert_respond_size(1, wait_archive_respond(Client))), 3791: #forwarded_message{message_body = Body} = parse_forwarded_message(ArcMsg1). 3792: 3793: retraction_message(Type, To, ApplyToElement) -> 3794: #xmlel{name = <<"message">>, 3795: attrs = [{<<"type">>, Type}, 3796: {<<"to">>, To}], 3797: children = [ApplyToElement]}. 3798: 3799: origin_id_element(OriginId) -> 3800: #xmlel{name = <<"origin-id">>, 3801: attrs = [{<<"xmlns">>, <<"urn:xmpp:sid:0">>}, 3802: {<<"id">>, OriginId}]}. 3803: 3804: apply_to_element(Config, Copy) -> 3805: {RetractOn, Id} = case ?config(retract_on, Config) of 3806: {origin_id, OrigId} -> {origin_id, OrigId}; 3807: stanza_id -> {stanza_id, stanza_id_from_msg(Copy)}; 3808: none -> {origin_id, none} 3809: end, 3810: #xmlel{name = <<"apply-to">>, 3811: attrs = [{<<"xmlns">>, <<"urn:xmpp:fasten:0">>} | maybe_append_id(Id)], 3812: children = [retract_element(RetractOn)] 3813: }. 3814: 3815: maybe_append_id(none) -> 3816: []; 3817: maybe_append_id(Id) -> 3818: [{<<"id">>, Id}]. 3819: 3820: stanza_id_from_msg(Msg) -> 3821: case exml_query:path(Msg, [{element, <<"stanza-id">>}, {attr, <<"id">>}]) of 3822: undefined -> exml_query:path(Msg, [{element, <<"result">>}, {attr, <<"id">>}]); 3823: Id -> Id 3824: end. 3825: 3826: retract_element(origin_id) -> 3827: #xmlel{name = <<"retract">>, 3828: attrs = [{<<"xmlns">>, <<"urn:xmpp:message-retract:0">>}]}; 3829: retract_element(stanza_id) -> 3830: #xmlel{name = <<"retract">>, 3831: attrs = [{<<"xmlns">>, <<"urn:esl:message-retract-by-stanza-id:0">>}]}. 3832: 3833: origin_id() -> 3834: <<"orig-id-1">>. 3835: 3836: simple_range(From, To, IsComplete) -> 3837: #{total_count => undefined, offset => undefined, 3838: from => From, to => To, is_complete => IsComplete, step => 1}. 3839: 3840: pagination_test(Name, RSM, Range, Config) -> 3841: P = ?config(props, Config), 3842: F = fun(Alice) -> 3843: rsm_send(Config, Alice, stanza_page_archive_request(P, atom_to_binary(Name), RSM)), 3844: wait_message_range(Alice, Range) 3845: end, 3846: parallel_story(Config, [{alice, 1}], F). 3847: 3848: assert_failed_to_decode_message(ArcMsg) -> 3849: Forwarded = parse_forwarded_message(ArcMsg), 3850: Err = <<"Failed to decode message in database">>, 3851: ?assertMatch(#forwarded_message{message_body = Err}, Forwarded), 3852: ?assertMatch(#forwarded_message{message_type = <<"error">>}, Forwarded), 3853: #forwarded_message{message_children = [Msg]} = Forwarded, 3854: ?assertMatch(#xmlel{ 3855: name = <<"error">>, 3856: attrs = [{<<"code">>, <<"500">>}, {<<"type">>,<<"wait">>}], 3857: children = [#xmlel{name = <<"internal-server-error">>}, 3858: #xmlel{name = <<"text">>, children = [#xmlcdata{content = Err}]}]}, Msg).