1: -module(disco_and_caps_SUITE). 2: -compile([export_all, nowarn_export_all]). 3: 4: -include_lib("eunit/include/eunit.hrl"). 5: -include_lib("escalus/include/escalus_xmlns.hrl"). 6: 7: -import(domain_helper, [host_type/0, domain/0]). 8: 9: all() -> 10: [{group, disco_with_caps}, 11: {group, disco_with_extra_features}]. 12: 13: groups() -> 14: G = [{disco_with_caps, [parallel], basic_test_cases() ++ caps_test_cases()}, 15: {disco_with_extra_features, [parallel], basic_test_cases() ++ extra_feature_test_cases()}], 16: ct_helper:repeat_all_until_all_ok(G). 17: 18: basic_test_cases() -> 19: [user_cannot_query_stranger_resources, 20: user_cannot_query_stranger_features, 21: user_can_query_friend_resources, 22: user_can_query_friend_features, 23: user_cannot_query_own_resources_with_unknown_node, 24: user_cannot_query_friend_resources_with_unknown_node, 25: user_can_query_server_features]. 26: 27: caps_test_cases() -> 28: [caps_feature_is_advertised, 29: user_can_query_server_caps_via_disco]. 30: 31: extra_feature_test_cases() -> 32: [user_can_query_extra_domains, 33: user_can_query_server_info]. 34: 35: init_per_suite(C) -> 36: C. 37: 38: end_per_suite(C) -> 39: escalus_fresh:clean(), 40: escalus:end_per_suite(C). 41: 42: init_per_group(Name, C) -> 43: C2 = escalus:init_per_suite(dynamic_modules:save_modules(host_type(), C)), 44: dynamic_modules:ensure_modules(host_type(), required_modules(Name)), 45: C2. 46: 47: end_per_group(_Name, C) -> 48: dynamic_modules:restore_modules(C). 49: 50: init_per_testcase(Name, C) -> 51: escalus:init_per_testcase(Name, C). 52: 53: end_per_testcase(Name, C) -> 54: escalus:end_per_testcase(Name, C). 55: 56: caps_feature_is_advertised(Config) -> 57: Spec = escalus_users:get_userspec(Config, alice), 58: {ok, Connection, Features} = escalus_connection:start(Spec, [start_stream, stream_features]), 59: true = is_map(proplists:get_value(caps, Features)), 60: escalus_connection:stop(Connection). 61: 62: user_can_query_server_caps_via_disco(Config) -> 63: NewConfig = escalus_fresh:create_users(Config, [{alice, 1}]), 64: Spec = escalus_users:get_userspec(NewConfig, alice), 65: {ok, Alice, Features} = escalus_connection:start(Spec), 66: #{<<"node">> := Node, 67: <<"ver">> := Ver} = proplists:get_value(caps, Features), 68: NodeVer = <<Node/binary, $#, Ver/binary>>, 69: Server = proplists:get_value(server, Spec), 70: Disco = escalus_stanza:disco_info(Server, NodeVer), 71: escalus:send(Alice, Disco), 72: DiscoResp = escalus:wait_for_stanza(Alice), 73: escalus:assert(is_iq_result, [Disco], DiscoResp), 74: Identity = exml_query:path(DiscoResp, [{element, <<"query">>}, 75: {element, <<"identity">>}, 76: {attr, <<"name">>}]), 77: <<"MongooseIM">> = Identity, 78: escalus_connection:stop(Alice). 79: 80: user_cannot_query_stranger_resources(Config) -> 81: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 82: BobJid = escalus_client:short_jid(Bob), 83: Request = escalus_stanza:disco_items(BobJid), 84: escalus:send(Alice, Request), 85: Stanza = escalus:wait_for_stanza(Alice), 86: escalus:assert(is_iq_error, [Request], Stanza), 87: escalus:assert(is_error, [<<"cancel">>, <<"service-unavailable">>], Stanza), 88: escalus:assert(is_stanza_from, [BobJid], Stanza) 89: end). 90: 91: user_cannot_query_stranger_features(Config) -> 92: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 93: BobJid = escalus_client:short_jid(Bob), 94: Request = escalus_stanza:disco_info(BobJid), 95: escalus:send(Alice, Request), 96: Stanza = escalus:wait_for_stanza(Alice), 97: escalus:assert(is_iq_error, [Request], Stanza), 98: escalus:assert(is_error, [<<"cancel">>, <<"service-unavailable">>], Stanza), 99: escalus:assert(is_stanza_from, [BobJid], Stanza) 100: end). 101: 102: user_can_query_friend_resources(Config) -> 103: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 104: escalus_story:make_all_clients_friends([Alice, Bob]), 105: BobJid = escalus_client:short_jid(Bob), 106: escalus:send(Alice, escalus_stanza:disco_items(BobJid)), 107: Stanza = escalus:wait_for_stanza(Alice), 108: Query = exml_query:subelement(Stanza, <<"query">>), 109: BobFullJid = escalus_client:full_jid(Bob), 110: BobName = escalus_client:username(Bob), 111: Item = exml_query:subelement_with_attr(Query, <<"jid">>, BobFullJid), 112: ?assertEqual(BobName, exml_query:attr(Item, <<"name">>)), 113: escalus:assert(is_stanza_from, [BobJid], Stanza) 114: end). 115: 116: user_can_query_friend_features(Config) -> 117: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 118: escalus_story:make_all_clients_friends([Alice, Bob]), 119: BobJid = escalus_client:short_jid(Bob), 120: escalus:send(Alice, escalus_stanza:disco_info(BobJid)), 121: Stanza = escalus:wait_for_stanza(Alice), 122: escalus:assert(has_identity, [<<"account">>, <<"registered">>], Stanza), 123: escalus:assert(is_stanza_from, [BobJid], Stanza) 124: end). 125: 126: user_cannot_query_own_resources_with_unknown_node(Config) -> 127: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 128: AliceJid = escalus_client:short_jid(Alice), 129: Request = escalus_stanza:disco_items(AliceJid, <<"unknown-node">>), 130: escalus:send(Alice, Request), 131: Stanza = escalus:wait_for_stanza(Alice), 132: escalus:assert(is_iq_error, [Request], Stanza), 133: escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Stanza), 134: escalus:assert(is_stanza_from, [AliceJid], Stanza) 135: end). 136: 137: user_cannot_query_friend_resources_with_unknown_node(Config) -> 138: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 139: escalus_story:make_all_clients_friends([Alice, Bob]), 140: BobJid = escalus_client:short_jid(Bob), 141: Request = escalus_stanza:disco_items(BobJid, <<"unknown-node">>), 142: escalus:send(Alice, Request), 143: Stanza = escalus:wait_for_stanza(Alice), 144: escalus:assert(is_iq_error, [Request], Stanza), 145: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Stanza), 146: escalus:assert(is_stanza_from, [BobJid], Stanza) 147: end). 148: 149: user_can_query_extra_domains(Config) -> 150: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 151: Server = escalus_client:server(Alice), 152: escalus:send(Alice, escalus_stanza:service_discovery(Server)), 153: Stanza = escalus:wait_for_stanza(Alice), 154: escalus:assert(has_service, [extra_domain()], Stanza), 155: escalus:assert(is_stanza_from, [domain()], Stanza) 156: end). 157: 158: user_can_query_server_features(Config) -> 159: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 160: Server = escalus_client:server(Alice), 161: escalus:send(Alice, escalus_stanza:disco_info(Server)), 162: Stanza = escalus:wait_for_stanza(Alice), 163: escalus:assert(has_identity, [<<"server">>, <<"im">>], Stanza), 164: escalus:assert(has_feature, [<<"iq">>], Stanza), 165: escalus:assert(has_feature, [<<"presence">>], Stanza), 166: escalus:assert(has_feature, [<<"presence-invisible">>], Stanza), 167: escalus:assert(is_stanza_from, [domain()], Stanza) 168: end). 169: 170: %% XEP-0157: Contact Addresses for XMPP Services 171: user_can_query_server_info(Config) -> 172: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 173: Server = escalus_client:server(Alice), 174: escalus:send(Alice, escalus_stanza:disco_info(Server)), 175: Stanza = escalus:wait_for_stanza(Alice), 176: escalus:assert(is_stanza_from, [domain()], Stanza), 177: 178: %% 'sales' is hidden for mod_disco, so only 'abuse' and 'admin' are expected 179: [HiddenField, AbuseField, AdminField] = get_form_fields(Stanza), 180: ?assertEqual(<<"FORM_TYPE">>, exml_query:attr(HiddenField, <<"var">>)), 181: ?assertEqual(<<"hidden">>, exml_query:attr(HiddenField, <<"type">>)), 182: ?assertEqual([?NS_SERVERINFO], exml_query:paths(HiddenField, [{element, <<"value">>}, 183: cdata])), 184: ?assertEqual(name(abuse), exml_query:attr(AbuseField, <<"var">>)), 185: ?assertEqual(urls(abuse), exml_query:paths(AbuseField, [{element, <<"value">>}, 186: cdata])), 187: ?assertEqual(name(admin), exml_query:attr(AdminField, <<"var">>)), 188: ?assertEqual(urls(admin), exml_query:paths(AdminField, [{element, <<"value">>}, 189: cdata])) 190: end). 191: 192: %% Helpers 193: 194: required_modules(disco_with_caps) -> 195: [{mod_caps, []}, 196: {mod_disco, []}]; 197: required_modules(disco_with_extra_features) -> 198: [{mod_disco, [{extra_domains, [extra_domain()]}, 199: {server_info, [server_info(abuse, []), 200: server_info(admin, [{modules, [mod_disco]}]), 201: server_info(sales, [{modules, [mod_pubsub]}])] 202: }] 203: }]. 204: 205: get_form_fields(Stanza) -> 206: exml_query:paths(Stanza, [{element_with_ns, <<"query">>, ?NS_DISCO_INFO}, 207: {element_with_ns, <<"x">>, ?NS_DATA_FORMS}, 208: {element, <<"field">>}]). 209: 210: extra_domain() -> 211: <<"eXtra.example.com">>. 212: 213: server_info(Type, Extra) -> 214: [{name, name(Type)}, {urls, urls(Type)} | Extra]. 215: 216: name(abuse) -> <<"abuse-addresses">>; 217: name(admin) -> <<"admin-addresses">>; 218: name(sales) -> <<"sales-addresses">>. 219: 220: urls(abuse) -> [<<"abuse@example.com">>]; 221: urls(admin) -> [<<"admin@example.com">>, <<"operations@example.com">>]; 222: urls(sales) -> [<<"sales@example.com">>].