Skip to content

Commit

Permalink
Merge pull request #3702 from esl/graphql-cli-test-poc
Browse files Browse the repository at this point in the history
Test GraphQL CLI for accounts
  • Loading branch information
JanuszJakubiec authored Jul 11, 2022
2 parents 18ad8e3 + b3a3a19 commit e8ccddb
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 165 deletions.
161 changes: 76 additions & 85 deletions big_tests/tests/graphql_account_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-compile([export_all, nowarn_export_all]).

-import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]).
-import(graphql_helper, [execute/3, execute_auth/2, get_listener_port/1,
-import(graphql_helper, [execute/3, execute_auth/2, execute_command/4, get_listener_port/1,
get_listener_config/1, get_ok_value/2, get_err_msg/1]).

-define(NOT_EXISTING_JID, <<"unknown987@unknown">>).
Expand All @@ -16,17 +16,19 @@ suite() ->

all() ->
[{group, user_account_handler},
{group, admin_account_handler}].
{group, admin_account_handler},
{group, admin_account_cli}].

groups() ->
[{user_account_handler, [parallel], user_account_handler()},
{admin_account_handler, [], admin_account_handler()}].
[{user_account_handler, [parallel], user_account_tests()},
{admin_account_handler, [], admin_account_tests()},
{admin_account_cli, [], admin_account_tests()}].

user_account_handler() ->
user_account_tests() ->
[user_unregister,
user_change_password].

admin_account_handler() ->
admin_account_tests() ->
[admin_list_users,
admin_count_users,
admin_check_password,
Expand All @@ -43,28 +45,38 @@ admin_account_handler() ->
init_per_suite(Config) ->
Config1 = [{ctl_auth_mods, mongoose_helper:auth_modules()} | Config],
Config2 = escalus:init_per_suite(Config1),
dynamic_modules:save_modules(domain_helper:host_type(), Config2).
Config3 = ejabberd_node_utils:init(mim(), Config2),
dynamic_modules:save_modules(domain_helper:host_type(), Config3).

end_per_suite(Config) ->
dynamic_modules:restore_modules(Config),
escalus:end_per_suite(Config).

init_per_group(admin_account_handler, Config) ->
Config1 = escalus:create_users(Config, escalus:get_users([alice])),
graphql_helper:init_admin_handler(Config1);
graphql_helper:init_admin_handler(init_users(Config));
init_per_group(admin_account_cli, Config) ->
graphql_helper:init_admin_cli(init_users(Config));
init_per_group(user_account_handler, Config) ->
[{schema_endpoint, user} | Config];
init_per_group(_, Config) ->
Config.

end_per_group(admin_account_handler, Config) ->
escalus_fresh:clean(),
escalus:delete_users(Config, escalus:get_users([alice]));
clean_users(Config);
end_per_group(admin_account_cli, Config) ->
clean_users(Config);
end_per_group(user_account_handler, _Config) ->
escalus_fresh:clean();
end_per_group(_, _Config) ->
ok.

init_users(Config) ->
escalus:create_users(Config, escalus:get_users([alice])).

clean_users(Config) ->
escalus_fresh:clean(),
escalus:delete_users(Config, escalus:get_users([alice])).

init_per_testcase(admin_register_user = C, Config) ->
Config1 = [{user, {<<"gql_admin_registration_test">>, domain_helper:domain()}} | Config],
escalus:init_per_testcase(C, Config1);
Expand Down Expand Up @@ -110,7 +122,7 @@ user_unregister_story(Config, Alice) ->
AllUsers = rpc(mim(), mongoose_account_api, list_users, [domain_helper:domain()]),
LAliceJID = jid:to_binary(jid:to_lower((jid:binary_to_bare(BinJID)))),
?assertNot(lists:member(LAliceJID, AllUsers)).

user_change_password(Config) ->
escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_change_password_story/2).

Expand All @@ -128,48 +140,48 @@ user_change_password_story(Config, Alice) ->

admin_list_users(Config) ->
% An unknown domain
Resp = execute_auth(list_users_body(<<"unknown-domain">>), Config),
Resp = list_users(<<"unknown-domain">>, Config),
?assertEqual([], get_ok_value([data, account, listUsers], Resp)),
% A domain with users
Domain = domain_helper:domain(),
Username = jid:nameprep(escalus_users:get_username(Config, alice)),
JID = <<Username/binary, "@", Domain/binary>>,
Resp2 = execute_auth(list_users_body(Domain), Config),
Resp2 = list_users(Domain, Config),
Users = get_ok_value([data, account, listUsers], Resp2),
?assert(lists:member(JID, Users)).

admin_count_users(Config) ->
% An unknown domain
Resp = execute_auth(count_users_body(<<"unknown-domain">>), Config),
Resp = count_users(<<"unknown-domain">>, Config),
?assertEqual(0, get_ok_value([data, account, countUsers], Resp)),
% A domain with at least one user
Domain = domain_helper:domain(),
Resp2 = execute_auth(count_users_body(Domain), Config),
Resp2 = count_users(Domain, Config),
?assert(0 < get_ok_value([data, account, countUsers], Resp2)).

admin_check_password(Config) ->
Password = lists:last(escalus_users:get_usp(Config, alice)),
BinJID = escalus_users:get_jid(Config, alice),
Path = [data, account, checkPassword],
% A correct password
Resp1 = execute_auth(check_password_body(BinJID, Password), Config),
Resp1 = check_password(BinJID, Password, Config),
?assertMatch(#{<<"correct">> := true, <<"message">> := _}, get_ok_value(Path, Resp1)),
% An incorrect password
Resp2 = execute_auth(check_password_body(BinJID, <<"incorrect_pw">>), Config),
Resp2 = check_password(BinJID, <<"incorrect_pw">>, Config),
?assertMatch(#{<<"correct">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)),
% A non-existing user
Resp3 = execute_auth(check_password_body(?NOT_EXISTING_JID, Password), Config),
?assertEqual(null, get_ok_value(Path, Resp3)).
Resp3 = check_password(?NOT_EXISTING_JID, Password, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp3), <<"not exist">>)).

admin_check_password_hash(Config) ->
UserSCRAM = escalus_users:get_jid(Config, alice),
EmptyHash = list_to_binary(get_md5(<<>>)),
Method = <<"md5">>,
% SCRAM password user
Resp1 = execute_auth(check_password_hash_body(UserSCRAM, EmptyHash, Method), Config),
Resp1 = check_password_hash(UserSCRAM, EmptyHash, Method, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"SCRAM password">>)),
% A non-existing user
Resp2 = execute_auth(check_password_hash_body(?NOT_EXISTING_JID, EmptyHash, Method), Config),
Resp2 = check_password_hash(?NOT_EXISTING_JID, EmptyHash, Method, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"not exist">>)).

admin_check_plain_password_hash(Config) ->
Expand All @@ -180,57 +192,57 @@ admin_check_plain_password_hash(Config) ->
WrongHash = list_to_binary(get_md5(<<"wrong password">>)),
Path = [data, account, checkPasswordHash],
% A correct hash
Resp = execute_auth(check_password_hash_body(UserJID, Hash, Method), Config),
Resp = check_password_hash(UserJID, Hash, Method, Config),
?assertMatch(#{<<"correct">> := true, <<"message">> := _}, get_ok_value(Path, Resp)),
% An incorrect hash
Resp2 = execute_auth(check_password_hash_body(UserJID, WrongHash, Method), Config),
Resp2 = check_password_hash(UserJID, WrongHash, Method, Config),
?assertMatch(#{<<"correct">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)),
% A not-supported hash method
Resp3 = execute_auth(check_password_hash_body(UserJID, Hash, <<"a">>), Config),
Resp3 = check_password_hash(UserJID, Hash, <<"a">>, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp3), <<"not supported">>)).

admin_check_user(Config) ->
BinJID = escalus_users:get_jid(Config, alice),
Path = [data, account, checkUser],
% An existing user
Resp1 = execute_auth(check_user_body(BinJID), Config),
Resp1 = check_user(BinJID, Config),
?assertMatch(#{<<"exist">> := true, <<"message">> := _}, get_ok_value(Path, Resp1)),
% A non-existing user
Resp2 = execute_auth(check_user_body(?NOT_EXISTING_JID), Config),
Resp2 = check_user(?NOT_EXISTING_JID, Config),
?assertMatch(#{<<"exist">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)).

admin_register_user(Config) ->
Password = <<"my_password">>,
{Username, Domain} = proplists:get_value(user, Config),
Path = [data, account, registerUser, message],
% Register a new user
Resp1 = execute_auth(register_user_body(Domain, Username, Password), Config),
Resp1 = register_user(Domain, Username, Password, Config),
?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp1), <<"successfully registered">>)),
% Try to register a user with existing name
Resp2 = execute_auth(register_user_body(Domain, Username, Password), Config),
Resp2 = register_user(Domain, Username, Password, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"already registered">>)).

admin_register_random_user(Config) ->
Password = <<"my_password">>,
Domain = domain_helper:domain(),
Path = [data, account, registerUser],
% Register a new user
Resp1 = execute_auth(register_user_body(Domain, null, Password), Config),
Resp1 = register_random_user(Domain, Password, Config),
#{<<"message">> := Msg, <<"jid">> := JID} = get_ok_value(Path, Resp1),
{Username, Server} = jid:to_lus(jid:from_binary(JID)),

?assertNotEqual(nomatch, binary:match(Msg, <<"successfully registered">>)),
{ok, _} = rpc(mim(), mongoose_account_api, unregister_user, [Username, Server]).

admin_remove_non_existing_user(Config) ->
Resp = execute_auth(remove_user_body(?NOT_EXISTING_JID), Config),
Resp = remove_user(?NOT_EXISTING_JID, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"not exist">>)).

admin_remove_existing_user(Config) ->
escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
Path = [data, account, removeUser, message],
BinJID = escalus_client:full_jid(Alice),
Resp4 = execute_auth(remove_user_body(BinJID), Config),
Resp4 = remove_user(BinJID, Config),
?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp4),
<<"successfully unregister">>))
end).
Expand All @@ -239,28 +251,28 @@ admin_ban_user(Config) ->
Path = [data, account, banUser, message],
Reason = <<"annoying">>,
% Ban not existing user
Resp1 = execute_auth(ban_user_body(?NOT_EXISTING_JID, Reason), Config),
Resp1 = ban_user(?NOT_EXISTING_JID, Reason, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"not allowed">>)),
% Ban an existing user
escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
BinJID = escalus_client:full_jid(Alice),
Resp2 = execute_auth(ban_user_body(BinJID, Reason), Config),
Resp2 = ban_user(BinJID, Reason, Config),
?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp2), <<"successfully banned">>))
end).

admin_change_user_password(Config) ->
Path = [data, account, changeUserPassword, message],
NewPassword = <<"new password">>,
% Change password of not existing user
Resp1 = execute_auth(change_user_password_body(?NOT_EXISTING_JID, NewPassword), Config),
Resp1 = change_user_password(?NOT_EXISTING_JID, NewPassword, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"not allowed">>)),
% Set an empty password
Resp2 = execute_auth(change_user_password_body(?NOT_EXISTING_JID, <<>>), Config),
Resp2 = change_user_password(?NOT_EXISTING_JID, <<>>, Config),
?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"Empty password">>)),
% Change password of an existing user
escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
BinJID = escalus_client:full_jid(Alice),
Resp3 = execute_auth(change_user_password_body(BinJID, NewPassword), Config),
Resp3 = change_user_password(BinJID, NewPassword, Config),
?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp3), <<"Password changed">>))
end).

Expand All @@ -270,70 +282,49 @@ get_md5(AccountPass) ->
lists:flatten([io_lib:format("~.16B", [X])
|| X <- binary_to_list(crypto:hash(md5, AccountPass))]).

%% Request bodies
%% Admin commands

list_users_body(Domain) ->
Query = <<"query Q1($domain: String!) { account { listUsers(domain: $domain) } }">>,
OpName = <<"Q1">>,
list_users(Domain, Config) ->
Vars = #{<<"domain">> => Domain},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"listUsers">>, Vars, Config).

count_users_body(Domain) ->
Query = <<"query Q1($domain: String!) { account { countUsers(domain: $domain) } }">>,
OpName = <<"Q1">>,
count_users(Domain, Config) ->
Vars = #{<<"domain">> => Domain},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"countUsers">>, Vars, Config).

check_password_body(User, Password) ->
Query = <<"query Q1($user: JID!, $password: String!)
{ account { checkPassword(user: $user, password: $password) {correct message} } }">>,
OpName = <<"Q1">>,
check_password(User, Password, Config) ->
Vars = #{<<"user">> => User, <<"password">> => Password},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"checkPassword">>, Vars, Config).

check_password_hash_body(User, PasswordHash, HashMethod) ->
Query = <<"query Q1($user: JID!, $hash: String!, $method: String!)
{ account { checkPasswordHash(user: $user, passwordHash: $hash, hashMethod: $method)
{correct message} } }">>,
OpName = <<"Q1">>,
Vars = #{<<"user">> => User, <<"hash">> => PasswordHash, <<"method">> => HashMethod},
#{query => Query, operationName => OpName, variables => Vars}.
check_password_hash(User, PasswordHash, HashMethod, Config) ->
Vars = #{<<"user">> => User, <<"passwordHash">> => PasswordHash, <<"hashMethod">> => HashMethod},
execute_command(<<"account">>, <<"checkPasswordHash">>, Vars, Config).

check_user_body(User) ->
Query = <<"query Q1($user: JID!)
{ account { checkUser(user: $user) {exist message} } }">>,
OpName = <<"Q1">>,
check_user(User, Config) ->
Vars = #{<<"user">> => User},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"checkUser">>, Vars, Config).

register_user_body(Domain, Username, Password) ->
Query = <<"mutation M1($domain: String!, $username: String, $password: String!)
{ account { registerUser(domain: $domain, username: $username, password: $password)
{ jid message } } }">>,
OpName = <<"M1">>,
register_user(Domain, Username, Password, Config) ->
Vars = #{<<"domain">> => Domain, <<"username">> => Username, <<"password">> => Password},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"registerUser">>, Vars, Config).

remove_user_body(User) ->
Query = <<"mutation M1($user: JID!)
{ account { removeUser(user: $user) { jid message } } }">>,
OpName = <<"M1">>,
register_random_user(Domain, Password, Config) ->
Vars = #{<<"domain">> => Domain, <<"password">> => Password},
execute_command(<<"account">>, <<"registerUser">>, Vars, Config).

remove_user(User, Config) ->
Vars = #{<<"user">> => User},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"removeUser">>, Vars, Config).

ban_user_body(JID, Reason) ->
Query = <<"mutation M1($user: JID!, $reason: String!)
{ account { banUser(user: $user, reason: $reason) { jid message } } }">>,
OpName = <<"M1">>,
ban_user(JID, Reason, Config) ->
Vars = #{<<"user">> => JID, <<"reason">> => Reason},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"banUser">>, Vars, Config).

change_user_password_body(JID, NewPassword) ->
Query = <<"mutation M1($user: JID!, $newPassword: String!)
{ account { changeUserPassword(user: $user, newPassword: $newPassword) { jid message } } }">>,
OpName = <<"M1">>,
change_user_password(JID, NewPassword, Config) ->
Vars = #{<<"user">> => JID, <<"newPassword">> => NewPassword},
#{query => Query, operationName => OpName, variables => Vars}.
execute_command(<<"account">>, <<"changeUserPassword">>, Vars, Config).

%% Request bodies

user_change_password_body(NewPassword) ->
Query = <<"mutation M1($newPassword: String!)
Expand Down
Loading

0 comments on commit e8ccddb

Please sign in to comment.