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:      {group, user_stanza_caregory}].
   18: 
   19: groups() ->
   20:     [{admin_stanza_category, [parallel], admin_stanza_category()},
   21:      {user_stanza_caregory, [parallel], user_stanza_caregory()}].
   22: 
   23: admin_stanza_category() ->
   24:     [admin_send_message,
   25:      admin_send_message_to_unparsable_jid,
   26:      admin_send_message_headline,
   27:      admin_send_stanza,
   28:      admin_send_unparsable_stanza,
   29:      admin_send_stanza_from_unknown_user,
   30:      admin_send_stanza_from_unknown_domain]
   31:     ++ admin_get_last_messages_cases().
   32: 
   33: admin_get_last_messages_cases() ->
   34:     [admin_get_last_messages,
   35:      admin_get_last_messages_for_unknown_user,
   36:      admin_get_last_messages_with,
   37:      admin_get_last_messages_limit,
   38:      admin_get_last_messages_limit_enforced,
   39:      admin_get_last_messages_before].
   40: 
   41: user_stanza_caregory() ->
   42:     [user_send_message,
   43:      user_send_message_without_from,
   44:      user_send_message_with_spoofed_from,
   45:      user_send_message_headline,
   46:      user_send_message_headline_with_spoofed_from,
   47:      user_send_stanza,
   48:      user_send_stanza_with_spoofed_from]
   49:     ++ user_get_last_messages_cases().
   50: 
   51: user_get_last_messages_cases() ->
   52:     [user_get_last_messages].
   53: 
   54: init_per_suite(Config) ->
   55:     Config1 = escalus:init_per_suite(Config),
   56:     dynamic_modules:save_modules(domain_helper:host_type(), Config1).
   57: 
   58: end_per_suite(Config) ->
   59:     escalus_fresh:clean(),
   60:     dynamic_modules:restore_modules(Config),
   61:     escalus:end_per_suite(Config).
   62: 
   63: init_per_group(admin_stanza_category, Config) ->
   64:     Config2 = graphql_helper:init_admin_handler(Config),
   65:     init_mam(Config2);
   66: init_per_group(user_stanza_caregory, Config) ->
   67:     init_mam(Config).
   68: 
   69: end_per_group(_, _Config) ->
   70:     ok.
   71: 
   72: init_per_testcase(CaseName, Config) ->
   73:     HasMam = proplists:get_value(has_mam, Config, false),
   74:     MamOnly = lists:member(CaseName,
   75:                            user_get_last_messages_cases()
   76:                            ++ admin_get_last_messages_cases()),
   77:     case {HasMam, MamOnly} of
   78:         {false, true} ->
   79:             {skip, no_mam};
   80:         _ ->
   81:             escalus:init_per_testcase(CaseName, Config)
   82:     end.
   83: 
   84: end_per_testcase(CaseName, Config) ->
   85:     escalus:end_per_testcase(CaseName, Config).
   86: 
   87: init_mam(Config) when is_list(Config) ->
   88:     case mam_helper:backend() of
   89:         disabled ->
   90:             Config;
   91:         Backend ->
   92:             Mods = [{mod_mam_meta, mam_helper:config_opts(#{backend => Backend, pm => #{}})}],
   93:             dynamic_modules:ensure_modules(domain_helper:host_type(), Mods),
   94:             [{has_mam, true}|Config]
   95:     end;
   96: init_mam(Other) ->
   97:     Other.
   98: 
   99: %% Test Cases
  100: 
  101: admin_send_message(Config) ->
  102:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  103:                                     fun admin_send_message_story/3).
  104: 
  105: admin_send_message_story(Config, Alice, Bob) ->
  106:     Body = <<"Hi!">>,
  107:     Vars = #{from => escalus_client:full_jid(Alice),
  108:              to => escalus_client:short_jid(Bob),
  109:              body => Body},
  110:     Res = ok_result(<<"stanza">>, <<"sendMessage">>,
  111:                     execute_send_message(Vars, Config)),
  112:     #{<<"id">> := MamID} = Res,
  113:     assert_not_empty(MamID, Config).
  114: 
  115: user_send_message(Config) ->
  116:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  117:                                     fun user_send_message_story/3).
  118: 
  119: user_send_message_story(Config, Alice, Bob) ->
  120:     Body = <<"Hi!">>,
  121:     Vars = #{from => escalus_client:full_jid(Alice),
  122:              to => escalus_client:short_jid(Bob),
  123:              body => Body},
  124:     Res = ok_result(<<"stanza">>, <<"sendMessage">>,
  125:                     execute_user_send_message(Alice, Vars, Config)),
  126:     #{<<"id">> := MamID} = Res,
  127:     assert_not_empty(MamID, Config),
  128:     escalus:assert(is_message, escalus:wait_for_stanza(Bob)).
  129: 
  130: user_send_message_without_from(Config) ->
  131:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  132:                                     fun user_send_message_without_from_story/3).
  133: 
  134: user_send_message_without_from_story(Config, Alice, Bob) ->
  135:     Body = <<"Hi!">>,
  136:     Vars = #{to => escalus_client:short_jid(Bob),
  137:              body => Body},
  138:     Res = ok_result(<<"stanza">>, <<"sendMessage">>,
  139:                     execute_user_send_message(Alice, Vars, Config)),
  140:     #{<<"id">> := MamID} = Res,
  141:     assert_not_empty(MamID, Config),
  142:     escalus:assert(is_message, escalus:wait_for_stanza(Bob)).
  143: 
  144: user_send_message_with_spoofed_from(Config) ->
  145:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  146:                                     fun user_send_message_with_spoofed_from_story/3).
  147: 
  148: user_send_message_with_spoofed_from_story(Config, Alice, Bob) ->
  149:     Body = <<"Hi!">>,
  150:     Vars = #{from => escalus_client:short_jid(Bob),
  151:              to => escalus_client:short_jid(Bob),
  152:              body => Body},
  153:     Res = execute_user_send_message(Alice, Vars, Config),
  154:     spoofed_error(<<"sendMessage">>, Res).
  155: 
  156: admin_send_message_to_unparsable_jid(Config) ->
  157:     escalus:fresh_story_with_config(Config, [{alice, 1}],
  158:                                     fun admin_send_message_to_unparsable_jid_story/2).
  159: 
  160: admin_send_message_to_unparsable_jid_story(Config, Alice) ->
  161:     Body = <<"Hi!">>,
  162:     Vars = #{from => escalus_client:full_jid(Alice),
  163:              to => <<"test@">>,
  164:              body => Body},
  165:     Res = execute_send_message(Vars, Config),
  166:     {{<<"400">>, <<"Bad Request">>}, #{<<"errors">> := Errors}} = Res,
  167:     [#{<<"extensions">> := #{<<"code">> := <<"input_coercion">>},
  168:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  169:     ?assertEqual([<<"M1">>, <<"to">>], ErrPath),
  170:     ?assertEqual(<<"Input coercion failed for type JID with value "
  171:                    "<<\"test@\">>. The reason it failed is: failed_to_parse_jid">>,
  172:                  ErrMsg).
  173: 
  174: admin_send_message_headline(Config) ->
  175:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  176:                                     fun admin_send_message_headline_story/3).
  177: 
  178: admin_send_message_headline_story(Config, Alice, Bob) ->
  179:     Subject = <<"Welcome">>,
  180:     Body = <<"Hi!">>,
  181:     Vars = #{from => escalus_client:full_jid(Alice),
  182:              to => escalus_client:short_jid(Bob),
  183:              subject => Subject, body => Body},
  184:     Res = ok_result(<<"stanza">>, <<"sendMessageHeadLine">>,
  185:                     execute_send_message_headline(Vars, Config)),
  186:     #{<<"id">> := MamID} = Res,
  187:     %% Headlines are not stored in MAM
  188:     <<>> = MamID.
  189: 
  190: user_send_message_headline(Config) ->
  191:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  192:                                     fun user_send_message_headline_story/3).
  193: 
  194: user_send_message_headline_story(Config, Alice, Bob) ->
  195:     Subject = <<"Welcome">>,
  196:     Body = <<"Hi!">>,
  197:     Vars = #{from => escalus_client:full_jid(Alice),
  198:              to => escalus_client:short_jid(Bob),
  199:              subject => Subject, body => Body},
  200:     Res = ok_result(<<"stanza">>, <<"sendMessageHeadLine">>,
  201:                     execute_user_send_message_headline(Alice, Vars, Config)),
  202:     #{<<"id">> := MamID} = Res,
  203:     %% Headlines are not stored in MAM
  204:     <<>> = MamID,
  205:     escalus:assert(is_message, escalus:wait_for_stanza(Bob)).
  206: 
  207: user_send_message_headline_with_spoofed_from(Config) ->
  208:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  209:                                     fun user_send_message_headline_with_spoofed_from_story/3).
  210: 
  211: user_send_message_headline_with_spoofed_from_story(Config, Alice, Bob) ->
  212:     Subject = <<"Welcome">>,
  213:     Body = <<"Hi!">>,
  214:     Vars = #{from => escalus_client:short_jid(Bob),
  215:              to => escalus_client:short_jid(Bob),
  216:              subject => Subject, body => Body},
  217:     Res = execute_user_send_message_headline(Alice, Vars, Config),
  218:     spoofed_error(<<"sendMessageHeadLine">>, Res).
  219: 
  220: admin_send_stanza(Config) ->
  221:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  222:                                     fun admin_send_stanza_story/3).
  223: 
  224: admin_send_stanza_story(Config, Alice, Bob) ->
  225:     Body = <<"Hi!">>,
  226:     Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), Alice),
  227:     Vars = #{stanza => exml:to_binary(Stanza)},
  228:     Res = ok_result(<<"stanza">>, <<"sendStanza">>, execute_send_stanza(Vars, Config)),
  229:     #{<<"id">> := MamID} = Res,
  230:     assert_not_empty(MamID, Config).
  231: 
  232: user_send_stanza(Config) ->
  233:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  234:                                     fun user_send_stanza_story/3).
  235: 
  236: user_send_stanza_story(Config, Alice, Bob) ->
  237:     Body = <<"Hi!">>,
  238:     Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), Alice),
  239:     Vars = #{stanza => exml:to_binary(Stanza)},
  240:     Res = ok_result(<<"stanza">>, <<"sendStanza">>,
  241:                     execute_user_send_stanza(Alice, Vars, Config)),
  242:     #{<<"id">> := MamID} = Res,
  243:     assert_not_empty(MamID, Config).
  244: 
  245: user_send_stanza_with_spoofed_from(Config) ->
  246:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  247:                                     fun user_send_stanza_with_spoofed_from_story/3).
  248: 
  249: user_send_stanza_with_spoofed_from_story(Config, Alice, Bob) ->
  250:     Body = <<"Hi!">>,
  251:     Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), Bob),
  252:     Vars = #{stanza => exml:to_binary(Stanza)},
  253:     Res = execute_user_send_stanza(Alice, Vars, Config),
  254:     spoofed_error(<<"sendStanza">>, Res).
  255: 
  256: admin_send_unparsable_stanza(Config) ->
  257:     Vars = #{stanza => <<"<test">>},
  258:     Res = execute_send_stanza(Vars, Config),
  259:     {{<<"400">>, <<"Bad Request">>}, #{<<"errors">> := Errors}} = Res,
  260:     [#{<<"extensions">> := #{<<"code">> := <<"input_coercion">>},
  261:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  262:     ?assertEqual(<<"Input coercion failed for type Stanza with value <<\"<test\">>. "
  263:                    "The reason it failed is: \"expected >\"">>, ErrMsg),
  264:     ?assertEqual([<<"M1">>, <<"stanza">>], ErrPath).
  265: 
  266: admin_send_stanza_from_unknown_user(Config) ->
  267:     escalus:fresh_story_with_config(Config, [{bob, 1}],
  268:                                     fun admin_send_stanza_from_unknown_user_story/2).
  269: 
  270: admin_send_stanza_from_unknown_user_story(Config, Bob) ->
  271:     Body = <<"Hi!">>,
  272:     Server = escalus_client:server(Bob),
  273:     From = <<"YeeeAH@", Server/binary>>,
  274:     Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From),
  275:     Vars = #{stanza => exml:to_binary(Stanza)},
  276:     Res = execute_send_stanza(Vars, Config),
  277:     {{<<"200">>,<<"OK">>},
  278:          #{<<"data">> := #{<<"stanza">> := #{<<"sendStanza">> := null}},
  279:            <<"errors">> := Errors}} = Res,
  280:     [#{<<"extensions">> := #{<<"code">> := <<"unknown_user">>,
  281:                              <<"jid">> := From},
  282:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  283:     ?assertEqual(<<"Given user does not exist">>, ErrMsg),
  284:     ?assertEqual([<<"stanza">>, <<"sendStanza">>], ErrPath).
  285: 
  286: admin_send_stanza_from_unknown_domain(Config) ->
  287:     escalus:fresh_story_with_config(Config, [{bob, 1}],
  288:                                     fun admin_send_stanza_from_unknown_domain_story/2).
  289: 
  290: admin_send_stanza_from_unknown_domain_story(Config, Bob) ->
  291:     Body = <<"Hi!">>,
  292:     From = <<"YeeeAH@oopsie">>,
  293:     Stanza = escalus_stanza:from(escalus_stanza:chat_to_short_jid(Bob, Body), From),
  294:     Vars = #{stanza => exml:to_binary(Stanza)},
  295:     Res = execute_send_stanza(Vars, Config),
  296:     {{<<"200">>, <<"OK">>},
  297:      #{<<"data">> := #{<<"stanza">> := #{<<"sendStanza">> := null}},
  298:        <<"errors">> := Errors}} = Res,
  299:     [#{<<"extensions">> := #{<<"code">> := <<"unknown_domain">>,
  300:                              <<"domain">> := <<"oopsie">>},
  301:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  302:     ?assertEqual([<<"stanza">>, <<"sendStanza">>], ErrPath),
  303:     ?assertEqual(<<"Given domain does not exist">>, ErrMsg).
  304: 
  305: admin_get_last_messages(Config) ->
  306:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  307:                                     fun admin_get_last_messages_story/3).
  308: 
  309: admin_get_last_messages_story(Config, Alice, Bob) ->
  310:     admin_send_message_story(Config, Alice, Bob),
  311:     mam_helper:wait_for_archive_size(Alice, 1),
  312:     mam_helper:wait_for_archive_size(Bob, 1),
  313:     Vars1 = #{caller => escalus_client:full_jid(Alice)},
  314:     Vars2 = #{caller => escalus_client:full_jid(Bob)},
  315:     Res1 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  316:                      execute_get_last_messages(Vars1, Config)),
  317:     #{<<"stanzas">> := [M1], <<"limit">> := 50} = Res1,
  318:     check_stanza_map(M1, Alice),
  319:     Res2 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  320:                      execute_get_last_messages(Vars2, Config)),
  321:     #{<<"stanzas">> := [M2], <<"limit">> := 50} = Res2,
  322:     check_stanza_map(M2, Alice).
  323: 
  324: user_get_last_messages(Config) ->
  325:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  326:                                     fun user_get_last_messages_story/3).
  327: 
  328: user_get_last_messages_story(Config, Alice, Bob) ->
  329:     user_send_message_story(Config, Alice, Bob),
  330:     mam_helper:wait_for_archive_size(Alice, 1),
  331:     mam_helper:wait_for_archive_size(Bob, 1),
  332:     Vars1 = #{caller => escalus_client:full_jid(Alice)},
  333:     Vars2 = #{caller => escalus_client:full_jid(Bob)},
  334:     Res1 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  335:                      execute_user_get_last_messages(Alice, Vars1, Config)),
  336:     #{<<"stanzas">> := [M1], <<"limit">> := 50} = Res1,
  337:     check_stanza_map(M1, Alice),
  338:     Res2 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  339:                      execute_user_get_last_messages(Alice, Vars2, Config)),
  340:     #{<<"stanzas">> := [M2], <<"limit">> := 50} = Res2,
  341:     check_stanza_map(M2, Alice).
  342: 
  343: admin_get_last_messages_for_unknown_user(Config) ->
  344:     Domain = domain_helper:domain(),
  345:     Jid = <<"maybemaybebutnot@", Domain/binary>>,
  346:     Vars = #{caller => Jid},
  347:     Res = execute_get_last_messages(Vars, Config),
  348:     {{<<"200">>, <<"OK">>},
  349:      #{<<"data">> := #{<<"stanza">> := #{<<"getLastMessages">> := null}},
  350:        <<"errors">> := Errors}} = Res,
  351:     [#{<<"extensions">> := #{<<"code">> := <<"unknown_user">>,
  352:                              <<"jid">> := Jid},
  353:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  354:     ?assertEqual([<<"stanza">>, <<"getLastMessages">>], ErrPath),
  355:     ?assertEqual(<<"Given user does not exist">>, ErrMsg).
  356: 
  357: admin_get_last_messages_with(Config) ->
  358:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}],
  359:                                     fun admin_get_last_messages_with_story/4).
  360: 
  361: admin_get_last_messages_with_story(Config, Alice, Bob, Kate) ->
  362:     admin_send_message_story(Config, Alice, Bob),
  363:     mam_helper:wait_for_archive_size(Alice, 1),
  364:     admin_send_message_story(Config, Kate, Alice),
  365:     mam_helper:wait_for_archive_size(Alice, 2),
  366:     Vars = #{caller => escalus_client:full_jid(Alice),
  367:              with => escalus_client:short_jid(Bob)},
  368:     Res = ok_result(<<"stanza">>, <<"getLastMessages">>,
  369:                     execute_get_last_messages(Vars, Config)),
  370:     #{<<"stanzas">> := [M1], <<"limit">> := 50} = Res,
  371:     check_stanza_map(M1, Alice).
  372: 
  373: admin_get_last_messages_limit(Config) ->
  374:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  375:                                     fun admin_get_last_messages_limit_story/3).
  376: 
  377: admin_get_last_messages_limit_story(Config, Alice, Bob) ->
  378:     admin_send_message_story(Config, Alice, Bob),
  379:     mam_helper:wait_for_archive_size(Alice, 1),
  380:     admin_send_message_story(Config, Bob, Alice),
  381:     mam_helper:wait_for_archive_size(Alice, 2),
  382:     Vars = #{caller => escalus_client:full_jid(Alice), limit => 1},
  383:     Res = ok_result(<<"stanza">>, <<"getLastMessages">>,
  384:                     execute_get_last_messages(Vars, Config)),
  385:     #{<<"stanzas">> := [M1], <<"limit">> := 1} = Res,
  386:     check_stanza_map(M1, Bob).
  387: 
  388: admin_get_last_messages_limit_enforced(Config) ->
  389:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  390:                                     fun admin_get_last_messages_limit_enforced_story/3).
  391: 
  392: admin_get_last_messages_limit_enforced_story(Config, Alice, Bob) ->
  393:     admin_send_message_story(Config, Alice, Bob),
  394:     mam_helper:wait_for_archive_size(Alice, 1),
  395:     Vars = #{caller => escalus_client:full_jid(Alice), limit => 1000},
  396:     Res = ok_result(<<"stanza">>, <<"getLastMessages">>,
  397:                     execute_get_last_messages(Vars, Config)),
  398:     %% The actual limit is returned
  399:     #{<<"stanzas">> := [M1], <<"limit">> := 500} = Res,
  400:     check_stanza_map(M1, Alice).
  401: 
  402: admin_get_last_messages_before(Config) ->
  403:     escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}],
  404:                                     fun admin_get_last_messages_before_story/3).
  405: 
  406: admin_get_last_messages_before_story(Config, Alice, Bob) ->
  407:     admin_send_message_story(Config, Alice, Bob),
  408:     mam_helper:wait_for_archive_size(Alice, 1),
  409:     admin_send_message_story(Config, Bob, Alice),
  410:     mam_helper:wait_for_archive_size(Alice, 2),
  411:     admin_send_message_story(Config, Bob, Alice),
  412:     mam_helper:wait_for_archive_size(Alice, 3),
  413:     Vars1 = #{caller => escalus_client:full_jid(Alice)},
  414:     Res1 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  415:                      execute_get_last_messages(Vars1, Config)),
  416:     #{<<"stanzas">> := [M1, M2, _M3], <<"limit">> := 50} = Res1,
  417:     Vars2 = #{caller => escalus_client:full_jid(Alice),
  418:               before => maps:get(<<"timestamp">>, M2)},
  419:     Res2 = ok_result(<<"stanza">>, <<"getLastMessages">>,
  420:                      execute_get_last_messages(Vars2, Config)),
  421:     #{<<"stanzas">> := [M1, M2], <<"limit">> := 50} = Res2.
  422: 
  423: %% Helpers
  424: 
  425: execute_send_message(Vars, Config) ->
  426:     Q = <<"mutation M1($from: JID!, $to: JID!, $body: String!) "
  427:           "{ stanza { sendMessage(from: $from, to: $to, body: $body) { id } } }">>,
  428:     execute_auth(#{query => Q, variables => Vars,
  429:                    operationName => <<"M1">>}, Config).
  430: 
  431: execute_user_send_message(User, Vars, _Config) ->
  432:     Creds = graphql_helper:make_creds(User),
  433:     Q = <<"mutation M1($from: JID, $to: JID!, $body: String!) "
  434:           "{ stanza { sendMessage(from: $from, to: $to, body: $body) { id } } }">>,
  435:     QQ = #{query => Q, variables => Vars, operationName => <<"M1">>},
  436:     graphql_helper:execute(user, QQ, Creds).
  437: 
  438: execute_send_message_headline(Vars, Config) ->
  439:     Q = <<"mutation M1($from: JID!, $to: JID!, $subject: String, $body: String) "
  440:           "{ stanza { sendMessageHeadLine("
  441:             "from: $from, to: $to, subject: $subject, body: $body) { id } } }">>,
  442:     execute_auth(#{query => Q, variables => Vars,
  443:                    operationName => <<"M1">>}, Config).
  444: 
  445: execute_user_send_message_headline(User, Vars, _Config) ->
  446:     Creds = graphql_helper:make_creds(User),
  447:     Q = <<"mutation M1($from: JID, $to: JID!, $subject: String, $body: String) "
  448:           "{ stanza { sendMessageHeadLine("
  449:             "from: $from, to: $to, subject: $subject, body: $body) { id } } }">>,
  450:     QQ = #{query => Q, variables => Vars, operationName => <<"M1">>},
  451:     graphql_helper:execute(user, QQ, Creds).
  452: 
  453: execute_send_stanza(Vars, Config) ->
  454:     Q = <<"mutation M1($stanza: Stanza!) "
  455:           "{ stanza { sendStanza(stanza: $stanza) { id } } }">>,
  456:     execute_auth(#{query => Q, variables => Vars,
  457:                    operationName => <<"M1">>}, Config).
  458: 
  459: execute_user_send_stanza(User, Vars, _Config) ->
  460:     Creds = graphql_helper:make_creds(User),
  461:     Q = <<"mutation M1($stanza: Stanza!) "
  462:           "{ stanza { sendStanza(stanza: $stanza) { id } } }">>,
  463:     QQ = #{query => Q, variables => Vars, operationName => <<"M1">>},
  464:     graphql_helper:execute(user, QQ, Creds).
  465: 
  466: execute_get_last_messages(Vars, Config) ->
  467:     Q = <<"query Q1($caller: JID!, $with: JID, $limit: Int, $before: DateTime) "
  468:           "{ stanza { getLastMessages(caller: $caller, with: $with, "
  469:                  " limit: $limit, before: $before) "
  470:                      "{ stanzas { stanza_id stanza sender timestamp } limit } } }">>,
  471:     execute_auth(#{query => Q, variables => Vars,
  472:                    operationName => <<"Q1">>}, Config).
  473: 
  474: execute_user_get_last_messages(User, Vars, _Config) ->
  475:     Creds = graphql_helper:make_creds(User),
  476:     Q = <<"query Q1($with: JID, $limit: Int, $before: DateTime) "
  477:           "{ stanza { getLastMessages(with: $with, limit: $limit, before: $before) "
  478:                      "{ stanzas { stanza_id stanza sender timestamp } limit } } }">>,
  479:     QQ = #{query => Q, variables => Vars, operationName => <<"Q1">>},
  480:     graphql_helper:execute(user, QQ, Creds).
  481: 
  482: assert_not_empty(Bin, Config) ->
  483:     case proplists:get_value(has_mam, Config) of
  484:         true ->
  485:             assert_not_empty(Bin);
  486:         _ ->
  487:             skip
  488:     end.
  489: 
  490: assert_not_empty(Bin) when byte_size(Bin) > 0 -> ok.
  491: 
  492: ok_result(What1, What2, {{<<"200">>, <<"OK">>}, #{<<"data">> := Data}}) ->
  493:     maps:get(What2, maps:get(What1, Data)).
  494: 
  495: check_stanza_map(#{<<"sender">> := SenderJID,
  496:                    <<"stanza">> := XML,
  497:                    <<"stanza_id">> := StanzaID,
  498:                    <<"timestamp">> := TS}, SenderClient) ->
  499:     ?assertEqual(escalus_utils:jid_to_lower(escalus_client:full_jid(SenderClient)),
  500:                  escalus_utils:jid_to_lower(SenderJID)),
  501:      true = byte_size(StanzaID) > 6,
  502:      true = is_integer(calendar:rfc3339_to_system_time(binary_to_list(TS))),
  503:      {ok, #xmlel{name = <<"message">>}} = exml:parse(XML).
  504: 
  505: spoofed_error(Call, Res) ->
  506:     {{<<"200">>, <<"OK">>},
  507:      #{<<"data">> := #{<<"stanza">> := #{Call := null}},
  508:        <<"errors">> := Errors}} = Res,
  509:     [#{<<"extensions">> := #{<<"code">> := <<"bad_from_jid">>},
  510:        <<"message">> := ErrMsg, <<"path">> := ErrPath}] = Errors,
  511:     ?assertEqual([<<"stanza">>, Call], ErrPath),
  512:     ?assertEqual(<<"Sending from this JID is not allowed">>, ErrMsg).