1: -module(domain_isolation_SUITE). 2: 3: -include_lib("common_test/include/ct.hrl"). 4: -include_lib("eunit/include/eunit.hrl"). 5: 6: -compile([export_all, nowarn_export_all]). 7: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4, subhost_pattern/1]). 8: -import(domain_helper, [host_type/0, secondary_host_type/0]). 9: -import(config_parser_helper, [mod_config/2]). 10: 11: suite() -> 12: require_rpc_nodes([mim]). 13: 14: all() -> 15: [{group, two_domains}]. 16: 17: groups() -> 18: [{two_domains, [parallel], cases()}]. 19: 20: cases() -> 21: [routing_one2one_message_inside_one_domain_works, 22: routing_one2one_message_to_another_domain_gets_dropped, 23: routing_one2one_message_to_another_domain_results_in_service_unavailable, 24: routing_to_yours_subdomain_gets_passed_to_muc_module, 25: routing_to_foreign_subdomain_results_in_service_unavailable]. 26: 27: host_types() -> 28: %% This suite tests domain isolation. 29: %% But two domains could be on the same host type, and still should be isolated. 30: %% So, we could need to init modules only once. 31: lists:usort([host_type(), secondary_host_type()]). 32: 33: %%-------------------------------------------------------------------- 34: %% Init & teardown 35: %%-------------------------------------------------------------------- 36: 37: init_per_suite(Config) -> 38: escalus:init_per_suite(Config). 39: 40: end_per_suite(Config) -> 41: escalus:end_per_suite(Config). 42: 43: modules() -> 44: MucHost = subhost_pattern(muc_helper:muc_host_pattern()), 45: Backend = mongoose_helper:mnesia_or_rdbms_backend(), 46: [{mod_domain_isolation, []}, 47: {mod_muc_light, mod_config(mod_muc_light, #{host => MucHost, backend => Backend})}]. 48: 49: init_per_group(two_domains, Config) -> 50: Config2 = dynamic_modules:save_modules(host_types(), Config), 51: [dynamic_modules:ensure_modules(HostType, modules()) || HostType <- host_types()], 52: Config2. 53: 54: end_per_group(two_domains, Config) -> 55: escalus_fresh:clean(), 56: dynamic_modules:restore_modules(Config), 57: Config. 58: 59: init_per_testcase(Testcase, Config) -> 60: escalus:init_per_testcase(Testcase, Config). 61: 62: end_per_testcase(Testcase, Config) -> 63: escalus:end_per_testcase(Testcase, Config). 64: 65: %%-------------------------------------------------------------------- 66: %% Tests 67: %%-------------------------------------------------------------------- 68: 69: routing_one2one_message_inside_one_domain_works(Config) -> 70: F = fun(Alice, Bob) -> 71: %% WHEN Routed inside the same domain 72: escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hello">>)), 73: %% THEN Message gets delivered 74: Stanza = escalus:wait_for_stanza(Alice), 75: escalus:assert(is_chat_message, [<<"Hello">>], Stanza) 76: end, 77: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], F). 78: 79: routing_one2one_message_to_another_domain_gets_dropped(Config) -> 80: F = fun(Alice, Bob, Bis) -> 81: %% GIVEN Alice and Bis are on different domains 82: %% WHEN A stanza is sent to another domain 83: escalus_client:send(Bis, escalus_stanza:chat_to(Alice, <<"Hello">>)), 84: %% THEN Receiver does not receive a message 85: verify_alice_has_no_pending_messages(Alice, Bob) 86: end, 87: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {alice_bis, 1}], F). 88: 89: routing_one2one_message_to_another_domain_results_in_service_unavailable(Config) -> 90: F = fun(Alice, Bis) -> 91: %% GIVEN Alice and Bis are on different domains 92: %% WHEN A stanza is sent to another domain 93: escalus_client:send(Bis, escalus_stanza:chat_to(Alice, <<"Hello">>)), 94: %% THEN Sender receives an error 95: receives_service_unavailable(Bis) 96: end, 97: escalus:fresh_story(Config, [{alice, 1}, {alice_bis, 1}], F). 98: 99: routing_to_yours_subdomain_gets_passed_to_muc_module(Config) -> 100: F = fun(Alice) -> 101: %% GIVEN Alice is on the same domain 102: %% WHEN Alice routes a stanza 103: escalus_client:send(Alice, invalid_muc_stanza()), 104: %% THEN Alice receives an error from mod_muc, 105: %% like if there is no mod_domain_isolation. 106: receives_muc_bad_request(Alice) 107: end, 108: escalus:fresh_story(Config, [{alice, 1}], F). 109: 110: routing_to_foreign_subdomain_results_in_service_unavailable(Config) -> 111: F = fun(Alice) -> 112: %% GIVEN Alice is on another domain 113: %% WHEN Alice routes a stanza 114: escalus_client:send(Alice, invalid_muc_stanza()), 115: %% THEN Sender receives an error about the drop 116: receives_service_unavailable(Alice) 117: end, 118: escalus:fresh_story(Config, [{alice_bis, 1}], F). 119: 120: %%-------------------------------------------------------------------- 121: %% Helpers 122: %%-------------------------------------------------------------------- 123: 124: get_error_text(Err) -> 125: exml_query:path(Err, [{element, <<"error">>}, {element, <<"text">>}, cdata]). 126: 127: invalid_muc_address() -> 128: MucHost = muc_helper:muc_host(), 129: <<MucHost/binary, "/wow_resource_not_so_empty">>. 130: 131: invalid_muc_stanza() -> 132: escalus_stanza:chat_to(invalid_muc_address(), <<"Hi muc!">>). 133: 134: receives_service_unavailable(Alice) -> 135: Err = escalus:wait_for_stanza(Alice), 136: escalus:assert(is_error, [<<"cancel">>, <<"service-unavailable">>], Err), 137: <<"Filtered by the domain isolation">> = get_error_text(Err). 138: 139: receives_muc_bad_request(Alice) -> 140: Err = escalus:wait_for_stanza(Alice), 141: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], Err), 142: %% This error is generated by mod_muc: 143: <<"Resource expected to be empty">> = get_error_text(Err). 144: 145: %% Verify than there is no unreceived messages by Alice by routing a message from Bob. 146: %% Bob should be able to send messages to Alice. 147: %% If the Bob's message gets received - there is no pending messages. 148: verify_alice_has_no_pending_messages(Alice, Bob) -> 149: escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Forces to flush">>)), 150: Stanza = escalus:wait_for_stanza(Alice), 151: escalus:assert(is_chat_message, [<<"Forces to flush">>], Stanza).