1: -module(graphql_stanza_SUITE). 2: 3: -include_lib("common_test/include/ct.hrl"). 4: -include_lib("eunit/include/eunit.hrl"). 5: -include_lib("exml/include/exml.hrl"). 6: 7: -compile([export_all, nowarn_export_all]). 8: 9: -import(distributed_helper, [require_rpc_nodes/1]). 10: -import(graphql_helper, [execute_auth/2]). 11: 12: suite() -> 13: require_rpc_nodes([mim]) ++ escalus:suite(). 14: 15: all() -> 16: [{group, admin_stanza_category}]. 17: 18: groups() -> 19: [{admin_stanza_category, [parallel], admin_stanza_category()}]. 20: 21: admin_stanza_category() -> 22: [send_message, 23: send_message_to_unparsable_jid, 24: send_message_headline, 25: send_stanza, 26: send_unparsable_stanza, 27: send_stanza_from_unknown_user, 28: send_stanza_from_unknown_domain, 29: get_last_messages, 30: get_last_messages_for_unknown_user, 31: get_last_messages_with, 32: get_last_messages_limit, 33: get_last_messages_limit_enforced, 34: get_last_messages_before]. 35: 36: init_per_suite(Config) -> 37: Config1 = escalus:init_per_suite(Config), 38: dynamic_modules:save_modules(domain_helper:host_type(), Config1). 39: 40: end_per_suite(Config) -> 41: escalus_fresh:clean(), 42: dynamic_modules:restore_modules(Config), 43: escalus:end_per_suite(Config). 44: 45: init_per_group(admin_stanza_category, Config) -> 46: Config2 = graphql_helper:init_admin_handler(Config), 47: init_mam(Config2); 48: init_per_group(_, Config) -> 49: Config. 50: 51: end_per_group(admin_stanza_category, _Config) -> 52: dynamic_modules:ensure_stopped(domain_helper:host_type(), [mod_mam_meta]); 53: end_per_group(_, _Config) -> 54: ok. 55: 56: init_per_testcase(CaseName, Config) -> 57: escalus:init_per_testcase(CaseName, Config). 58: 59: end_per_testcase(CaseName, Config) -> 60: escalus:end_per_testcase(CaseName, Config). 61: 62: init_mam(Config) when is_list(Config) -> 63: case mam_helper:backend() of 64: disabled -> 65: {skip, no_backend}; 66: Backend -> 67: Mods = [{mod_mam_meta, [{backend, Backend}, {pm, []}]}], 68: dynamic_modules:ensure_modules(domain_helper:host_type(), Mods), 69: Config 70: end; 71: init_mam(Other) -> 72: Other. 73: 74: %% Test Cases 75: 76: send_message(Config) -> 77: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 78: fun send_message_story/3). 79: 80: send_message_story(Config, Alice, Bob) -> 81: Body = <<"Hi!">>, 82: Vars = #{from => escalus_client:full_jid(Alice), 83: to => escalus_client:short_jid(Bob), 84: body => Body}, 85: Res = ok_result(<<"stanza">>, <<"sendMessage">>, 86: execute_send_message(Vars, Config)), 87: #{<<"id">> := MamID} = Res, 88: assert_not_empty(MamID). 89: 90: send_message_to_unparsable_jid(Config) -> 91: escalus:fresh_story_with_config(Config, [{alice, 1}], 92: fun send_message_to_unparsable_jid_story/2). 93: 94: send_message_to_unparsable_jid_story(Config, Alice) -> 95: Body = <<"Hi!">>, 96: Vars = #{from => escalus_client:full_jid(Alice), 97: to => <<"test@">>, 98: body => Body}, 99: Res = execute_send_message(Vars, Config), 100: {{<<"400">>, <<"Bad Request">>}, #{<<"errors">> := Errors}} = Res, 101: [#{<<"extensions">> := #{<<"code">> := <<"input_coercion">>}, 102: <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors, 103: ?assertEqual([<<"M1">>, <<"to">>], ErrPath), 104: ?assertEqual(<<"Input coercion failed for type JID with value " 105: "<<\"test@\">>. The reason it failed is: failed_to_parse_jid">>, 106: ErrMsg). 107: 108: send_message_headline(Config) -> 109: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 110: fun send_message_headline_story/3). 111: 112: send_message_headline_story(Config, Alice, Bob) -> 113: Subject = <<"Welcome">>, 114: Body = <<"Hi!">>, 115: Vars = #{from => escalus_client:full_jid(Alice), 116: to => escalus_client:short_jid(Bob), 117: subject => Subject, body => Body}, 118: Res = ok_result(<<"stanza">>, <<"sendMessageHeadLine">>, 119: execute_send_message_headline(Vars, Config)), 120: #{<<"id">> := MamID} = Res, 121: %% Headlines are not stored in MAM 122: <<>> = MamID. 123: 124: send_stanza(Config) -> 125: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 126: fun send_stanza_story/3). 127: 128: send_stanza_story(Config, Alice, Bob) -> 129: Body = <<"Hi!">>, 130: Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), Alice), 131: Vars = #{stanza => exml:to_binary(Stanza)}, 132: Res = ok_result(<<"stanza">>, <<"sendStanza">>, execute_send_stanza(Vars, Config)), 133: #{<<"id">> := MamID} = Res, 134: assert_not_empty(MamID). 135: 136: send_unparsable_stanza(Config) -> 137: Vars = #{stanza => <<"<test">>}, 138: Res = execute_send_stanza(Vars, Config), 139: {{<<"400">>, <<"Bad Request">>}, #{<<"errors">> := Errors}} = Res, 140: [#{<<"extensions">> := #{<<"code">> := <<"input_coercion">>}, 141: <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors, 142: ?assertEqual(<<"Input coercion failed for type Stanza with value <<\"<test\">>. " 143: "The reason it failed is: \"expected >\"">>, ErrMsg), 144: ?assertEqual([<<"M1">>, <<"stanza">>], ErrPath). 145: 146: send_stanza_from_unknown_user(Config) -> 147: escalus:fresh_story_with_config(Config, [{bob, 1}], 148: fun send_stanza_from_unknown_user_story/2). 149: 150: send_stanza_from_unknown_user_story(Config, Bob) -> 151: Body = <<"Hi!">>, 152: Server = escalus_client:server(Bob), 153: From = <<"YeeeAH@", Server/binary>>, 154: Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From), 155: Vars = #{stanza => exml:to_binary(Stanza)}, 156: Res = execute_send_stanza(Vars, Config), 157: {{<<"200">>,<<"OK">>}, 158: #{<<"data">> := #{<<"stanza">> := #{<<"sendStanza">> := null}}, 159: <<"errors">> := Errors}} = Res, 160: [#{<<"extensions">> := #{<<"code">> := <<"unknown_user">>, 161: <<"jid">> := From}, 162: <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors, 163: ?assertEqual(<<"Given user does not exist">>, ErrMsg), 164: ?assertEqual([<<"stanza">>, <<"sendStanza">>], ErrPath). 165: 166: send_stanza_from_unknown_domain(Config) -> 167: escalus:fresh_story_with_config(Config, [{bob, 1}], 168: fun send_stanza_from_unknown_domain_story/2). 169: 170: send_stanza_from_unknown_domain_story(Config, Bob) -> 171: Body = <<"Hi!">>, 172: From = <<"YeeeAH@oopsie">>, 173: Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From), 174: Vars = #{stanza => exml:to_binary(Stanza)}, 175: Res = execute_send_stanza(Vars, Config), 176: {{<<"200">>, <<"OK">>}, 177: #{<<"data">> := #{<<"stanza">> := #{<<"sendStanza">> := null}}, 178: <<"errors">> := Errors}} = Res, 179: [#{<<"extensions">> := #{<<"code">> := <<"unknown_domain">>, 180: <<"domain">> := <<"oopsie">>}, 181: <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors, 182: ?assertEqual([<<"stanza">>, <<"sendStanza">>], ErrPath), 183: ?assertEqual(<<"Given domain does not exist">>, ErrMsg). 184: 185: get_last_messages(Config) -> 186: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 187: fun get_last_messages_story/3). 188: 189: get_last_messages_story(Config, Alice, Bob) -> 190: send_message_story(Config, Alice, Bob), 191: mam_helper:wait_for_archive_size(Alice, 1), 192: mam_helper:wait_for_archive_size(Bob, 1), 193: Vars1 = #{caller => escalus_client:full_jid(Alice)}, 194: Vars2 = #{caller => escalus_client:full_jid(Bob)}, 195: Res1 = ok_result(<<"stanza">>, <<"getLastMessages">>, 196: execute_get_last_messages(Vars1, Config)), 197: #{<<"stanzas">> := [M1], <<"limit">> := 50} = Res1, 198: check_stanza_map(M1, Alice), 199: Res2 = ok_result(<<"stanza">>, <<"getLastMessages">>, 200: execute_get_last_messages(Vars2, Config)), 201: #{<<"stanzas">> := [M2], <<"limit">> := 50} = Res2, 202: check_stanza_map(M2, Alice). 203: 204: get_last_messages_for_unknown_user(Config) -> 205: Domain = domain_helper:domain(), 206: Jid = <<"maybemaybebutnot@", Domain/binary>>, 207: Vars = #{caller => Jid}, 208: Res = execute_get_last_messages(Vars, Config), 209: {{<<"200">>, <<"OK">>}, 210: #{<<"data">> := #{<<"stanza">> := #{<<"getLastMessages">> := null}}, 211: <<"errors">> := Errors}} = Res, 212: [#{<<"extensions">> := #{<<"code">> := <<"unknown_user">>, 213: <<"jid">> := Jid}, 214: <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors, 215: ?assertEqual([<<"stanza">>, <<"getLastMessages">>], ErrPath), 216: ?assertEqual(<<"Given user does not exist">>, ErrMsg). 217: 218: get_last_messages_with(Config) -> 219: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}], 220: fun get_last_messages_with_story/4). 221: 222: get_last_messages_with_story(Config, Alice, Bob, Kate) -> 223: send_message_story(Config, Alice, Bob), 224: mam_helper:wait_for_archive_size(Alice, 1), 225: send_message_story(Config, Kate, Alice), 226: mam_helper:wait_for_archive_size(Alice, 2), 227: Vars = #{caller => escalus_client:full_jid(Alice), 228: with => escalus_client:short_jid(Bob)}, 229: Res = ok_result(<<"stanza">>, <<"getLastMessages">>, 230: execute_get_last_messages(Vars, Config)), 231: #{<<"stanzas">> := [M1], <<"limit">> := 50} = Res, 232: check_stanza_map(M1, Alice). 233: 234: get_last_messages_limit(Config) -> 235: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 236: fun get_last_messages_limit_story/3). 237: 238: get_last_messages_limit_story(Config, Alice, Bob) -> 239: send_message_story(Config, Alice, Bob), 240: mam_helper:wait_for_archive_size(Alice, 1), 241: send_message_story(Config, Bob, Alice), 242: mam_helper:wait_for_archive_size(Alice, 2), 243: Vars = #{caller => escalus_client:full_jid(Alice), limit => 1}, 244: Res = ok_result(<<"stanza">>, <<"getLastMessages">>, 245: execute_get_last_messages(Vars, Config)), 246: #{<<"stanzas">> := [M1], <<"limit">> := 1} = Res, 247: check_stanza_map(M1, Bob). 248: 249: get_last_messages_limit_enforced(Config) -> 250: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 251: fun get_last_messages_limit_enforced_story/3). 252: 253: get_last_messages_limit_enforced_story(Config, Alice, Bob) -> 254: send_message_story(Config, Alice, Bob), 255: mam_helper:wait_for_archive_size(Alice, 1), 256: Vars = #{caller => escalus_client:full_jid(Alice), limit => 1000}, 257: Res = ok_result(<<"stanza">>, <<"getLastMessages">>, 258: execute_get_last_messages(Vars, Config)), 259: %% The actual limit is returned 260: #{<<"stanzas">> := [M1], <<"limit">> := 500} = Res, 261: check_stanza_map(M1, Alice). 262: 263: get_last_messages_before(Config) -> 264: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 265: fun get_last_messages_before_story/3). 266: 267: get_last_messages_before_story(Config, Alice, Bob) -> 268: send_message_story(Config, Alice, Bob), 269: mam_helper:wait_for_archive_size(Alice, 1), 270: send_message_story(Config, Bob, Alice), 271: mam_helper:wait_for_archive_size(Alice, 2), 272: send_message_story(Config, Bob, Alice), 273: mam_helper:wait_for_archive_size(Alice, 3), 274: Vars1 = #{caller => escalus_client:full_jid(Alice)}, 275: Res1 = ok_result(<<"stanza">>, <<"getLastMessages">>, 276: execute_get_last_messages(Vars1, Config)), 277: #{<<"stanzas">> := [M1, M2, _M3], <<"limit">> := 50} = Res1, 278: Vars2 = #{caller => escalus_client:full_jid(Alice), 279: before => maps:get(<<"timestamp">>, M2)}, 280: Res2 = ok_result(<<"stanza">>, <<"getLastMessages">>, 281: execute_get_last_messages(Vars2, Config)), 282: #{<<"stanzas">> := [M1, M2], <<"limit">> := 50} = Res2. 283: 284: %% Helpers 285: 286: execute_send_message(Vars, Config) -> 287: Q = <<"mutation M1($from: JID!, $to: JID!, $body: String!) " 288: "{ stanza { sendMessage(from: $from, to: $to, body: $body) { id } } }">>, 289: execute_auth(#{query => Q, variables => Vars, 290: operationName => <<"M1">>}, Config). 291: 292: execute_send_message_headline(Vars, Config) -> 293: Q = <<"mutation M1($from: JID!, $to: JID!, $subject: String, $body: String) " 294: "{ stanza { sendMessageHeadLine(" 295: "from: $from, to: $to, subject: $subject, body: $body) { id } } }">>, 296: execute_auth(#{query => Q, variables => Vars, 297: operationName => <<"M1">>}, Config). 298: 299: execute_send_stanza(Vars, Config) -> 300: Q = <<"mutation M1($stanza: Stanza!) " 301: "{ stanza { sendStanza(stanza: $stanza) { id } } }">>, 302: execute_auth(#{query => Q, variables => Vars, 303: operationName => <<"M1">>}, Config). 304: 305: execute_get_last_messages(Vars, Config) -> 306: Q = <<"query Q1($caller: JID!, $with: JID, $limit: Int, $before: DateTime) " 307: "{ stanza { getLastMessages(caller: $caller, with: $with, " 308: " limit: $limit, before: $before) " 309: "{ stanzas { stanza_id stanza sender timestamp } limit } } }">>, 310: execute_auth(#{query => Q, variables => Vars, 311: operationName => <<"Q1">>}, Config). 312: 313: assert_not_empty(Bin) when byte_size(Bin) > 0 -> ok. 314: 315: ok_result(What1, What2, {{<<"200">>, <<"OK">>}, #{<<"data">> := Data}}) -> 316: maps:get(What2, maps:get(What1, Data)). 317: 318: check_stanza_map(#{<<"sender">> := SenderJID, 319: <<"stanza">> := XML, 320: <<"stanza_id">> := StanzaID, 321: <<"timestamp">> := TS}, SenderClient) -> 322: ?assertEqual(escalus_utils:jid_to_lower(escalus_client:full_jid(SenderClient)), 323: escalus_utils:jid_to_lower(SenderJID)), 324: true = byte_size(StanzaID) > 6, 325: true = is_integer(calendar:rfc3339_to_system_time(binary_to_list(TS))), 326: {ok, #xmlel{name = <<"message">>}} = exml:parse(XML).