1: -module(graphql_session_SUITE).
    2: 
    3: -include_lib("eunit/include/eunit.hrl").
    4: 
    5: -compile([export_all, nowarn_export_all]).
    6: 
    7: -import(common_helper, [unprep/1]).
    8: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
    9: -import(domain_helper, [domain/0]).
   10: -import(graphql_helper, [execute_user_command/5, execute_command/4,  get_listener_port/1,
   11:                          get_listener_config/1, get_ok_value/2, get_err_msg/1, get_unauthorized/1,
   12:                          get_coercion_err_msg/1]).
   13: 
   14: suite() ->
   15:     require_rpc_nodes([mim]) ++ escalus:suite().
   16: 
   17: all() ->
   18:     [{group, user_session},
   19:      {group, admin_session},
   20:      {group, domain_admin_session}].
   21: 
   22: groups() ->
   23:     [{user_session, [parallel], user_session_tests()},
   24:      {admin_session, [], [{group, admin_session_http}, {group, admin_session_cli}]},
   25:      {admin_session_http, [], admin_session_tests()},
   26:      {admin_session_cli, [], admin_session_tests()},
   27:      {domain_admin_session, [], domain_admin_session_tests()}].
   28: 
   29: user_session_tests() ->
   30:     [user_list_resources,
   31:      user_count_resources,
   32:      user_sessions_info].
   33: 
   34: admin_session_tests() ->
   35:     [admin_list_sessions,
   36:      admin_count_sessions,
   37:      admin_list_user_sessions,
   38:      admin_count_user_resources,
   39:      admin_get_user_resource,
   40:      admin_list_users_with_status,
   41:      admin_count_users_with_status,
   42:      admin_kick_user_session,
   43:      admin_kick_user,
   44:      admin_set_presence,
   45:      admin_set_presence_away,
   46:      admin_set_presence_unavailable].
   47: 
   48: domain_admin_session_tests() ->
   49:     [domain_admin_list_sessions,
   50:      domain_admin_count_sessions,
   51:      admin_list_user_sessions,
   52:      domain_admin_list_user_sessions_no_permission,
   53:      admin_count_user_resources,
   54:      domain_admin_count_user_resources_no_permission,
   55:      admin_get_user_resource,
   56:      domain_admin_get_user_resource_no_permission,
   57:      domain_admin_list_users_with_status,
   58:      domain_admin_count_users_with_status,
   59:      admin_kick_user_session,
   60:      domain_admin_kick_user_session_no_permission,
   61:      domain_admin_kick_user_no_permission,
   62:      admin_set_presence,
   63:      admin_set_presence_away,
   64:      admin_set_presence_unavailable,
   65:      domain_admin_set_presence_no_permission].
   66: 
   67: init_per_suite(Config) ->
   68:     Config1 = ejabberd_node_utils:init(mim(), Config),
   69:     Config2 = escalus:init_per_suite(Config1),
   70:     dynamic_modules:save_modules(domain_helper:host_type(), Config2).
   71: 
   72: end_per_suite(Config) ->
   73:     dynamic_modules:restore_modules(Config),
   74:     escalus:end_per_suite(Config).
   75: 
   76: init_per_group(admin_session, Config) ->
   77:     escalus:create_users(Config, escalus:get_users([alice, alice_bis, bob]));
   78: init_per_group(admin_session_cli, Config) ->
   79:     graphql_helper:init_admin_handler(Config);
   80: init_per_group(admin_session_http, Config) ->
   81:     graphql_helper:init_admin_cli(Config);
   82: init_per_group(domain_admin_session, Config) ->
   83:     Config1 = graphql_helper:init_domain_admin_handler(Config),
   84:     case Config1 of
   85:         {skip, require_rdbms} ->
   86:             Config1;
   87:         _ ->
   88:             escalus:create_users(Config1, escalus:get_users([alice, alice_bis, bob]))
   89:     end;
   90: init_per_group(user_session, Config) ->
   91:     graphql_helper:init_user(Config).
   92: 
   93: end_per_group(admin_session, Config) ->
   94:     escalus:delete_users(Config, escalus:get_users([alice, alice_bis, bob]));
   95: end_per_group(domain_admin_session, Config) ->
   96:     escalus:delete_users(Config, escalus:get_users([alice, alice_bis, bob])),
   97:     escalus_fresh:clean(),
   98:     graphql_helper:clean();
   99: end_per_group(_GroupName, _Config) ->
  100:     escalus_fresh:clean(),
  101:     graphql_helper:clean().
  102: 
  103: init_per_testcase(CaseName, Config) ->
  104:     escalus:init_per_testcase(CaseName, Config).
  105: 
  106: end_per_testcase(CaseName, Config) ->
  107:     escalus:end_per_testcase(CaseName, Config).
  108: 
  109: %% Test cases
  110: 
  111: user_list_resources(Config) ->
  112:     escalus:fresh_story_with_config(Config, [{alice, 2}], fun user_list_resources_story/3).
  113: 
  114: user_list_resources_story(Config, Alice, Alice2) ->
  115:     Result = user_list_resources(Alice, Config),
  116:     Path = [data, session, listResources],
  117:     ExpectedRes = [escalus_client:resource(Alice), escalus_client:resource(Alice2)],
  118:     ?assertMatch(ExpectedRes, lists:sort(get_ok_value(Path, Result))).
  119: 
  120: user_count_resources(Config) ->
  121:     escalus:fresh_story_with_config(Config, [{alice, 3}], fun user_count_resources_story/4).
  122: 
  123: user_count_resources_story(Config, Alice, _Alice2, _Alice3) ->
  124:     Result = user_count_resources(Alice, Config),
  125:     Path = [data, session, countResources],
  126:     ?assertEqual(3, get_ok_value(Path, Result)).
  127: 
  128: user_sessions_info(Config) ->
  129:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_sessions_info_story/2).
  130: 
  131: user_sessions_info_story(Config, Alice) ->
  132:     Result = user_list_sessions(Alice, Config),
  133:     ExpectedUser = escalus_utils:jid_to_lower(escalus_client:full_jid(Alice)),
  134:     Path = [data, session, listSessions],
  135:     ?assertMatch([#{<<"user">> := ExpectedUser}], get_ok_value(Path, Result)).
  136: 
  137: 
  138: domain_admin_list_sessions(Config) ->
  139:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}],
  140:                                     fun domain_admin_list_sessions_story/4).
  141: 
  142: domain_admin_list_sessions_story(Config, Alice, AliceB, _Bob) ->
  143:     Domain = escalus_client:server(Alice),
  144:     BisDomain = escalus_client:server(AliceB),
  145:     Path = [data, session, listSessions],
  146:     % List all sessions
  147:     Res = list_sessions(null, Config),
  148:     get_unauthorized(Res),
  149:     % List sessions for an external domain
  150:     Res2 = list_sessions(BisDomain, Config),
  151:     get_unauthorized(Res2),
  152:     % List sessions for local domain
  153:     Res3 = list_sessions(Domain, Config),
  154:     Sessions = get_ok_value(Path, Res3),
  155:     ?assertEqual(2, length(Sessions)).
  156: 
  157: domain_admin_count_sessions(Config) ->
  158:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}],
  159:                                     fun domain_admin_count_sessions_story/4).
  160: 
  161: domain_admin_count_sessions_story(Config, Alice, AliceB, _Bob) ->
  162:     Domain = escalus_client:server(Alice),
  163:     BisDomain = escalus_client:server(AliceB),
  164:     Path = [data, session, countSessions],
  165:     % Count all sessions
  166:     Res = count_sessions(null, Config),
  167:     get_unauthorized(Res),
  168:     % Count sessions for an external domain
  169:     Res2 = count_sessions(BisDomain, Config),
  170:     get_unauthorized(Res2),
  171:     % Count sessions for local domain
  172:     Res3 = count_sessions(Domain, Config),
  173:     Number = get_ok_value(Path, Res3),
  174:     ?assertEqual(2, Number).
  175: 
  176: domain_admin_list_user_sessions_no_permission(Config) ->
  177:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  178:                                     fun domain_admin_list_user_sessions_no_permission_story/2).
  179: 
  180: domain_admin_list_user_sessions_no_permission_story(Config, AliceBis) ->
  181:     AliceBisJID = escalus_client:full_jid(AliceBis),
  182:     Res = list_user_sessions(AliceBisJID, Config),
  183:     get_unauthorized(Res).
  184: 
  185: domain_admin_count_user_resources_no_permission(Config) ->
  186:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  187:                                     fun domain_admin_count_user_resources_story_no_permission/2).
  188: 
  189: domain_admin_count_user_resources_story_no_permission(Config, AliceBis) ->
  190:     AliceBisJID = escalus_client:full_jid(AliceBis),
  191:     Res = count_user_resources(AliceBisJID, Config),
  192:     get_unauthorized(Res).
  193: 
  194: domain_admin_get_user_resource_no_permission(Config) ->
  195:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  196:                                     fun domain_admin_get_user_resource_story_no_permission_story/2).
  197: 
  198: domain_admin_get_user_resource_story_no_permission_story(Config, AliceBis) ->
  199:     AliceBisJID = escalus_client:short_jid(AliceBis),
  200:     Res = get_user_resource(AliceBisJID, 2, Config),
  201:     get_unauthorized(Res).
  202: 
  203: domain_admin_kick_user_session_no_permission(Config) ->
  204:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  205:                                     fun domain_admin_kick_user_session_no_permission_story/2).
  206: 
  207: domain_admin_kick_user_session_no_permission_story(Config, AliceBis) ->
  208:     AliceBisJID = escalus_client:full_jid(AliceBis),
  209:     Reason = <<"Test kick">>,
  210:     Res = kick_user_session(AliceBisJID, Reason, Config),
  211:     get_unauthorized(Res).
  212: 
  213: domain_admin_kick_user_no_permission(Config) ->
  214:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  215:                                     fun domain_admin_kick_user_no_permission_story/2).
  216: 
  217: domain_admin_kick_user_no_permission_story(Config, AliceBis) ->
  218:     AliceBisJID = escalus_client:short_jid(AliceBis),
  219:     Reason = <<"Test kick">>,
  220:     Res = kick_user(AliceBisJID, Reason, Config),
  221:     get_unauthorized(Res).
  222: 
  223: domain_admin_set_presence_no_permission(Config) ->
  224:     escalus:fresh_story_with_config(Config, [{alice_bis, 1}],
  225:                                     fun domain_admin_set_presence_no_permission_story/2).
  226: 
  227: domain_admin_set_presence_no_permission_story(Config, AliceBis) ->
  228:     AliceBisJID = escalus_client:full_jid(AliceBis),
  229:     Type = <<"AVAILABLE">>,
  230:     Show = <<"ONLINE">>,
  231:     Status = <<"Be right back">>,
  232:     Priority = 1,
  233:     Res = set_presence(AliceBisJID, Type, Show, Status, Priority, Config),
  234:     get_unauthorized(Res).
  235: 
  236: domain_admin_list_users_with_status(Config) ->
  237:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}],
  238:                                     fun domain_admin_list_users_with_status_story/3).
  239: 
  240: domain_admin_list_users_with_status_story(Config, Alice, _AliceB) ->
  241:     AliceJID = escalus_client:full_jid(Alice),
  242:     AwayStatus = <<"away">>,
  243:     AwayPresence = escalus_stanza:presence_show(AwayStatus),
  244:     DndStatus = <<"dnd">>,
  245:     DndPresence = escalus_stanza:presence_show(DndStatus),
  246:     % List users with away status globally
  247:     escalus_client:send(Alice, AwayPresence),
  248:     Res = list_users_with_status(null, AwayStatus, Config),
  249:     get_unauthorized(Res),
  250:     % List users with away status for a domain
  251:     assert_list_users_with_status([AliceJID], domain(), AwayStatus, Config),
  252:     assert_list_users_with_status([AliceJID], unprep(domain()), AwayStatus, Config),
  253:     % List users with away status for an external domain
  254:     Res3 = list_users_with_status(domain_helper:secondary_domain(), AwayStatus, Config),
  255:     get_unauthorized(Res3),
  256:     % List users with dnd status globally
  257:     escalus_client:send(Alice, DndPresence),
  258:     Res4 = list_users_with_status(null, DndStatus, Config),
  259:     get_unauthorized(Res4),
  260:     % List users with dnd status for a domain
  261:     assert_list_users_with_status([AliceJID], domain(), DndStatus, Config),
  262:     % List users with dnd status for an external domain
  263:     Res6 = list_users_with_status(domain_helper:secondary_domain(), AwayStatus, Config),
  264:     get_unauthorized(Res6).
  265: 
  266: domain_admin_count_users_with_status(Config) ->
  267:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}],
  268:                                     fun domain_admin_count_users_with_status_story/3).
  269: 
  270: domain_admin_count_users_with_status_story(Config, Alice, _AliceB) ->
  271:     AwayStatus = <<"away">>,
  272:     AwayPresence = escalus_stanza:presence_show(AwayStatus),
  273:     DndStatus = <<"dnd">>,
  274:     DndPresence = escalus_stanza:presence_show(DndStatus),
  275:     % Count users with away status globally
  276:     escalus_client:send(Alice, AwayPresence),
  277:     Res = count_users_with_status(null, AwayStatus, Config),
  278:     get_unauthorized(Res),
  279:     % Count users with away status for a domain
  280:     assert_count_users_with_status(1, domain_helper:domain(), AwayStatus, Config),
  281:     assert_count_users_with_status(1, unprep(domain_helper:domain()), AwayStatus, Config),
  282:     % Count users with dnd status globally
  283:     escalus_client:send(Alice, DndPresence),
  284:     Res3 = count_users_with_status(null, DndStatus, Config),
  285:     get_unauthorized(Res3),
  286:     % Count users with dnd status for a domain
  287:     assert_count_users_with_status(1, domain_helper:domain(), DndStatus, Config).
  288: 
  289: admin_list_sessions(Config) ->
  290:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}],
  291:                                     fun admin_list_sessions_story/4).
  292: 
  293: admin_list_sessions_story(Config, _Alice, AliceB, _Bob) ->
  294:     BisDomain = escalus_client:server(AliceB),
  295:     Path = [data, session, listSessions],
  296:     % List all sessions
  297:     Res = list_sessions(null, Config),
  298:     Sessions = get_ok_value(Path, Res),
  299:     ?assertEqual(3, length(Sessions)),
  300:     % List sessions for a domain
  301:     Res2 = list_sessions(BisDomain, Config),
  302:     Sessions2 = get_ok_value(Path, Res2),
  303:     ?assertEqual(1, length(Sessions2)),
  304:     Res3 = list_sessions(unprep(BisDomain), Config),
  305:     Sessions3 = get_ok_value(Path, Res3),
  306:     ?assertEqual(1, length(Sessions3)),
  307:     % List sessions for a non-existing domain
  308:     Res4 = list_sessions(<<"nonexisting">>, Config),
  309:     ?assertEqual(<<"Domain not found">>, get_err_msg(Res4)).
  310: 
  311: admin_count_sessions(Config) ->
  312:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}],
  313:                                     fun admin_count_sessions_story/4).
  314: 
  315: admin_count_sessions_story(Config, _Alice, AliceB, _Bob) ->
  316:     BisDomain = escalus_client:server(AliceB),
  317:     Path = [data, session, countSessions],
  318:     % Count all sessions
  319:     Res = count_sessions(null, Config),
  320:     Number = get_ok_value(Path, Res),
  321:     ?assertEqual(3, Number),
  322:     % Count sessions for a domain
  323:     Res2 = count_sessions(BisDomain, Config),
  324:     ?assertEqual(1,  get_ok_value(Path, Res2)),
  325:     Res3 = count_sessions(unprep(BisDomain), Config),
  326:     ?assertEqual(1,  get_ok_value(Path, Res3)),
  327:     % Count sessions for a non-existing domain
  328:     Res4 = count_sessions(<<"nonexisting">>, Config),
  329:     ?assertEqual(<<"Domain not found">>, get_err_msg(Res4)).
  330: 
  331: admin_list_user_sessions(Config) ->
  332:     escalus:fresh_story_with_config(Config, [{alice, 2}, {bob, 1}],
  333:                                     fun admin_list_user_sessions_story/4).
  334: 
  335: admin_list_user_sessions_story(Config, Alice, Alice2, _Bob) ->
  336:     S1JID = escalus_client:full_jid(Alice),
  337:     S2JID = escalus_client:full_jid(Alice2),
  338:     Path = [data, session, listUserSessions],
  339:     Res = list_user_sessions(S1JID, Config),
  340:     ExpectedRes = lists:map(fun escalus_utils:jid_to_lower/1, [S1JID, S2JID]),
  341:     Sessions = get_ok_value(Path, Res),
  342:     ?assertEqual(2, length(Sessions)),
  343:     check_users(ExpectedRes, Sessions),
  344:     % Check for a non-existing user
  345:     Domain = domain(),
  346:     Res2 = list_user_sessions(<<"alien@", Domain/binary>>, Config),
  347:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)).
  348: 
  349: admin_count_user_resources(Config) ->
  350:     escalus:fresh_story_with_config(Config, [{alice, 3}], fun admin_count_user_resources_story/4).
  351: 
  352: admin_count_user_resources_story(Config, Alice, _Alice2, _Alice3) ->
  353:     Path = [data, session, countUserResources],
  354:     JID = escalus_client:full_jid(Alice),
  355:     Res = count_user_resources(JID, Config),
  356:     ?assertEqual(3, get_ok_value(Path, Res)),
  357:     % Check for a non-existing user
  358:     Domain = domain(),
  359:     Res2 = count_user_resources(<<"alien@", Domain/binary>>, Config),
  360:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)).
  361: 
  362: admin_get_user_resource(Config) ->
  363:     escalus:fresh_story_with_config(Config, [{alice, 3}], fun admin_get_user_resource_story/4).
  364: 
  365: admin_get_user_resource_story(Config, Alice, Alice2, _Alice3) ->
  366:     Path = [data, session, getUserResource],
  367:     JID = escalus_client:short_jid(Alice),
  368:     % Provide a correct resource number
  369:     Res = get_user_resource(JID, 2, Config),
  370:     ?assertEqual(escalus_client:resource(Alice2), get_ok_value(Path, Res)),
  371:     % Provide a wrong resource number
  372:     Res2 = get_user_resource(JID, 4, Config),
  373:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"Wrong resource number">>)),
  374:     % Check for a non-existing user
  375:     Domain = domain(),
  376:     Res3 = get_user_resource(<<"alien@", Domain/binary>>, 1, Config),
  377:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res3)).
  378: 
  379: admin_count_users_with_status(Config) ->
  380:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}],
  381:                                     fun admin_count_users_with_status_story/3).
  382: 
  383: admin_count_users_with_status_story(Config, Alice, AliceB) ->
  384:     AwayStatus = <<"away">>,
  385:     AwayPresence = escalus_stanza:presence_show(AwayStatus),
  386:     DndStatus = <<"dnd">>,
  387:     DndPresence = escalus_stanza:presence_show(DndStatus),
  388:     % Count users with away status globally
  389:     escalus_client:send(Alice, AwayPresence),
  390:     escalus_client:send(AliceB, AwayPresence),
  391:     assert_count_users_with_status(2, null, AwayStatus, Config),
  392:     % Count users with away status for a domain
  393:     assert_count_users_with_status(1, domain_helper:domain(), AwayStatus, Config),
  394:     assert_count_users_with_status(1, unprep(domain_helper:domain()), AwayStatus, Config),
  395:     % Count users with dnd status globally
  396:     escalus_client:send(AliceB, DndPresence),
  397:     assert_count_users_with_status(1, null, DndStatus, Config),
  398:     % Count users with dnd status for a non-existing domain
  399:     Res = count_users_with_status(<<"nonexisting">>, DndStatus, Config),
  400:     ?assertEqual(<<"Domain not found">>, get_err_msg(Res)).
  401: 
  402: admin_list_users_with_status(Config) ->
  403:     escalus:fresh_story_with_config(Config, [{alice, 1}, {alice_bis, 1}],
  404:                                     fun admin_list_users_with_status_story/3).
  405: 
  406: admin_list_users_with_status_story(Config, Alice, AliceB) ->
  407:     AliceJID = escalus_client:full_jid(Alice),
  408:     AliceBJID = escalus_client:full_jid(AliceB),
  409:     AwayStatus = <<"away">>,
  410:     AwayPresence = escalus_stanza:presence_show(AwayStatus),
  411:     DndStatus = <<"dnd">>,
  412:     DndPresence = escalus_stanza:presence_show(DndStatus),
  413:     % List users with away status globally
  414:     escalus_client:send(Alice, AwayPresence),
  415:     escalus_client:send(AliceB, AwayPresence),
  416:     assert_list_users_with_status([AliceJID, AliceBJID], null, AwayStatus, Config),
  417:     % List users with away status for a domain
  418:     assert_list_users_with_status([AliceJID], domain(), AwayStatus, Config),
  419:     assert_list_users_with_status([AliceJID], unprep(domain()), AwayStatus, Config),
  420:     % List users with dnd status globally
  421:     escalus_client:send(AliceB, DndPresence),
  422:     assert_list_users_with_status([AliceBJID], null, DndStatus, Config),
  423:     % List users with dnd status for a non-existing domain
  424:     Res = count_users_with_status(<<"nonexisting">>, DndStatus, Config),
  425:     ?assertEqual(<<"Domain not found">>, get_err_msg(Res)).
  426: 
  427: admin_kick_user_session(Config) ->
  428:     escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_kick_user_session_story/3).
  429: 
  430: admin_kick_user_session_story(Config, Alice1, Alice2) ->
  431:     JIDA1 = escalus_client:full_jid(Alice1),
  432:     JIDA2 = escalus_client:full_jid(Alice2),
  433:     Reason = <<"Test kick">>,
  434:     Path = [data, session, kickUserSession, message],
  435:     Res = kick_user_session(JIDA1, Reason, Config),
  436:     % Kick an active session
  437:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res), <<"kicked">>)),
  438:     ?assertEqual(JIDA1, get_ok_value([data, session, kickUserSession, jid], Res)),
  439:     % Try to kick an offline session
  440:     Res2 = kick_user_session(JIDA1, Reason, Config),
  441:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"No active session">>)),
  442:     % Try to kick a session with JID without a resource
  443:     Res3 = kick_user_session(escalus_client:short_jid(Alice2), Reason, Config),
  444:     ?assertNotEqual(nomatch, binary:match(get_coercion_err_msg(Res3), <<"jid_without_resource">>)),
  445:     % Kick active session without reason text
  446:     Res4 = kick_user_session(JIDA2, null, Config),
  447:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res4), <<"kicked">>)),
  448:     % Kick a non-existing user
  449:     Domain = domain(),
  450:     Res5 = kick_user_session(<<"alien@", Domain/binary, "/mobile">>, null, Config),
  451:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res5)).
  452: 
  453: admin_kick_user(Config) ->
  454:     escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_kick_user_story/3).
  455: 
  456: admin_kick_user_story(Config, Alice1, _Alice2) ->
  457:     AliceJID = escalus_client:short_jid(Alice1),
  458:     Reason = <<"Test kick">>,
  459:     Res1 = kick_user(AliceJID, Reason, Config),
  460:     Res2 = get_ok_value([data, session, kickUser], Res1),
  461:     ?assertEqual(2, length(Res2)),
  462:     ?assertEqual([true, true], [Kicked || #{<<"kicked">> := Kicked} <- Res2]),
  463:     % Kick a non-existing user
  464:     Domain = domain(),
  465:     Res5 = kick_user(<<"alien@", Domain/binary>>, null, Config),
  466:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res5)).
  467: 
  468: admin_set_presence(Config) ->
  469:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_set_presence_story/2).
  470: 
  471: admin_set_presence_story(Config, Alice) ->
  472:     JID = escalus_client:full_jid(Alice),
  473:     ShortJID = escalus_client:short_jid(Alice),
  474:     Type = <<"AVAILABLE">>,
  475:     Show = <<"ONLINE">>,
  476:     Status = <<"Be right back">>,
  477:     Priority = 1,
  478:     % Send short JID
  479:     Res = set_presence(ShortJID, Type, Show, Status, Priority, Config),
  480:     ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"resource is empty">>)),
  481:     % Non-existing user
  482:     Domain = domain(),
  483:     Res2 = set_presence(<<"alien@", Domain/binary, "/mobile">>, Type, Show, Status, Priority, Config),
  484:     ?assertEqual(<<"Given user does not exist">>, get_err_msg(Res2)),
  485:     % Send full JID
  486:     Path = [data, session, setPresence, message],
  487:     Res3 = set_presence(JID, Type, Show, Status, Priority, Config),
  488:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res3), <<"set successfully">>)),
  489:     Presence = escalus:wait_for_stanza(Alice),
  490:     ?assertNot(escalus_pred:is_presence_with_show(<<"online">>, Presence)),
  491:     escalus:assert(is_presence_with_type, [<<"available">>], Presence),
  492:     escalus:assert(is_presence_with_status, [Status], Presence),
  493:     escalus:assert(is_presence_with_priority, [<<"1">>], Presence).
  494: 
  495: admin_set_presence_away(Config) ->
  496:     escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_set_presence_away_story/2).
  497: 
  498: admin_set_presence_away_story(Config, Alice) ->
  499:     JID = escalus_client:full_jid(Alice),
  500:     Type = <<"AVAILABLE">>,
  501:     Show = <<"AWAY">>,
  502:     Path = [data, session, setPresence, message],
  503:     Res2 = set_presence(JID, Type, Show, null, null, Config),
  504:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res2), <<"set successfully">>)),
  505:     Presence = escalus:wait_for_stanza(Alice),
  506:     escalus:assert(is_presence_with_type, [<<"available">>], Presence),
  507:     escalus:assert(is_presence_with_show, [<<"away">>], Presence).
  508: 
  509: admin_set_presence_unavailable(Config) ->
  510:     escalus:fresh_story_with_config(Config, [{alice, 2}], fun admin_set_presence_unavailable_story/3).
  511: 
  512: admin_set_presence_unavailable_story(Config, Alice, Alice2) ->
  513:     JID = escalus_client:full_jid(Alice),
  514:     Type = <<"UNAVAILABLE">>,
  515:     Status = <<"I'm sleeping">>,
  516:     Path = [data, session, setPresence, message],
  517:     Res2 = set_presence(JID, Type, null, Status, null, Config),
  518:     ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Res2), <<"set successfully">>)),
  519:     Presence = escalus:wait_for_stanza(Alice2),
  520:     escalus:assert(is_presence_with_type, [<<"unavailable">>], Presence),
  521:     escalus:assert(is_presence_with_status, [Status], Presence).
  522: 
  523: 
  524: %% Commands
  525: 
  526: user_list_resources(User, Config) ->
  527:     execute_user_command(<<"session">>, <<"listResources">>, User, #{}, Config).
  528: 
  529: user_count_resources(User, Config) ->
  530:     execute_user_command(<<"session">>, <<"countResources">>, User, #{}, Config).
  531: 
  532: user_list_sessions(User, Config) ->
  533:     execute_user_command(<<"session">>, <<"listSessions">>, User, #{}, Config).
  534: 
  535: list_sessions(Domain, Config) ->
  536:     Vars = #{<<"domain">> => Domain},
  537:     execute_command(<<"session">>, <<"listSessions">>, Vars, Config).
  538: 
  539: count_sessions(Domain, Config) ->
  540:     Vars = #{<<"domain">> => Domain},
  541:     execute_command(<<"session">>, <<"countSessions">>, Vars, Config).
  542: 
  543: list_user_sessions(User, Config) ->
  544:     Vars = #{<<"user">> => User},
  545:     execute_command(<<"session">>, <<"listUserSessions">>, Vars, Config).
  546: 
  547: count_user_resources(User, Config) ->
  548:     Vars = #{<<"user">> => User},
  549:     execute_command(<<"session">>, <<"countUserResources">>, Vars, Config).
  550: 
  551: get_user_resource(User, Number, Config) ->
  552:     Vars = #{<<"user">> => User, <<"number">> => Number},
  553:     execute_command(<<"session">>, <<"getUserResource">>, Vars, Config).
  554: 
  555: list_users_with_status(Domain, Status, Config) ->
  556:     Vars = #{<<"domain">> => Domain, <<"status">> => Status},
  557:     execute_command(<<"session">>, <<"listUsersWithStatus">>, Vars, Config).
  558: 
  559: count_users_with_status(Domain, Status, Config) ->
  560:     Vars = #{<<"domain">> => Domain, <<"status">> => Status},
  561:     execute_command(<<"session">>, <<"countUsersWithStatus">>, Vars, Config).
  562: 
  563: kick_user_session(JID, Reason, Config) ->
  564:     Vars = #{<<"user">> => JID, <<"reason">> => Reason},
  565:     execute_command(<<"session">>, <<"kickUserSession">>, Vars, Config).
  566: 
  567: kick_user(JID, Reason, Config) ->
  568:     Vars = #{<<"user">> => JID, <<"reason">> => Reason},
  569:     execute_command(<<"session">>, <<"kickUser">>, Vars, Config).
  570: 
  571: set_presence(JID, Type, Show, Status, Priority, Config) ->
  572:     Vars = #{<<"user">> => JID, <<"type">> => Type, <<"show">> => Show,
  573:              <<"status">> => Status, <<"priority">> => Priority},
  574:     execute_command(<<"session">>, <<"setPresence">>, Vars, Config).
  575: 
  576: %% Helpers
  577: 
  578: assert_list_users_with_status(ExpectedUsers, Domain, Status, Config) ->
  579:     Res = list_users_with_status(Domain, Status, Config),
  580:     Users = get_ok_value([data, session, listUsersWithStatus], Res),
  581:     check_users(ExpectedUsers, Users).
  582: 
  583: assert_count_users_with_status(ExpectedCount, Domain, Status, Config) ->
  584:     Res = count_users_with_status(Domain, Status, Config),
  585:     Count = get_ok_value([data, session, countUsersWithStatus], Res),
  586:     ?assertEqual(ExpectedCount, Count).
  587: 
  588: -spec check_users([jid:literal_jid()], [#{user := jid:literal_jid()}]) -> boolean().
  589: check_users(Expected, ActualUsers) ->
  590:     ActualJIDs = [JID || #{<<"user">> := JID} <- ActualUsers],
  591:     ?assertEqual(lists:sort(Expected), lists:sort(ActualJIDs)).