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: [{mod_domain_isolation, []}, 46: {mod_muc_light, mod_config(mod_muc_light, #{host => MucHost})}]. 47: 48: init_per_group(two_domains, Config) -> 49: Config2 = dynamic_modules:save_modules(host_types(), Config), 50: [dynamic_modules:ensure_modules(HostType, modules()) || HostType <- host_types()], 51: Config2. 52: 53: end_per_group(two_domains, Config) -> 54: escalus_fresh:clean(), 55: dynamic_modules:restore_modules(Config), 56: Config. 57: 58: init_per_testcase(Testcase, Config) -> 59: escalus:init_per_testcase(Testcase, Config). 60: 61: end_per_testcase(Testcase, Config) -> 62: escalus:end_per_testcase(Testcase, Config). 63: 64: %%-------------------------------------------------------------------- 65: %% Tests 66: %%-------------------------------------------------------------------- 67: 68: routing_one2one_message_inside_one_domain_works(Config) -> 69: F = fun(Alice, Bob) -> 70: %% WHEN Routed inside the same domain 71: escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hello">>)), 72: %% THEN Message gets delivered 73: Stanza = escalus:wait_for_stanza(Alice), 74: escalus:assert(is_chat_message, [<<"Hello">>], Stanza) 75: end, 76: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], F). 77: 78: routing_one2one_message_to_another_domain_gets_dropped(Config) -> 79: F = fun(Alice, Bob, Bis) -> 80: %% GIVEN Alice and Bis are on different domains 81: %% WHEN A stanza is sent to another domain 82: escalus_client:send(Bis, escalus_stanza:chat_to(Alice, <<"Hello">>)), 83: %% THEN Receiver does not receive a message 84: verify_alice_has_no_pending_messages(Alice, Bob) 85: end, 86: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {alice_bis, 1}], F). 87: 88: routing_one2one_message_to_another_domain_results_in_service_unavailable(Config) -> 89: F = fun(Alice, Bis) -> 90: %% GIVEN Alice and Bis are on different domains 91: %% WHEN A stanza is sent to another domain 92: escalus_client:send(Bis, escalus_stanza:chat_to(Alice, <<"Hello">>)), 93: %% THEN Sender receives an error 94: receives_service_unavailable(Bis) 95: end, 96: escalus:fresh_story(Config, [{alice, 1}, {alice_bis, 1}], F). 97: 98: routing_to_yours_subdomain_gets_passed_to_muc_module(Config) -> 99: F = fun(Alice) -> 100: %% GIVEN Alice is on the same domain 101: %% WHEN Alice routes a stanza 102: escalus_client:send(Alice, invalid_muc_stanza()), 103: %% THEN Alice receives an error from mod_muc, 104: %% like if there is no mod_domain_isolation. 105: receives_muc_bad_request(Alice) 106: end, 107: escalus:fresh_story(Config, [{alice, 1}], F). 108: 109: routing_to_foreign_subdomain_results_in_service_unavailable(Config) -> 110: F = fun(Alice) -> 111: %% GIVEN Alice is on another domain 112: %% WHEN Alice routes a stanza 113: escalus_client:send(Alice, invalid_muc_stanza()), 114: %% THEN Sender receives an error about the drop 115: receives_service_unavailable(Alice) 116: end, 117: escalus:fresh_story(Config, [{alice_bis, 1}], F). 118: 119: %%-------------------------------------------------------------------- 120: %% Helpers 121: %%-------------------------------------------------------------------- 122: 123: get_error_text(Err) -> 124: exml_query:path(Err, [{element, <<"error">>}, {element, <<"text">>}, cdata]). 125: 126: invalid_muc_address() -> 127: MucHost = muc_helper:muc_host(), 128: <<MucHost/binary, "/wow_resource_not_so_empty">>. 129: 130: invalid_muc_stanza() -> 131: escalus_stanza:chat_to(invalid_muc_address(), <<"Hi muc!">>). 132: 133: receives_service_unavailable(Alice) -> 134: Err = escalus:wait_for_stanza(Alice), 135: escalus:assert(is_error, [<<"cancel">>, <<"service-unavailable">>], Err), 136: <<"Filtered by the domain isolation">> = get_error_text(Err). 137: 138: receives_muc_bad_request(Alice) -> 139: Err = escalus:wait_for_stanza(Alice), 140: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], Err), 141: %% This error is generated by mod_muc: 142: <<"Resource expected to be empty">> = get_error_text(Err). 143: 144: %% Verify than there is no unreceived messages by Alice by routing a message from Bob. 145: %% Bob should be able to send messages to Alice. 146: %% If the Bob's message gets received - there is no pending messages. 147: verify_alice_has_no_pending_messages(Alice, Bob) -> 148: escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Forces to flush">>)), 149: Stanza = escalus:wait_for_stanza(Alice), 150: escalus:assert(is_chat_message, [<<"Forces to flush">>], Stanza).